FileDocCategorySizeDatePackage
JavaCodeCompact.javaAPI DocJ2ME CLDC 1.123940Wed Feb 05 15:56:04 GMT 2003None

JavaCodeCompact

public class JavaCodeCompact extends LinkerUtil

Fields Summary
int
verbosity
boolean
fail
ConstantPool
t
ClassFileFinder
searchPath
String
firstFileName
String
outName
Vector
arrayClasses
boolean
classDebug
boolean
ROMout
boolean
outSet
String
archName
boolean
archSet
boolean
doShared
Vector
romAttributes
ClassReader
rdr
MemberLoader
memberLoader
Hashtable
headerDirs
String
stubDestName
boolean
stubTraceMode
ClassnameFilterList
nativeTypes
ClassnameFilterList
extraHeaders
int
maxSegmentSize
Vector
classesProcessed
int
nclasses
boolean
buildTables
boolean
quicken
boolean
doClosure
boolean
qlossless
VMClassFactory
classMaker
Constructors Summary
Methods Summary
private voidaddConstant2SharedPool(ClassInfo cinfo, ConstantPool cp)

        for (int j = 0; j < cinfo.constants.length; j++) {
            if (cinfo.constants[j] == null)
                continue;

            int count = cinfo.constants[j].references;
            if (count > 0) {
               cinfo.constants[j] = cp.appendElement(cinfo.constants[j]);
        }
        }

        // update interfaces array
        if (cinfo.interfaces != null) {
            for (int k = 0 ; k < cinfo.interfaces.length; k++) {
               cinfo.interfaces[k] = (ClassConstant)
                               cp.appendElement(cinfo.interfaces[k]);
            }
        }

        // update exception table (catchType)
        for (int i = 0; i < cinfo.methods.length; i++) {
            if ( cinfo.methods[i].exceptionTable != null) {
                for (int j = 0; j < cinfo.methods[i].exceptionTable.length; j++) {
                    ClassConstant cc = cinfo.methods[i].exceptionTable[j].catchType;
                    if (cc != null) {
                        cinfo.methods[i].exceptionTable[j].catchType = (ClassConstant)                                                             cp.appendElement(cc);
                    }
                }
            }    
        }
    
private booleancollectArrayClass(java.lang.String cname, boolean verbose)

    // cname is the name of an array class
    // make sure it doesn't exist ( it won't if it came from a 
    // class constant ), and instantiate it. For EVM, do the same with
    // any sub-array types.
    boolean good = true;
    do {
        if ( ClassInfo.lookupClass( cname ) != null ){
        continue; // this one exists. But subclasses may not, so keep going.
        }
        try {
        arrayClasses.addElement( new ArrayClassInfo( verbose, cname ) );
        } catch ( DataFormatException e ){
        e.printStackTrace();
        good = false;
        break; // out of do...while
        }
    } while ( (cname = cname.substring(1) ).charAt(0) == Const.SIGC_ARRAY );
    return good;
    
private voidfileFound(java.lang.String fname)


     
       
    // currently, the only thing we do with file names
    // is make them into potential output file names.
    if ( firstFileName == null ) firstFileName = fname;
    
public ClassClass[]finalizeClasses()


      
    ClassClass classes[] = ClassClass.getClassVector(classMaker);
    int n = classes.length;

    if ( quicken ){
        CodeHacker ch = new CodeHacker( t, qlossless, true, verbosity >= 2 );
        for ( int i = 0; i < n; i++ ){
        if ( verbosity != 0 )System.out.println(Localizer.getString("javacodecompact.quickening_code_of_class", classes[i].ci.className));
        if ( ! ch.quickenCode( classes[i].ci ) )
            fail = true;
        }
    }

    // constant pool smashing has to be done after quickening,
    // else it doesn't make much difference!

    for ( int i = 0; i < n; i++ ){
        ClassInfo c = classes[i].ci;
        if ( verbosity != 0 )System.out.println(Localizer.getString("javacodecompact.reducing_constant_pool_of_class", c.className));
        c.countReferences( !ROMout );
        c.smashConstantPool();
        c.relocateReferences();
    }

    for ( int i = 0; i < n ; i++ )
        classes[i].ci.allocateFieldsFromFieldtable();
    
    /*
     * EVM doesn't do inlining, yet.
     * This last-minute preparation step might be generalized
     * to something more useful.
     */
    /*
    //for ( int i = 0; i < n; i++) 
    //    classes[i].getInlining();
    */
    return classes;
    
public booleaninstantiateArrayClasses(ClassInfo[] classTable, boolean verbose)

    int nclasses = classTable.length;
    boolean good = true;
    // For EVM, make sure that all arrays of basic types
    // are instantiated!
    String basicArray[] = { "[C", "[S", "[Z", "[I", "[J", "[F", "[D", "[B", 
        "[Ljava/lang/Object;" // not strictly basic.
    };
    for ( int ino = 0; ino < basicArray.length; ino++ ){
        if ( ! collectArrayClass( basicArray[ino], verbose )){
        good = false;
        }
    }

    // Now dredge through all class constant pools.
    for ( int cno = 0; cno < nclasses; cno++ ){
        ClassInfo c = classTable[cno];
        ConstantObject ctable[] = c.constants;
        if ( ctable == null ) continue;
        int n = ctable.length;
        for( int i = 0; i < n; i++ ){
        if ( ctable[i] instanceof ClassConstant ){
            ClassConstant cc = (ClassConstant)ctable[i];
            String        cname = cc.name.string;
            if (cname.charAt(0) != Const.SIGC_ARRAY ){
            continue; // not interesting
            }
            if ( cc.isResolved() ){
            continue; // not interesting
            }
            if ( ! collectArrayClass( cname, verbose )){
            good = false;
            }
            cc.forget(); // forget the fact that we couldn't find it
        }
        }
    }
    return good;
    
private voidloadMembers(java.lang.String filename, java.util.Vector classlist)

    if ( memberLoader == null ){
        if ( rdr == null ){
        rdr = new ClassReader( t, verbosity );
        }
        if ( searchPath == null ){
        searchPath = new ClassFileFinder();
        }
        memberLoader = new MemberLoader( rdr, searchPath );
    }
    try {
        memberLoader.readFromFile( filename, classlist );
    } catch ( IOException e ){
        System.err.println("-memberlist "+filename);
        e.printStackTrace();
        fail = true;
    }
    
public static voidmain(java.lang.String[] clist)

    boolean success = new JavaCodeCompact().process( clist );
    if ( !success ){
        System.out.flush();
        System.err.flush();
        System.exit(1);
    }
    return;
    
private voidmakeOutfileName()

    if ( outName != null ) return; // already done by -o option.
    if (firstFileName==null) firstFileName = "ROMjava.c";
    int sepindex = firstFileName.lastIndexOf( File.separatorChar )+1;
    int suffindex = firstFileName.lastIndexOf( '." );
    if ( suffindex < 0 ) suffindex = firstFileName.length();
    outName = firstFileName.substring( sepindex, suffindex)
          + (ROMout ? ".c" : ".mclass");
    
public booleanprocess(java.lang.String[] clist)


    if ( ! processOptions( clist ) )
        return false;
    makeOutfileName();
    if ( !ROMout ){
        quicken = false;
        buildTables = false;
    }
        
        

    if ( doClosure ){
        while ( !fail ){
        Vector unresolved = unresolvedClassNames();
        if ( unresolved.size() == 0 )
            break; // none left!
        Enumeration ulist = unresolved.elements();
        int nfound = 0;
        while ( ulist.hasMoreElements() ){
            String uname = (String)ulist.nextElement();
            nfound += rdr.readClass(uname, searchPath, classesProcessed);
        }
        if ( nfound == 0 ){
            // the list now contains things which could
            // not ever be resolved. Print it out for
            // information and go on.
            // this is not actually an error!
            if ( verbosity > 0 ){
            ulist = unresolved.elements();
            System.out.println(Localizer.getString("javacodecompact.could_not_resolve_these_names"));
            while( ulist.hasMoreElements() ){
                System.out.write('\t");
                System.out.println( (String)ulist.nextElement() );
            }
            }
            break;
        }
        }
    }

    if ( fail ){
        return false;
    }

    if ( memberLoader != null ){
        // then we saw a -memberlist option.
        // go through all classes, hacking away
        // all unmarked, unwanted elements.
        memberLoader.deleteUnwantedMembers( classesProcessed );
    }

    nclasses = classesProcessed.size();
    ClassInfo c[] = new ClassInfo[ nclasses ];
    classesProcessed.copyInto( c );

    if ( buildTables ){
        if ( verbosity != 0 )System.out.println(Localizer.getString("javacodecompact.resolving_superclass_hierarchy") );
        if ( ! ClassInfo.resolveSupers() ){
        return false; // missing superclass is a fatal error.
        }
        for ( int i = 0; i < nclasses; i++ ){
        if ( verbosity != 0 )System.out.println(Localizer.getString("javacodecompact.building_tables_for_class", c[i].className));
        c[i].buildReferenceFieldtable( t );
        c[i].buildReferenceMethodtable( t );
        }
    }
    for ( int i = 0; i < nclasses; i++ ){
        c[i].findReferences();
    }

    //if ( fail ) System.exit(1);

    // now write the output
    if ( verbosity != 0 )System.out.println(Localizer.getString("javacodecompact.writing_output_file"));

    writeNativesHeaders( nativeTypes, c, nclasses );
    writeNativesHeaders( extraHeaders, c, nclasses );

    if ( stubDestName != null ){
        writeCStubs( c, nclasses );
    }

    if ( ROMout ){
        return writeROMFile( outName, c, romAttributes );
    } else {
        MultiClass out = new MultiClass( t, c, verbosity>1 );
        out.writeMultiClass( outName );
    }

    return !fail;

    
public voidprocessArrayClasses(boolean verbose, ConstantPool x)

    Enumeration arrays = arrayClasses.elements();
    while( arrays.hasMoreElements() ){
        ArrayClassInfo a = (ArrayClassInfo)arrays.nextElement();
        if ( verbose ){
        System.out.println(Localizer.getString("javacodecompact.processing_array_class", a.className));
        }
        a.externalize(x);
        //a.countReferences();
        //a.smashConstantPool();
    }
    
private booleanprocessOptions(java.lang.String[] clist)


     
       
    boolean success = true;

    for( int i = 0; i < clist.length; i++ ){
        if ( clist[i].equals(/*NOI18N*/"-c") ){
        doClosure = true;
        continue;
        } else if ( clist[i].equals(/*NOI18N*/"-t") ){
        buildTables = true;
        continue;
        } else if ( clist[i].equals(/*NOI18N*/"-q") ){
        quicken     = true;
        continue;
        } else if ( clist[i].equals(/*NOI18N*/"-nt") ){
        buildTables = false;
        continue;
        } else if ( clist[i].equals(/*NOI18N*/"-nq") ){
        quicken     = false;
        continue;
        } else if ( clist[i].equals(/*NOI18N*/"-qlossless") ){
        buildTables = true;
        quicken     = true;
        qlossless   = true;
        continue;
        } else if ( clist[i].equals(/*NOI18N*/"-g") ){
        classDebug = true;
        ClassInfo.classDebug = true;
        continue;
        } else if ( clist[i].equals(/*NOI18N*/"-imageAttribute") ){
        romAttributes.addElement( clist[ ++i ] );
        continue;
        } else if ( clist[i].equals(/*NOI18N*/"-v") ){
        verbosity++;
        continue;
        } else if ( clist[i].equals(/*NOI18N*/"-r") ){
        ROMout = false;
        continue;
        } else if ( clist[i].equals(/*NOI18N*/"-o")  ){
        outName =  clist[ ++i ];
        } else if ( clist[i].equals(/*NOI18N*/"-classpath")  ){
        if ( searchPath == null )
            searchPath = new ClassFileFinder();
        searchPath.addToSearchPath( clist[ ++i ] );
        } else if ( clist[i].equals(/*NOI18N*/"-arch") ){
        String archArg = clist[ ++i ];
        archName = archArg.toUpperCase();
        if ( archSet ){
            System.err.println(Localizer.getString("javacodecompact.too_many_-arch_targetarchname_specifiers"));
            success = false;
        }
        archSet = true;
        continue;
        } else if (clist[i].equals(/*NOI18N*/"-s")){ 
        doShared = true;
        } else if ( clist[i].equals("-memberlist") ){
        loadMembers( clist[++i], classesProcessed );
        } else if ( clist[i].equals("-headersDir") ){
        String type = clist[++i];
        String dir = clist[++i];
        headerDirs.put(type, dir);
        buildTables = true; // got to.
        } else if ( clist[i].equals("-stubs") ){
        stubDestName = clist[++i];
        } else if ( clist[i].equals("-trace") ){
        stubTraceMode = true;
        } else if ( clist[i].equals("-f") ){
        try {
            success = processOptions( parseOptionFile( clist[++i] ) );
        } catch ( java.io.IOException e ){
            e.printStackTrace();
            success = false;
        }
        } else if ( clist[i].equals("-nativesType") ){
        String name = clist[++i];
        String patterns = clist[++i];
        nativeTypes.addTypePatterns( name, patterns );
        } else if ( clist[i].equals("-extraHeaders") ){
        String name = clist[++i];
        String patterns = clist[++i];
        extraHeaders.addTypePatterns( name, patterns );
        } else if ( clist[i].equals("-maxSegmentSize") ){
        String arg = clist[++i];
        try {
            maxSegmentSize = (new Integer(arg)).intValue();
        } catch (NumberFormatException ex) {
            System.err.println(Localizer.getString("javacodecompact.invalid_max_segment_size"));
            success = false;
        }
        } else { 
        readFile( clist[i], classesProcessed );
        }
    }

    // Default classname filter for natives
    nativeTypes.addTypePatterns( "JDKPack", "-*" );

    return success;
    
private voidreadFile(java.lang.String fileName, java.util.Vector classesProcessed)


    if ( rdr == null ){
        rdr = new ClassReader( t, verbosity );
    }
    try {
        if (fileName.endsWith(".zip") || fileName.endsWith(".jar")){ 
        rdr.readZip( fileName, classesProcessed );
        } else { 
        rdr.readFile( fileName, classesProcessed );
        fileFound( fileName );
        }
    } catch ( IOException e ){
        System.out.println(Localizer.getString("javacodecompact.could_not_read_file", fileName));
        e.printStackTrace();
        fail = true;
    }
    
public java.util.VectorunresolvedClassNames()

    Vector names  = new Vector();
    Enumeration symbols = t.getEnumeration();
    while ( symbols.hasMoreElements() ){
        Object o = symbols.nextElement();
        if ( o instanceof ClassConstant ){
        ClassConstant cc = (ClassConstant)o;
        if ( ! cc.isResolved() ){
            names.addElement( cc.name.string );
            cc.forget(); // so 'unresolved' doesn't stick.
        }
        }
    }
    Enumeration classes = ClassInfo.allClasses();
    while ( classes.hasMoreElements() ){
        ClassInfo c = (ClassInfo) classes.nextElement();
        ConstantObject constants[] = c.constants;
        if ( constants == null ) 
        continue;
        int nc = constants.length;
        for ( int i = 0 ; i < nc; i++ ){
        if ( (constants[i] instanceof ClassConstant ) && ! constants[i].isResolved() ){
            //
            // so far, entries in the names array are
            // unique. But because each class has a separate
            // interfaces array, the current candidate
            // may already be on it. Avoid adding it 
            // a second time!
            // Also, don't put arrays on this list!
            ClassConstant intrf = (ClassConstant)constants[i];
            String intname = intrf.name.string;
            if ( (intname.charAt(0) != Const.SIGC_ARRAY ) && ! names.contains( intname ) )
            names.addElement( intname );
            intrf.forget(); // so 'unresolved' doesn't stick.
        }
        }
    }
    return names;
    
private voidwriteCStubs(ClassInfo[] c, int nclasses)

    // (conditional file creation copied from above)
    File destFile = new File( stubDestName );
    File dumpFile;

    if ( destFile.exists() ){
        dumpFile = new File( stubDestName+".TMP" );
    } else {
        dumpFile = destFile;
    }
    try {
        PrintStream o = new BufferedPrintStream( new FileOutputStream( dumpFile ) );
        CStubGenerator cs = new CStubGenerator( stubTraceMode, o );
        cs.writeStubs( c, nclasses, nativeTypes );
        o.close();
    } catch ( IOException e ){
        e.printStackTrace();
        return;
    }
    if ( destFile != dumpFile ){
        // copy and delete
        FileCompare.conditionalCopy( dumpFile, destFile );
        dumpFile.delete();
    }
    
private voidwriteNativesHeaders(ClassnameFilterList groups, ClassInfo[] c, int nclasses)

    Hashtable dumpers = new Hashtable(7);

    for ( int i = 0; i < nclasses; i++ ){
        ClassInfo ci = c[i];
        String classname = ci.className;

        String[] types =  groups.getTypes( classname );
        for ( int j = 0; j < types.length; ++j) {
        String type = types[j];
        HeaderDump hd = type != null ?
            (HeaderDump)dumpers.get(type) : null;
        if (hd == null) {
            try {
            Class dumperClass =
                Class.forName("runtime." + type + "Header");
            hd = (HeaderDump)dumperClass.newInstance();
            dumpers.put(type, hd);
            } catch (Exception e) {
            continue;
            }
        }
        String classFilename = hd.filename( classname );
        String destFilename = classFilename+".h";

        String nativesHeaderDestDir = (String)headerDirs.get(type);
        File nativesDestFile = new File(nativesHeaderDestDir,
                        destFilename);
        File nativesDumpFile;

        boolean didWorkForNatives;

        if ( nativesDestFile.exists() ){
            nativesDumpFile =
            new File( nativesHeaderDestDir, classFilename+".TMP" );
        } else {
            nativesDumpFile = nativesDestFile;
        }

        try {
            PrintStream o = new BufferedPrintStream( new FileOutputStream( nativesDumpFile ) );
            didWorkForNatives = hd.dumpHeader( ci, o );
            o.close();
        } catch ( IOException e ){
            e.printStackTrace();
            continue;
        }

        if ( didWorkForNatives ){
            if ( nativesDestFile != nativesDumpFile ){
            // copy and delete
            FileCompare.conditionalCopy( nativesDumpFile,
                             nativesDestFile );
            nativesDumpFile.delete();
            }
        } else {
            nativesDumpFile.delete();
        }
        }
    }
    
private booleanwriteROMFile(java.lang.String outName, ClassInfo[] classTable, java.util.Vector attributes)

    boolean good = true;
    ConstantPool sharedConstant = null;

    //
    // did arg parsing.
    // now do work.
    //

    good = instantiateArrayClasses( classTable, verbosity>1 );
    processArrayClasses( verbosity>1, t );
    PrimitiveClassInfo.init( verbosity > 1, t);

    // is better to have this after instantiating Array classes, I think.
    ClassClass classes[] = finalizeClasses();
    int       totalclasses = classes.length;
    // at this point, the classes array INCLUDES all the array
    // classes. classTable doesn't include these!
    // Since array classes CANNOT participate in sharing
    // (because of magic offsets) they are excluded from the
    // sharing calculation below. And because they don't have
    // any code...

    if (doShared) {
        // create a shared constant pool
        sharedConstant = new ConstantPool();
            for (int i = 0; i < classTable.length; i++) 
        addConstant2SharedPool(classTable[i], sharedConstant);
           
        // sort the reference count
        sharedConstant.doSort();

            // run via the shared constant pool once.
            if (ClassClass.isPartiallyResolved(sharedConstant.getConstants())) {
                sharedConstant = ClassClass.makeResolvable(sharedConstant);
            }
        } else {
            for (int i = 0; i < totalclasses; i++)
                classes[i].adjustSymbolicConstants();
        }

    for (int i = 0; i < totalclasses; i++) 
            classes[i].ci.relocateAndPackCode();

    if ( ! good ) return false;

    CoreImageWriter w;

    {
        String writername = "runtime."+archName+"Writer";
        Class writerClass = null;
        try {
        writerClass = Class.forName( writername );
        } catch ( ClassNotFoundException ee ){
        System.err.println(Localizer.getString("javacodecompact.not_supported", archName));
        return false;
        }
        try {
        w = (CoreImageWriter)(writerClass.newInstance());
        } catch ( Exception e ){
        System.err.println(Localizer.getString("javacodecompact.could_not_instantiate", writername));
        e.printStackTrace( );
        return false;
        }
    }

    w.init(classDebug, nativeTypes, verbosity>0, maxSegmentSize);

    Enumeration attr = attributes.elements();
    while ( attr.hasMoreElements() ){
        String val = (String)attr.nextElement();
        if ( ! w.setAttribute( val ) ){
        System.err.println(Localizer.getString("javacodecompact.bad_attribute_value",val));
        }
    }

    if (  w.open( outName ) != true ) {
        w.printError( System.out );
        good = false;
    } else {
        good = w.writeClasses(t, sharedConstant);
        w.printSpaceStats( System.out );
        w.close();
    }
    return good;