JavaCodeCompactpublic 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 |
Methods Summary |
---|
private void | addConstant2SharedPool(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 boolean | collectArrayClass(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 void | fileFound(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 boolean | instantiateArrayClasses(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 void | loadMembers(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 void | main(java.lang.String[] clist)
boolean success = new JavaCodeCompact().process( clist );
if ( !success ){
System.out.flush();
System.err.flush();
System.exit(1);
}
return;
| private void | makeOutfileName()
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 boolean | process(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 void | processArrayClasses(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 boolean | processOptions(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 void | readFile(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.Vector | unresolvedClassNames()
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 void | writeCStubs(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 void | writeNativesHeaders(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 boolean | writeROMFile(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;
|
|