0001: /*
0002: * @(#)CVMWriter.java 1.153 06/10/27
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: *
0026: */
0027: package runtime;
0028:
0029: import consts.Const;
0030: import consts.CVMConst;
0031: import components.*;
0032: import vm.*;
0033: import jcc.Util;
0034: import util.*;
0035: import java.util.Arrays;
0036: import java.util.Comparator;
0037: import java.util.Vector;
0038: import java.util.Enumeration;
0039: import java.util.Hashtable;
0040: import java.io.OutputStream;
0041:
0042: /*
0043: * The CoreImageWriter for the Embedded VM
0044: */
0045:
0046: public class CVMWriter implements CoreImageWriter, Const, CVMConst {
0047:
0048: /* INSTANCE DATA */
0049: protected Exception failureMode = null; // only interesting on falure
0050:
0051: protected String outputFileName;
0052: protected CCodeWriter classOut;
0053: protected CCodeWriter auxOut;
0054: protected OutputStream xxx;
0055: protected OutputStream zzz;
0056:
0057: protected String headerFileName = null;
0058: protected CCodeWriter headerOut;
0059: protected OutputStream yyy;
0060:
0061: protected String globalHeaderFileName = null;
0062: protected CCodeWriter globalHeaderOut;
0063: protected OutputStream www;
0064: /*
0065: * The following only used if we're segmenting the output,
0066: * which happens if this.init gets a maxSegSize > 0
0067: */
0068: protected boolean segmentedOutput;
0069: protected int maxClasses;
0070: protected int curClasses = 0;
0071: protected int nClassfileOut;
0072: protected BufferedPrintStream listOut;
0073:
0074: protected CVMStringTable stringTable;
0075: protected CVMClass classes[];
0076:
0077: private VMClassFactory classMaker = new CVMClassFactory();
0078:
0079: private CVMInitInfo initInfo;
0080: private CVMInitInfo initInfoForMBs;
0081:
0082: boolean formatError = false;
0083: boolean verbose = false;
0084: boolean classDebug = false;
0085: boolean lossless = false;
0086: boolean mutableMBs = false;
0087:
0088: private static final String staticInitThreadStoreName = "StaticInitThreadStorage";
0089: private static final String stringArrayName = "CVM_ROMStrings";
0090: private static final String masterStringArrayName = "CVM_ROMStringsMaster";
0091: private static final String staticStoreName = "CVM_staticData";
0092: private static final String numStaticStoreName = "CVM_nStaticData";
0093: private static final String masterStaticStoreName = "CVM_StaticDataMaster";
0094:
0095: private ClassnameFilterList nativeTypes;
0096: private ClassnameFilter invisibleClassList = new ClassnameFilter();
0097:
0098: private boolean classLoading = true; // by default.
0099:
0100: // Place all byte codes into read-write memory. Useful for setting
0101: // breakpoints.
0102: protected boolean noPureCode = false;
0103:
0104: private boolean doShared;
0105: private String sharedConstantPoolName;
0106: private int sharedConstantPoolSize;
0107:
0108: private CVMMethodType[] methodTypes;
0109: private int[] nMethodTypes;
0110: private int totalMethodTypes;
0111:
0112: //
0113: // to keep track of which variants of classblock, method arrays, field arrays,
0114: // and method descriptors have been declared
0115: // see declareClassblock, declareMethodArray, and declareFieldArray
0116: // respectively
0117: //
0118: private java.util.BitSet classblockSizes = new java.util.BitSet();
0119: private java.util.BitSet runtimeMethodArraySizes = new java.util.BitSet();
0120: private java.util.BitSet methodArraySizes = new java.util.BitSet();
0121: private java.util.BitSet compressibleMethodArraySizes = new java.util.BitSet();
0122: private java.util.BitSet fieldArraySizes = new java.util.BitSet();
0123:
0124: /*
0125: * Per-class data that is built up as we
0126: * print out the various data structures.
0127: * Rather than trying to pass around both name and size of each,
0128: * we collect the information here.
0129: */
0130: private String classBlockName;
0131: private String constantPoolName;
0132: private int constantPoolSize;
0133: private String methodArrayName;
0134: private int methodTableSize;
0135: private String checkedExceptionName;
0136: private String interfaceTableName;
0137: private String fieldTableName;
0138: private int fieldTableSize;
0139:
0140: /* for statistics only */
0141: int ncodebytes;
0142: int ncatchframes;
0143: int nmethods;
0144: int nfields;
0145: int nconstants;
0146: int njavastrings;
0147: int ninnerclasses;
0148: int nWritableMethodBlocks;
0149: int nClassesWithWritableMethodBlocks;
0150: int nClinits;
0151: int nMethodsWithCheckinitInvokes;
0152: int nTotalMethods; /* number of total romized methods */
0153:
0154: private CVMMethodStats methStats = new CVMMethodStats();
0155:
0156: public CVMWriter() {
0157: initInfo = new CVMInitInfo();
0158: initInfoForMBs = new CVMInitInfo();
0159:
0160: stringTable = new CVMStringTable(initInfo);
0161: }
0162:
0163: public void init(boolean classDebug, boolean lossless,
0164: ClassnameFilterList nativeTypes, boolean verbose,
0165: int maxSegmentSize, boolean mutableMBs) {
0166: this .verbose = verbose;
0167: this .classDebug = classDebug;
0168: this .lossless = lossless;
0169: this .nativeTypes = nativeTypes;
0170: this .mutableMBs = mutableMBs;
0171:
0172: if (maxSegmentSize > 0) {
0173: this .segmentedOutput = true;
0174: this .maxClasses = maxSegmentSize;
0175: } else {
0176: this .segmentedOutput = false;
0177: }
0178: }
0179:
0180: // If attribute starts with attributeName, then parse the rest of the
0181: // string as a list of classes.
0182: private boolean parseClassListAttribute(String attributeName,
0183: String attribute, ClassnameFilter filter) {
0184: if (!attribute.startsWith(attributeName))
0185: return false;
0186: String val = attribute.substring(attributeName.length());
0187: java.util.StringTokenizer tkn = new java.util.StringTokenizer(
0188: val, " ,", false);
0189: while (tkn.hasMoreTokens()) {
0190: String classname = tkn.nextToken().replace('.', '/');
0191: filter.includeName(classname);
0192: }
0193: return true;
0194: }
0195:
0196: private boolean isClassInvisible(String classname) {
0197: return invisibleClassList.accept(null, classname);
0198: }
0199:
0200: private boolean isClassCNI(String classname) {
0201: // compare against interned string
0202: return nativeTypes.isType(classname, "CNI");
0203: }
0204:
0205: private boolean isClassJNI(String classname) {
0206: // compare against interned string
0207: return nativeTypes.isType(classname, "JNI");
0208: }
0209:
0210: public boolean setAttribute(String attribute) {
0211: if (parseClassListAttribute("invisible=", attribute,
0212: invisibleClassList)) {
0213: return true;
0214: } else if (attribute.equals("noClassLoading")) {
0215: classLoading = false;
0216: return true;
0217: } else if (attribute.equals("noPureCode")) {
0218: noPureCode = true;
0219: return true;
0220: } else
0221: return false; // no attribute by this name.
0222: }
0223:
0224: /*
0225: * If this is a simple, unsegmented output file, then
0226: * the file name given is the name of the C file, from which
0227: * we compute the .h file, crudely. We open them here.
0228: *
0229: * But if this is a segmented output job, then the name given
0230: * serves as a prefix, and we open a whole bunch of files and
0231: * set up a whole bunch of state:
0232: * filename+"List" - file containing names of all .c files generated
0233: * opened as listOut;
0234: * filename+".h" - header file, as usual
0235: * filename+"Aux.c" - file containing all type, string, and other miscellanious
0236: * generated stuff.
0237: * opened as auxOut;
0238: * filename+"Class"+n+".c" - files containing directly class-related data,
0239: * whole classes, and a max of this.maxClasses of them
0240: * apiece.
0241: */
0242: public boolean open(String filename) {
0243: if (classOut != null)
0244: close();
0245: outputFileName = filename;
0246: if (!segmentedOutput) {
0247: /* old-fashioned, single output case */
0248: if (filename == null) {
0249: xxx = System.out;
0250: headerFileName = "jcc.output.h";
0251: } else {
0252: try {
0253: xxx = new java.io.FileOutputStream(filename);
0254: } catch (java.io.IOException e) {
0255: failureMode = e;
0256: return false;
0257: }
0258: headerFileName = filename + ".h";
0259: }
0260: try {
0261: classOut = auxOut = new CCodeWriter(xxx);
0262: yyy = new java.io.FileOutputStream(headerFileName);
0263: headerOut = new CCodeWriter(yyy);
0264:
0265: globalHeaderFileName = filename + "Globals.h";
0266: www = new java.io.FileOutputStream(globalHeaderFileName);
0267: globalHeaderOut = new CCodeWriter(www);
0268: } catch (java.io.IOException e) {
0269: failureMode = e;
0270: return false;
0271: }
0272: writeHeaderPrologue(headerOut);
0273: writeGlobalHeaderPrologue(globalHeaderOut);
0274: writePrologue(classOut);
0275: return true;
0276: } else {
0277: /* segmented output.
0278: * open the aux file, the first classOut file, the list file and
0279: * the header file.
0280: */
0281: curClasses = 0;
0282: nClassfileOut = 0;
0283: headerFileName = outputFileName + ".h";
0284: try {
0285: yyy = new java.io.FileOutputStream(headerFileName);
0286: headerOut = new CCodeWriter(yyy);
0287:
0288: globalHeaderFileName = outputFileName + "Globals.h";
0289: www = new java.io.FileOutputStream(globalHeaderFileName);
0290: globalHeaderOut = new CCodeWriter(www);
0291: zzz = new java.io.FileOutputStream(filename + "Aux.c");
0292: auxOut = new CCodeWriter(zzz);
0293: listOut = new BufferedPrintStream(
0294: new java.io.FileOutputStream(outputFileName
0295: + "List"));
0296: listOut.println(filename + "Aux.c");
0297: openNextClassFile();
0298: } catch (java.io.IOException e) {
0299: failureMode = e;
0300: return false;
0301: }
0302: writeHeaderPrologue(headerOut);
0303: writeGlobalHeaderPrologue(globalHeaderOut);
0304: writePrologue(auxOut);
0305:
0306: /*
0307: * Moved global variables to CVMROMGlobals
0308: */
0309: auxOut.println("");
0310: auxOut
0311: .println("/* Moved global variables to CVMROMGlobals.");
0312: auxOut
0313: .println(" * For each global variable <V> that was originally accessible outside");
0314: auxOut
0315: .println(" * the generated code, a corresponding constant pointer variable");
0316: auxOut
0317: .println(" * is provided here that points into the global structure.");
0318: auxOut
0319: .println(" * (the name <V> has only been changed to <V>ptr for those");
0320: auxOut
0321: .println(" * variables where the way they are accessed is changed)");
0322: auxOut.println(" * ");
0323: auxOut
0324: .println(" * The size of CVMROMGlobals is provided in a global constant");
0325: auxOut
0326: .println(" * so that the structure can be copied without including its definition.");
0327: auxOut.println(" */");
0328: auxOut.println("");
0329: auxOut.println("struct CVMROMGlobalState CVMROMGlobals;");
0330: auxOut
0331: .println("const int CVMROMGlobalsSize = sizeof(CVMROMGlobals);");
0332: auxOut.println("");
0333: auxOut
0334: .println("CVMTypeIDNamePart * const CVMMemberNameHash = CVMROMGlobals.CVMMemberNameHash;");
0335: auxOut
0336: .println("CVMTypeIDTypePart * const CVMMethodTypeHash = CVMROMGlobals.CVMMethodTypeHash;");
0337: auxOut
0338: .println("struct sigForm ** const CVMformTablePtr = &CVMROMGlobals.CVMformTable;");
0339: auxOut
0340: .println("struct pkg * const CVM_ROMpackages = CVMROMGlobals.CVM_ROMpackages;");
0341: auxOut
0342: .println("struct pkg ** const CVM_pkgHashtable = CVMROMGlobals.CVM_pkgHashtable;");
0343: auxOut
0344: .println("struct java_lang_Class * const CVM_ROMClassBlocks = CVMROMGlobals.CVM_ROMClassBlocks;");
0345: auxOut
0346: .println("struct java_lang_Class * const CVM_ROMClasses = CVMROMGlobals.CVM_ROMClasses;");
0347: auxOut
0348: .println("CVMAddr * const CVM_staticData = CVMROMGlobals.CVM_staticData;");
0349: auxOut
0350: .println("struct java_lang_String * const CVM_ROMStrings = CVMROMGlobals.CVM_ROMStrings;");
0351: auxOut
0352: .println("#if defined(CVM_JIT) && defined(CVM_MTASK)");
0353: auxOut
0354: .println("CVMUint16 * const CVMROMMethodInvokeCosts = CVMROMGlobals.CVMROMMethodInvokeCosts;");
0355: auxOut.println("#endif");
0356: auxOut.println("");
0357:
0358: return true;
0359: }
0360: }
0361:
0362: private void openNextClassFile() throws java.io.IOException {
0363: if (classOut != null) {
0364: classOut.close();
0365: }
0366: String newName = outputFileName + (nClassfileOut++) + ".c";
0367: xxx = new java.io.FileOutputStream(newName);
0368: classOut = new CCodeWriter(xxx);
0369: listOut.println(newName);
0370: writePrologue(classOut);
0371: }
0372:
0373: public void close() {
0374: if (classOut != null) {
0375: classOut.close();
0376: }
0377: if (auxOut != null && auxOut != classOut) {
0378: auxOut.close();
0379: }
0380: auxOut = null;
0381: classOut = null;
0382: if (listOut != null) {
0383: listOut.close();
0384: listOut = null;
0385: }
0386: if (headerOut != null) {
0387: /*
0388: * Added header file for globals
0389: */
0390: writeHeaderEpilogue(headerOut);
0391: headerOut.close();
0392: headerOut = null;
0393: }
0394: /*
0395: * Added header file for globals
0396: */
0397: if (globalHeaderOut != null) {
0398: writeGlobalHeaderEpilogue(globalHeaderOut);
0399: globalHeaderOut.close();
0400: globalHeaderOut = null;
0401: }
0402: outputFileName = null;
0403: return;
0404: }
0405:
0406: public void printError(java.io.PrintStream o) {
0407: if (failureMode != null) {
0408: failureMode.printStackTrace(o);
0409: }
0410: }
0411:
0412: protected void declare(String declaration,
0413: BufferedPrintStream curOut) {
0414: headerOut.print("extern ");
0415: headerOut.print(declaration);
0416: headerOut.write(';');
0417: headerOut.write('\n');
0418: curOut.print(declaration);
0419: }
0420:
0421: public static String getUTF(UnicodeConstant u) {
0422: return u.toUTF();
0423: }
0424:
0425: /*
0426: * For Java methods,
0427: * write out the structure which will be initialized with a
0428: * JavaMethodDescriptor and its associated structures: code array,
0429: * line numbers, exceptions, local variables
0430: */
0431: private void writeCode(CVMMethodInfo meth) {
0432: MethodInfo mi = meth.method;
0433: LineNumberTableEntry[] lntab = mi.getLineNumberTable();
0434: LocalVariableTableEntry[] locvartab = mi
0435: .getLocalVariableTable();
0436:
0437: int codeLengthRoundup = (mi.code.length + 3) & ~3;
0438: int nTryCatch = (mi.exceptionTable == null) ? 0
0439: : mi.exceptionTable.length;
0440: int nLineNumbers = (classDebug && lntab != null) ? lntab.length
0441: : 0;
0442: int nLocals = (classDebug && locvartab != null) ? locvartab.length
0443: : 0;
0444:
0445: String codeBlockName = meth.getNativeName();
0446: String descriptorTypeTag = codeBlockName + "MDType";
0447:
0448: CCodeWriter declareOut;
0449:
0450: boolean impureCode = noPureCode || !meth.isCodePure();
0451:
0452: classOut.println("\n/* Code block for "
0453: + meth.method.qualifiedName() + " */");
0454:
0455: /*
0456: * Declare the structure which will be initialized with a
0457: * JavaMethodDescriptor and its associated structures: code array,
0458: * line numbers, exceptions, local variables
0459: * Unlike several of the other structures, we do not bother remembering
0460: * and reusing prior definitions -- there are so many dimensions it doesn't
0461: * see worthwhile.
0462: * In fact, the only reason this is not an anonimous structure is the
0463: * case where it has to be writable and initialized, for JVMTI.
0464: */
0465: if (!impureCode) {
0466: // this might as well be static since there will be
0467: // no external references to it
0468: classOut.print("STATIC ");
0469: declareOut = classOut;
0470: } else {
0471: headerOut.print("extern ");
0472: declareOut = headerOut;
0473: }
0474:
0475: declareOut.print("const struct ");
0476: declareOut.print(descriptorTypeTag);
0477: declareOut.println(" {\n union {");
0478: declareOut.println(" CVMJavaMethodDescriptor jmd;");
0479: declareOut.println(" CVMUint"
0480: + ((meth.alignment() == 1) ? "8" : "32")
0481: + " align;\n } u;");
0482: declareOut.println(" CVMUint8 data[" + codeLengthRoundup
0483: + "];");
0484: if (nTryCatch != 0) {
0485: declareOut
0486: .println(" CVMExceptionHandler exceptionTable["
0487: + nTryCatch + "];");
0488: }
0489: if (nLineNumbers != 0) {
0490: declareOut
0491: .println(" CVMLineNumberEntry lineNumberTable["
0492: + nLineNumbers + "];");
0493: }
0494: if (nLocals != 0) {
0495: declareOut
0496: .println(" CVMLocalVariableEntry localVariableTable["
0497: + nLocals + "];");
0498: }
0499: declareOut.print("} ");
0500:
0501: /*
0502: * Now we have the shape of the data we need to supply the data itself
0503: * (themselves?)
0504: *
0505: * EITHER the MD has to be writable. in thise case the declaration above
0506: * was to the header file. Append to it the names of the master and
0507: * the working copy, emit the master, reserve space for the copy,
0508: * and don't forget the initialization instructions.
0509: *
0510: * OR the MD is read-only, const, so this is the thing itself
0511: */
0512:
0513: if (impureCode) {
0514: declareOut.print(codeBlockName);
0515: declareOut.print("Master;\n");
0516:
0517: declareOut.print(" extern struct " + descriptorTypeTag);
0518: declareOut.write(' ');
0519: declareOut.println(codeBlockName);
0520: declareOut.println(";");
0521:
0522: classOut.print("struct " + descriptorTypeTag);
0523: classOut.write(' ');
0524: classOut.println(codeBlockName);
0525: classOut.println(";");
0526:
0527: classOut.print("const struct ");
0528: classOut.print(descriptorTypeTag);
0529: classOut.write(' ');
0530: classOut.print(codeBlockName);
0531: classOut.print("Master");
0532:
0533: initInfo.addInfo("&" + codeBlockName + "Master", "&"
0534: + codeBlockName, "sizeof( struct "
0535: + descriptorTypeTag + ")");
0536: } else {
0537: classOut.print(codeBlockName);
0538: }
0539:
0540: classOut.print(" = {\n { CVM_INIT_JAVA_METHOD_DESCRIPTOR(");
0541: /*
0542: * Make sure locals are big enough for any return value.
0543: */
0544: classOut.print(mi.stack + ", " + Math.max(2, mi.locals));
0545: classOut.print(", ");
0546: if (meth.codeHasJsr()) {
0547: classOut.print("CVM_JMD_MAY_NEED_REWRITE|");
0548: if (meth.alignment() != 1) {
0549: classOut.print("CVM_JMD_NEEDS_ALIGNMENT|");
0550: }
0551: }
0552: if (meth.isStrictFP()) {
0553: classOut.print("CVM_JMD_STRICT|");
0554: }
0555: classOut.print("0, ");
0556: classOut.print(nTryCatch + ", " + mi.code.length);
0557: classOut.print(", " + nLineNumbers + ", " + nLocals);
0558: classOut.print(") },\n {");
0559:
0560: // output the code array
0561: int j = 99;
0562: byte[] methodCode = mi.code;
0563: int l = methodCode.length;
0564: for (int i = 0; i < l; i++) {
0565: if (j >= 12) {
0566: classOut.print("\n\t");
0567: j = 1;
0568: } else {
0569: j += 1;
0570: }
0571: classOut.printHexInt(methodCode[i] & 0xff);
0572: classOut.print(",");
0573: }
0574: classOut.print("\n }");
0575: ncodebytes += mi.code.length;
0576:
0577: // output the CVMExceptionHandler[] (catch frames)
0578: if (nTryCatch != 0) {
0579: classOut.println(",\n {");
0580: for (int i = 0; i < nTryCatch; i++) {
0581: ExceptionEntry e = mi.exceptionTable[i];
0582: classOut.println("\t{ " + e.startPC + ", " + e.endPC
0583: + ", " + e.handlerPC + ", "
0584: + (e.catchType == null ? 0 : e.catchType.index)
0585: + "},");
0586: }
0587: classOut.print(" }");
0588: ncatchframes += nTryCatch;
0589: }
0590:
0591: // output the CVMLineNumberEntry[]
0592: if (nLineNumbers != 0) {
0593: classOut.println(",\n {");
0594: for (int i = 0; i < nLineNumbers; i++) {
0595: LineNumberTableEntry e = lntab[i];
0596: classOut.println("\t{ " + e.startPC + ", "
0597: + e.lineNumber + "},");
0598: }
0599: classOut.print(" }");
0600: }
0601:
0602: // output the CVMLocalVariableEntry[]
0603: if (nLocals != 0) {
0604: classOut.println(",\n {");
0605: for (int i = 0; i < nLocals; i++) {
0606: LocalVariableTableEntry e = locvartab[i];
0607: int typeid = CVMDataType.parseSignature(getUTF(e.sig));
0608: int nameid = CVMMemberNameEntry
0609: .lookupEnter(getUTF(e.name));
0610: classOut.println("\t{ " + e.pc0 + ", " + e.length
0611: + ", " + e.slot + ", RAW_TYPEID_NAME_PART(0x"
0612: + Integer.toHexString(nameid)
0613: + "), RAW_TYPEID_TYPE_PART(0x"
0614: + Integer.toHexString(typeid) + ")},");
0615: }
0616: classOut.print(" }");
0617: }
0618:
0619: classOut.println("\n};");
0620:
0621: }
0622:
0623: //
0624: // The cb repeats every 'cbRepeat' entries in MethodArray's and
0625: // FieldArray's
0626: //
0627: static final int cbRepeat = 256;
0628:
0629: private void handleMethodArrayDecl(String flavorName, int nmethods) {
0630: // need to declare a structure containing a classblock pointer
0631: // plus "nmethods" CVMMethodBlock structures
0632: int i;
0633: headerOut.print(flavorName + " {");
0634: if (nmethods > cbRepeat)
0635: headerOut.println();
0636: int numMethodArrays = (nmethods - 1) / cbRepeat + 1;
0637: for (i = 1; i <= numMethodArrays; i++) {
0638: int nmethods2; // # methods in this method array
0639: if (i == numMethodArrays) {
0640: nmethods2 = (nmethods - 1) % cbRepeat + 1;
0641: } else {
0642: nmethods2 = cbRepeat;
0643: }
0644: headerOut
0645: .println(" CVMClassBlock const *cb" + i + ";"
0646: + " CVMMethodBlock mb" + i + "["
0647: + nmethods2 + "];");
0648: if (nmethods > cbRepeat) {
0649: headerOut.println();
0650: }
0651: }
0652: headerOut.println(" };");
0653: }
0654:
0655: private void declareMethodArray(CVMClass c, boolean writeable,
0656: boolean compressible) {
0657: String this TableName = c.getNativeName() + "_methods";
0658: String tableAddress = "&" + this TableName;
0659: int nmethods = c.methods.length;
0660: String methodArrayFlavor = "struct CVMMethodArray" + nmethods;
0661: String methodArrayImmutFlavor = "struct CVMMethodArrayImmut"
0662: + nmethods;
0663: String methodArrayImmutCompFlavor = "struct CVMMethodArrayImmutCompressed"
0664: + nmethods;
0665: String immutFlavor;
0666: String immutableType;
0667: java.util.BitSet methArrSizes;
0668:
0669: /* count the total number of romized methods */
0670: nTotalMethods += nmethods;
0671:
0672: if (compressible) {
0673: immutableType = "CVMMethodBlockImmutableCompressed";
0674: immutFlavor = methodArrayImmutCompFlavor;
0675: methArrSizes = compressibleMethodArraySizes;
0676: } else {
0677: immutableType = "CVMMethodBlockImmutable";
0678: immutFlavor = methodArrayImmutFlavor;
0679: methArrSizes = methodArraySizes;
0680: }
0681:
0682: /*
0683: * Declare the runtime typedef
0684: */
0685: if (!runtimeMethodArraySizes.get(nmethods)) {
0686: handleMethodArrayDecl(methodArrayFlavor, nmethods);
0687: runtimeMethodArraySizes.set(nmethods);
0688: }
0689:
0690: /*
0691: * And now, declare the proper immutable type
0692: */
0693: if (!methArrSizes.get(nmethods)) {
0694: /* The immutable version is easy. Just bundle all the immutable
0695: parts together, and let the initializer take care
0696: of the methods arrays */
0697: headerOut.print(immutFlavor + " {");
0698: headerOut.println(" CVMClassBlock const *cb; "
0699: + immutableType + " mb[" + nmethods + "];");
0700: headerOut.println(" };");
0701: methArrSizes.set(nmethods);
0702: }
0703:
0704: if (writeable) {
0705: /*
0706: * Declare actual array, record copying information.
0707: * What we're about to initialize is the read-only master.
0708: */
0709: String masterName = this TableName + "Master";
0710:
0711: /*
0712: * Moved global variables to CVMROMGlobals.
0713: */
0714: /*
0715: declare(methodArrayFlavor+" "+thisTableName, classOut);
0716: classOut.println(";");
0717: */
0718: globalHeaderOut.println(" " + methodArrayFlavor + " "
0719: + this TableName + ";");
0720: initInfoForMBs.addInfo("&" + masterName);
0721: declare("const " + immutFlavor + " " + masterName, classOut);
0722: } else {
0723: declare("const " + methodArrayFlavor + " " + this TableName,
0724: classOut);
0725: }
0726: /*
0727: * Moved globals to CVMROMGlobals. For classes without
0728: * writeable methods, there is (still) a constant global
0729: * variable <class>_methods - nothing has changed. For
0730: * classes with writeable methods, the <class>_methods
0731: * variable lives in the CVMROMGlobals structure.
0732: */
0733: if (writeable) {
0734: methodArrayName = "&CVMROMGlobals." + this TableName;
0735: } else {
0736: methodArrayName = tableAddress;
0737: }
0738: methodTableSize = nmethods;
0739: }
0740:
0741: //
0742: // Find out variations of several method components to see whether
0743: // compression opportunities exist.
0744: //
0745: // 1) Look for (argsSize, invokerIdx, accessFlags) triples. These
0746: // don't vary much, so we can encode commonly occurring
0747: // variants within 8-bits.
0748: //
0749: // 2) Check whether the method table index and checkedExceptionsOffset
0750: // can each be encoded in a byte.
0751: //
0752: // If #1 and #2 hold, we can shave off a word from the immutable method
0753: // block encoding.
0754: //
0755: void analyzeMethodsForCompression(CVMClass c) {
0756: CVMMethodInfo m[] = c.methods;
0757: int nCheckedExceptions = 0;
0758: int currCheckedException = 0;
0759: int checkedExceptionVector[];
0760: if ((m == null) || (m.length == 0)) {
0761: /* Nothing to do */
0762: return;
0763: }
0764: int nmethod = m.length;
0765: //
0766: // Traverse all methods, and look for opportunities. If any
0767: // one method in the methods of a class is not compressible,
0768: // the entire method array is expanded in the "long" form
0769: //
0770: for (int i = 0; i < nmethod; i++) {
0771: CVMMethodInfo meth = m[i];
0772: MethodInfo mi = meth.method;
0773: if (mi.exceptionsThrown != null) {
0774: int n = mi.exceptionsThrown.length;
0775: if (n != 0)
0776: nCheckedExceptions += n + 1; // "1" is for the count word.
0777: }
0778: }
0779: //
0780: // if any methods declare that they throw any exceptions,
0781: // we need to construct the exception vector.
0782: if (nCheckedExceptions == 0) {
0783: checkedExceptionVector = null;
0784: } else {
0785: // Ensure that item 0 in this array is always unused.
0786: // See classes.h.
0787: nCheckedExceptions++;
0788: checkedExceptionVector = new int[nCheckedExceptions];
0789: checkedExceptionVector[0] = 0;
0790: currCheckedException = 1;
0791: }
0792:
0793: for (int i = 0; i < nmethod; i++) {
0794: CVMMethodInfo meth = m[i];
0795:
0796: //
0797: // Item #1
0798: //
0799: int access = meth.CVMflags();
0800:
0801: boolean synchro = (access & CVM_METHOD_ACC_SYNCHRONIZED) != 0;
0802: boolean isNative = (access & CVM_METHOD_ACC_NATIVE) != 0;
0803: boolean isAbstract = (access & CVM_METHOD_ACC_ABSTRACT) != 0;
0804:
0805: //
0806: // Item #2
0807: //
0808: String invoker = isAbstract ? "CVM_INVOKE_ABSTRACT_METHOD"
0809: : isNative ? (isClassCNI(c.ci.className) ? "CVM_INVOKE_CNI_METHOD"
0810: : (synchro ? "CVM_INVOKE_JNI_SYNC_METHOD"
0811: : "CVM_INVOKE_JNI_METHOD"))
0812: : (synchro ? "CVM_INVOKE_JAVA_SYNC_METHOD"
0813: : "CVM_INVOKE_JAVA_METHOD");
0814:
0815: //
0816: // note the offset in the exception array,
0817: // and add to that array as necessary.
0818: //
0819: int exceptions;
0820: if ((meth.method.exceptionsThrown != null)
0821: && (meth.method.exceptionsThrown.length != 0)) {
0822: ClassConstant thrown[] = meth.method.exceptionsThrown;
0823: int net = thrown.length;
0824: exceptions = currCheckedException;
0825: checkedExceptionVector[currCheckedException++] = net;
0826: for (int j = 0; j < net; j++) {
0827: checkedExceptionVector[currCheckedException++] = thrown[j].index;
0828: }
0829: } else {
0830: // Note we have changed this from ((unsigned short)
0831: // -1) to 0 to be consistent with the documentation in
0832: // classes.h. A checkedExceptionsOffset of 0 indicates
0833: // no checked exceptions for the method. Also see the
0834: // allocation of the checkedExceptionVector above.
0835: exceptions = 0;
0836: }
0837: //
0838: // Item #3
0839: //
0840: int argssize = meth.method.argsSize;
0841:
0842: int tableIndex = meth.methodOffset();
0843:
0844: //
0845: // Remember these items
0846: // We won't know whether a class is compressible
0847: // until after all the triples for all methods have been seen
0848: //
0849: methStats.record(argssize, invoker, access);
0850:
0851: //
0852: // Also see whether the method table index and
0853: // checkedExceptionsOffset are encodable in one byte each.
0854: //
0855: if (tableIndex >= 256) {
0856: c.setCompressible(false);
0857: }
0858: if (exceptions >= 256) {
0859: c.setCompressible(false);
0860: }
0861: }
0862: }
0863:
0864: void writeMethods(CVMClass c) {
0865: boolean isCompressible = c.isCompressible();
0866: String cbname_comma = "&" + cbName(c) + ",";
0867: CVMMethodInfo m[] = c.methods;
0868: int nCheckedExceptions = 0;
0869: int currCheckedException = 0;
0870: int checkedExceptionVector[];
0871: boolean writableMethods = mutableMBs;
0872: if ((m == null) || (m.length == 0)) {
0873: methodArrayName = "0";
0874: checkedExceptionName = "0";
0875: methodTableSize = 0;
0876: return;
0877: }
0878: int nmethod = m.length;
0879: String this TableName = c.getNativeName() + "_methods";
0880: String this ExceptionName = null;
0881: for (int i = 0; i < nmethod; i++) {
0882: CVMMethodInfo meth = m[i];
0883: MethodInfo mi = meth.method;
0884: if (mi.exceptionsThrown != null) {
0885: int n = mi.exceptionsThrown.length;
0886: if (n != 0)
0887: nCheckedExceptions += n + 1; // "1" is for the count word.
0888: }
0889: if (mi.code != null) {
0890: writeCode(meth);
0891: }
0892: if (meth.codeHasJsr()) {
0893: writableMethods = true;
0894: }
0895: }
0896: //
0897: // if any methods declare that they throw any exceptions,
0898: // we need to construct the exception vector.
0899: if (nCheckedExceptions == 0) {
0900: checkedExceptionName = "0";
0901: checkedExceptionVector = null;
0902: } else {
0903: this ExceptionName = c.getNativeName() + "_throws";
0904: checkedExceptionName = this ExceptionName;
0905: // Ensure that item 0 in this array is always unused.
0906: // See classes.h.
0907: nCheckedExceptions++;
0908: checkedExceptionVector = new int[nCheckedExceptions];
0909: checkedExceptionVector[0] = 0;
0910: currCheckedException = 1;
0911: }
0912: boolean emittedNativeHeader = false;
0913: //
0914: // Look to see whether we can compact this
0915: //
0916: for (int i = 0; i < nmethod; i++) {
0917: CVMMethodInfo meth = m[i];
0918: int access = meth.CVMflags();
0919: if (!emittedNativeHeader
0920: && ((access & CVM_METHOD_ACC_NATIVE) != 0)) {
0921: String subdir = isClassCNI(c.ci.className) ? "cni/"
0922: : "jni/";
0923: headerOut.println("#include \"generated/" + subdir
0924: + Util.convertToClassName(c.ci.className)
0925: + ".h\"");
0926: emittedNativeHeader = true;
0927: }
0928: boolean synchro = (access & CVM_METHOD_ACC_SYNCHRONIZED) != 0;
0929: boolean isNative = (access & CVM_METHOD_ACC_NATIVE) != 0;
0930: boolean isAbstract = (access & CVM_METHOD_ACC_ABSTRACT) != 0;
0931:
0932: String invoker = isAbstract ? "CVM_INVOKE_ABSTRACT_METHOD"
0933: : isNative ? (isClassCNI(c.ci.className) ? "CVM_INVOKE_CNI_METHOD"
0934: : (synchro ? "CVM_INVOKE_JNI_SYNC_METHOD"
0935: : "CVM_INVOKE_JNI_METHOD"))
0936: : (synchro ? "CVM_INVOKE_JAVA_SYNC_METHOD"
0937: : "CVM_INVOKE_JAVA_METHOD");
0938: int argssize = meth.method.argsSize;
0939:
0940: CVMMethodStats.Entry entry = methStats.lookup(argssize,
0941: invoker, access);
0942: //
0943: // Cannot encode in one byte, therefore cannot compress
0944: //
0945: if (entry.getIdx() >= 256) {
0946: c.setCompressible(false);
0947: }
0948: meth.statsEntry = entry;
0949: }
0950:
0951: //
0952: // Update the compressibility of class c
0953: //
0954: isCompressible = isCompressible && c.isCompressible();
0955:
0956: //
0957: // isCompressible cannot be true if the mb's are to be read-only
0958: //
0959: isCompressible = isCompressible && writableMethods;
0960:
0961: // if any method has a JSR, then its method block, and thus
0962: // all of them, must be writable, so we can replace its code, bundled
0963: // with its JavaMethodDescriptor.
0964: declareMethodArray(c, writableMethods, isCompressible);
0965: String cbDeclaration;
0966:
0967: if (isCompressible) {
0968: cbDeclaration = "CVM_INIT_METHODARRAY_CB_WITH_COMPRESSED_MBS";
0969: } else {
0970: cbDeclaration = "CVM_INIT_METHODARRAY_CB_WITH_UNCOMPRESSED_MBS";
0971: }
0972:
0973: classOut.print(" = {\n\t" + cbDeclaration + "(&"
0974: + classBlockName + "),\n\t{\n");
0975:
0976: for (int i = 0; i < nmethod; i++) {
0977: CVMMethodInfo meth = m[i];
0978: if (meth.method.hasCheckinits) {
0979: nMethodsWithCheckinitInvokes++;
0980: }
0981: int mbIndex = i % cbRepeat;
0982: int typeid = meth.sigType.entryNo;
0983: int nameid = CVMMemberNameEntry
0984: .lookupEnter(getUTF(meth.method.name));
0985: String nameAndType = "RAW_TYPEID(0x"
0986: + Integer.toHexString(nameid) + ", 0x"
0987: + Integer.toHexString(typeid) + ")";
0988: int access = meth.CVMflags();
0989:
0990: boolean synchro = (access & CVM_METHOD_ACC_SYNCHRONIZED) != 0;
0991: boolean isNative = (access & CVM_METHOD_ACC_NATIVE) != 0;
0992: boolean isAbstract = (access & CVM_METHOD_ACC_ABSTRACT) != 0;
0993:
0994: String invoker = meth.statsEntry.getInvoker();
0995:
0996: /* By default let interpreter do invocation in all
0997: except native methods. Compilation might change
0998: invoker function */
0999: String jitInvoker = isNative ? (isClassCNI(c.ci.className) ? "CVMCCMinvokeCNIMethod"
1000: : "CVMCCMinvokeJNIMethod")
1001: : "CVMCCMletInterpreterDoInvoke";
1002:
1003: //
1004: // note the offset in the exception array,
1005: // and add to that array as necessary.
1006: int exceptions;
1007: if ((meth.method.exceptionsThrown != null)
1008: && (meth.method.exceptionsThrown.length != 0)) {
1009: ClassConstant thrown[] = meth.method.exceptionsThrown;
1010: int net = thrown.length;
1011: exceptions = currCheckedException;
1012: checkedExceptionVector[currCheckedException++] = net;
1013: for (int j = 0; j < net; j++) {
1014: checkedExceptionVector[currCheckedException++] = thrown[j].index;
1015: }
1016: } else {
1017: // Note we have changed this from ((unsigned short)
1018: // -1) to 0 to be consistent with the documentation in
1019: // classes.h. A checkedExceptionsOffset of 0 indicates
1020: // no checked exceptions for the method. Also see the
1021: // allocation of the checkedExceptionVector above.
1022: exceptions = 0;
1023: }
1024: int argssize = meth.method.argsSize;
1025: int tableIndex = meth.methodOffset();
1026:
1027: /*
1028: * method offsets are always mod 'cbRepeat' and we have to
1029: * emit a cb entry before each block of 'cbRepeat'
1030: * methods.
1031: */
1032: if ((mbIndex == 0) && (i != 0) && !isCompressible
1033: && !writableMethods) {
1034: // Output the repeated cb only if we are emitting read-only
1035: // method blocks.
1036: classOut.print("\t},\n");
1037: classOut.print("\t&" + classBlockName + ",\n\t{\n");
1038: }
1039:
1040: if (isCompressible) {
1041: // The C compiler checks that the values here are
1042: // really compressed within the proper sizes. We get
1043: // warnings if we exceed the maximum width for a given
1044: // data field.
1045: //
1046: // entryIdx encapsulates argssize, invoker, and access flags
1047: int entryIdx = meth.statsEntry.getIdx();
1048: classOut
1049: .print(" CVM_INIT_METHODBLOCK_IMMUTABLE_COMPRESSED("
1050: + cbname_comma
1051: + nameAndType
1052: + ","
1053: + tableIndex
1054: + ","
1055: + entryIdx
1056: + ","
1057: + mbIndex + "," + exceptions + ",");
1058: } else if (writableMethods) {
1059: classOut.print(" CVM_INIT_METHODBLOCK_IMMUTABLE("
1060: + cbname_comma + nameAndType + "," + tableIndex
1061: + "," + argssize + "," + invoker + "," + access
1062: + "," + mbIndex + "," + exceptions + ",");
1063: } else {
1064: classOut.print(" CVM_INIT_METHODBLOCK(" + cbname_comma
1065: + jitInvoker + "," + nameAndType + ","
1066: + tableIndex + "," + argssize + "," + invoker
1067: + "," + access + "," + mbIndex + ","
1068: + exceptions + ",");
1069: }
1070:
1071: if (isAbstract) {
1072: classOut.print("(CVMJavaMethodDescriptor*)" + i
1073: + "),\n");
1074: } else if (isNative) {
1075: if (isClassCNI(c.ci.className)) {
1076: String jniName = meth.method.getNativeName(true);
1077: String eniName = "CNI" + jniName.substring(5);
1078: classOut.print("(CVMJavaMethodDescriptor*)&"
1079: + eniName + "),\n");
1080: } else {
1081: classOut.print("(CVMJavaMethodDescriptor*)&"
1082: + meth.method.getNativeName(true) + "),\n");
1083: }
1084: } else {
1085: classOut.print("&(" + meth.getNativeName()
1086: + ".u.jmd)),\n");
1087: }
1088:
1089: }
1090: classOut.print("}};\n");
1091: this .nmethods += nmethod;
1092: if (writableMethods) {
1093: nClassesWithWritableMethodBlocks += 1;
1094: nWritableMethodBlocks += nmethod;
1095: }
1096: //
1097: // now, if there are any exception-catch clauses
1098: // that need to be represented, print out the table.
1099: if (nCheckedExceptions != 0) {
1100: classOut.println("STATIC const CVMUint16 "
1101: + this ExceptionName + "[] = {");
1102: int j = 0;
1103: for (int i = 0; i < nCheckedExceptions; i++) {
1104: if (j >= 8) {
1105: classOut.print("\n ");
1106: j = 0;
1107: } else {
1108: j += 1;
1109: }
1110: classOut.print(checkedExceptionVector[i] + ", ");
1111: }
1112: classOut.println("\n};");
1113: }
1114: }
1115:
1116: /*
1117: * Write out the InnerClassInfo structure. This structure will contain
1118: * information about all referenced inner classes.
1119: */
1120: private void writeInnerClasses(CVMClass c) {
1121: //Write information about each inner class contained in this class.
1122: int innerClassCount = c.ci.innerClassAttr.getInnerClassCount();
1123: InnerClassAttribute ica = c.ci.innerClassAttr;
1124: classOut.println(" " + innerClassCount + ", {");
1125: for (int j = 0; j < innerClassCount; j++) {
1126: // write out the indexes and access flags of this inner class.
1127: classOut.print(" {");
1128: classOut.print(ica.getInnerInfoIndex(j));
1129: classOut.write(',');
1130: classOut.print(ica.getOuterInfoIndex(j));
1131: classOut.write(',');
1132: /* innerNameIndex not supported because utf8 cp entries
1133: * are not kept around.
1134: classOut.print(ica.getInnerNameIndex(j));
1135: */
1136: classOut.print('0');
1137: classOut.write(',');
1138: classOut.print(ica.getAccessFlags(j));
1139: classOut.print("},\n");
1140: }
1141: classOut.println(" }");
1142: ninnerclasses += innerClassCount;
1143: }
1144:
1145: void mungeAllIDsAndWriteExternals(ClassClass classes[]) {
1146: }
1147:
1148: private static int CVMDataAccessFlags(int access) {
1149: int a = 0;
1150: if ((access & ACC_PUBLIC) != 0)
1151: a |= CVM_FIELD_ACC_PUBLIC;
1152: if ((access & ACC_PRIVATE) != 0)
1153: a |= CVM_FIELD_ACC_PRIVATE;
1154: if ((access & ACC_PROTECTED) != 0)
1155: a |= CVM_FIELD_ACC_PROTECTED;
1156: if ((access & ACC_STATIC) != 0)
1157: a |= CVM_FIELD_ACC_STATIC;
1158: if ((access & ACC_FINAL) != 0)
1159: a |= CVM_FIELD_ACC_FINAL;
1160: if ((access & ACC_VOLATILE) != 0)
1161: a |= CVM_FIELD_ACC_VOLATILE;
1162: if ((access & ACC_TRANSIENT) != 0)
1163: a |= CVM_FIELD_ACC_TRANSIENT;
1164: return a;
1165: }
1166:
1167: private void declareFieldArray(CVMClass c) {
1168: // Note: Should deal with > 255 fields.
1169: // Today is not that day. Just do the simple case.
1170: FieldInfo m[] = c.ci.fields;
1171: int nfields = m.length;
1172: String this TableName = c.getNativeName() + "_fields";
1173: String fieldArrayFlavor = "struct CVMFieldArray" + nfields;
1174: if (!fieldArraySizes.get(nfields)) {
1175: // need to declare a structure containing a classblock pointer
1176: // plus "nfields" CVMFieldBlock structures
1177: int i;
1178: headerOut.print(fieldArrayFlavor + " {");
1179: if (nfields > cbRepeat)
1180: headerOut.println();
1181: int numFieldArrays = (nfields - 1) / cbRepeat + 1;
1182: for (i = 1; i <= numFieldArrays; i++) {
1183: int nfields2; // # fields in this field array
1184: if (i == numFieldArrays) {
1185: nfields2 = (nfields - 1) % cbRepeat + 1;
1186: } else {
1187: nfields2 = cbRepeat;
1188: }
1189: headerOut.print(" CVMClassBlock const *cb" + i + ";"
1190: + " CVMFieldBlock fb" + i + "[" + nfields2
1191: + "];");
1192: if (nfields > cbRepeat) {
1193: headerOut.println();
1194: }
1195: }
1196: headerOut.println(" };");
1197: fieldArraySizes.set(nfields);
1198: }
1199: declare("const " + fieldArrayFlavor + " " + this TableName,
1200: classOut);
1201: fieldTableName = "&" + this TableName;
1202: fieldTableSize = nfields;
1203: }
1204:
1205: void writeFields(CVMClass c) {
1206: // Note: Should deal with > 255 fields.
1207: // Today is not that day. Just do the simple case.
1208: FieldInfo m[] = c.ci.fields;
1209: if ((m == null) || (m.length == 0)) {
1210: fieldTableName = "0";
1211: fieldTableSize = 0;
1212: return;
1213: }
1214: int nfields = m.length;
1215: declareFieldArray(c);
1216: classOut.print(" = {\n");
1217: for (int i = 0; i < nfields; i++) {
1218: int fbIndex = i % cbRepeat;
1219: FieldInfo f = m[i];
1220: int typeid = CVMDataType.parseSignature(getUTF(f.type));
1221: int nameid = CVMMemberNameEntry.lookupEnter(getUTF(f.name));
1222: String nameAndType = "RAW_TYPEID(0x"
1223: + Integer.toHexString(nameid) + ", 0x"
1224: + Integer.toHexString(typeid) + ")";
1225: //System.out.println( nameAndType+" => "+Integer.toHexString(typeid) );
1226: int access = CVMDataAccessFlags(f.access);
1227: int offset = f.instanceOffset;
1228: /* field offsets are always mod cbRepeat and we have to emit a cb
1229: * entry before each block of cbRepeat fields. */
1230: if (fbIndex == 0) {
1231: if (i != 0) {
1232: classOut.print("\t},\n");
1233: }
1234: classOut.print("\t&" + classBlockName + ",\n\t{\n");
1235: }
1236: // static members use simple byte offset
1237: // instance members include size of header info
1238: if (f.isStaticMember()) {
1239: classOut.print(" CVM_INIT_FIELDBLOCK(" + nameAndType
1240: + "," + access + "," + fbIndex
1241: + ", CVM_STATIC_OFFSET(" + offset + ")),\n");
1242: } else {
1243: classOut.print(" CVM_INIT_FIELDBLOCK(" + nameAndType
1244: + "," + access + "," + fbIndex
1245: + ", CVM_FIELD_OFFSET(" + offset + ")),\n");
1246: }
1247: }
1248: classOut.println("}};");
1249: this .nfields += nfields;
1250:
1251: }
1252:
1253: private String methodBlockAddress(MethodInfo mi) {
1254: CVMMethodInfo em = (CVMMethodInfo) (mi.vmMethodInfo);
1255: CVMClass ec = (CVMClass) (mi.parent.vmClass);
1256: int n = mi.index;
1257: /*
1258: * Moved globals to CVMROMGlobals. For classes without
1259: * writeable methods, there is (still) a constant global
1260: * variable <class>_methods - nothing has changed. For
1261: * classes with writeable methods, the <class>_methods
1262: * variable lives in the CVMROMGlobals structure. The ability
1263: * to determine whether a class has writable methods has been
1264: * added to CVMClass.
1265: */
1266: if (mutableMBs || ec.hasWritableMethods())
1267: return "&CVMROMGlobals." + ec.getNativeName()
1268: + "_methods.mb" + (n / cbRepeat + 1) + "[" + n
1269: % cbRepeat + "]"; // had better not be an interface.
1270: // had better not be an interface.
1271: return "&" + ec.getNativeName() + "_methods.mb"
1272: + (n / cbRepeat + 1) + "[" + n % cbRepeat + "]";
1273: }
1274:
1275: private static String fieldBlockAddress(FieldInfo f) {
1276: // pretty disgusting.
1277: // if this is frequent enough, find a better way!
1278: ClassInfo c = f.parent;
1279: FieldInfo cf[] = c.fields;
1280: int n = f.index;
1281: //for ( n = 0; cf[n] != f; n++ ) // TRY THIS.
1282: // ;
1283: // assume we found it.
1284: String parentName = ((CVMClass) (c.vmClass)).getNativeName();
1285: return "&" + parentName + "_fields.fb" + (n / cbRepeat + 1)
1286: + "[" + n % cbRepeat + "]";
1287: }
1288:
1289: private static final int unresolvedCVMConstantMap[] = {
1290: CVM_CONSTANT_Invalid, CVM_CONSTANT_Utf8,
1291: CVM_CONSTANT_Invalid,
1292: CVM_CONSTANT_Integer | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1293: CVM_CONSTANT_Float | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1294: CVM_CONSTANT_Long | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1295: CVM_CONSTANT_Double | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1296: CVM_CONSTANT_ClassTypeID,
1297: CVM_CONSTANT_StringObj | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1298: CVM_CONSTANT_Fieldref, CVM_CONSTANT_Methodref,
1299: CVM_CONSTANT_InterfaceMethodref, CVM_CONSTANT_NameAndType };
1300:
1301: private static final int resolvedCVMConstantMap[] = {
1302: CVM_CONSTANT_Invalid,
1303: CVM_CONSTANT_Utf8,
1304: CVM_CONSTANT_Invalid,
1305: CVM_CONSTANT_Integer | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1306: CVM_CONSTANT_Float | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1307: CVM_CONSTANT_Long | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1308: CVM_CONSTANT_Double | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1309: CVM_CONSTANT_ClassBlock | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1310: CVM_CONSTANT_StringObj | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1311: CVM_CONSTANT_FieldBlock | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1312: CVM_CONSTANT_MethodBlock | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1313: CVM_CONSTANT_MethodBlock | CVM_CONSTANT_POOL_ENTRY_RESOLVED,
1314: CVM_CONSTANT_NameAndType };
1315:
1316: private static int CVMconstantTag(ConstantObject c) {
1317: int t;
1318: if (c.isResolved()) {
1319: t = resolvedCVMConstantMap[c.tag];
1320: if (t == CVM_CONSTANT_NameAndType) {
1321: String sig = ((NameAndTypeConstant) c).type.string;
1322: t = (sig.charAt(0) == SIGC_METHOD) ? CVM_CONSTANT_MethodTypeID
1323: : CVM_CONSTANT_FieldTypeID;
1324: }
1325: } else {
1326: t = unresolvedCVMConstantMap[c.tag];
1327: if (t == CVM_CONSTANT_NameAndType) {
1328: String sig = ((NameAndTypeConstant) c).type.string;
1329: t = (sig.charAt(0) == SIGC_METHOD) ? CVM_CONSTANT_MethodTypeID
1330: : CVM_CONSTANT_FieldTypeID;
1331: }
1332: }
1333: return t;
1334: }
1335:
1336: // return address of this type table.
1337: private String writeTypeTable(ConstantObject constants[],
1338: String name) {
1339: int clen = constants.length;
1340: String ttname = name + "_tt";
1341: auxOut.print("CVMUint8 " + ttname + "[] = { 0,");
1342: int j = 99;
1343: for (int i = 1; i < clen; i += constants[i].nSlots) {
1344: if (j >= 10) {
1345: auxOut.print("\n ");
1346: j = 1;
1347: } else {
1348: j += 1;
1349: }
1350: auxOut.print(CVMconstantTag(constants[i]) + ",");
1351: if (constants[i].nSlots == 2) {
1352: auxOut.print(" 0,"); // 2nd word of 2-word constant
1353: j += 1;
1354: }
1355: }
1356: auxOut.println("\n};");
1357: headerOut.println("extern CVMUint8 " + ttname + "[" + clen
1358: + "];");
1359: return "&" + ttname;
1360: }
1361:
1362: // return address of this array Info.
1363: private String writeArrayInfo(ArrayClassInfo info, String name) {
1364: String arrayInfoName = name + "_ai";
1365: classOut.println("STATIC const union {");
1366: classOut.println("\tCVMArrayInfo ai;");
1367: classOut.println("\tCVMConstantPool constantpool;");
1368: classOut.println("} " + arrayInfoName + " = {{");
1369: classOut
1370: .println("\t" + info.depth + ", " + info.baseType + ",");
1371: classOut.println("\t(CVMClassBlock*)&"
1372: + cbName((CVMClass) info.baseClass.find().vmClass)
1373: + ",");
1374: classOut.println("\t(CVMClassBlock*)&"
1375: + cbName((CVMClass) info.subarrayClass.find().vmClass));
1376: classOut.println("}};");
1377: return "&" + arrayInfoName + ".ai";
1378: }
1379:
1380: // return address of this constant pool.
1381: private String writeConstants(ConstantPool cp, String name,
1382: boolean export) {
1383: ConstantObject constants[] = cp.getConstants();
1384: int clen = constants.length;
1385: if ((clen == 0) || (clen == 1)) {
1386: return "0";
1387: }
1388:
1389: // Check if we need a type table. When we write the class, we
1390: // check for unquickened bytecodes. If we find any, we mark
1391: // the constant pool as needing a type table. The check for
1392: // unresolved entries should be redundant, because unreferenced
1393: // entries should have been removed, and referenced entries
1394: // should have an unquickened reference.
1395:
1396: boolean doTypeTable = cp.needsTypeTable()
1397: || ClassClass.isPartiallyResolved(cp);
1398:
1399: if (doTypeTable) {
1400: System.err.println("NEEDS TYPE TABLE");
1401: }
1402: if (doTypeTable && !classLoading) {
1403: // in future, do something more useful here.
1404: System.err.println(Localizer
1405: .getString("cwriter.no_class_loading"));
1406: // write the type table out anyway, in case
1407: // there is someone to look at it at runtime!
1408: }
1409: String typeTableName;
1410: if (doTypeTable) {
1411: typeTableName = "CP_ADDR("
1412: + writeTypeTable(constants, name) + ")";
1413: } else {
1414: typeTableName = "CP_ADDR(0)";
1415: }
1416: String constantPoolName = name + "_cp";
1417: classOut.print(doTypeTable ? "" : "const ");
1418: classOut.println("CVMAddr " + constantPoolName + "[" + (clen)
1419: + "] = {");
1420: classOut.println(" (CVMAddr)" + typeTableName + ",");
1421:
1422: if (export) {
1423: // Export in the global header for multiple components of
1424: // romjava files to find
1425: headerOut.print("extern ");
1426: headerOut.print(doTypeTable ? "" : "const ");
1427: headerOut.println("CVMAddr " + constantPoolName + "["
1428: + (clen) + "];");
1429: }
1430: for (int i = 1; i < clen; i += constants[i].nSlots) {
1431: classOut.print(" ");
1432: writeConstant(constants[i], classOut, "CP_");
1433: classOut.println(",");
1434: }
1435: classOut.println("};");
1436: nconstants += clen;
1437: return constantPoolName;
1438: }
1439:
1440: private void declareClassblock(CVMClass c, int innerClassCount) {
1441: String myName = c.getNativeName();
1442: String classblockFlavor = "struct CVMClassBlock"
1443: + innerClassCount;
1444: if (!classblockSizes.get(innerClassCount)) {
1445: // need to declare a classblock-like struct with innerClassCount
1446: // elements in its CVMInnerClassInfo array
1447: if (innerClassCount < 1) {
1448: headerOut.println(classblockFlavor
1449: + " { CVMClassBlock classclass; };");
1450: } else {
1451: headerOut
1452: .println(classblockFlavor
1453: + " { CVMClassBlock classclass; CVMUint32 innerClassesCount; CVMInnerClassInfo innerClasses[ "
1454: + (innerClassCount) + "]; };");
1455: }
1456: classblockSizes.set(innerClassCount);
1457: }
1458: declare("const " + classblockFlavor + " " + myName
1459: + "_Classblock", classOut);
1460: }
1461:
1462: // helper for classBitMap
1463: private static int GCbits(FieldInfo slottable[], int first, int last) {
1464: int mapval = 0;
1465: for (int i = first; i < last; i++) {
1466: switch (slottable[i].type.string.charAt(0)) {
1467: case 'L':
1468: case '[':
1469: // this is a reference.
1470: mapval |= 1 << (i - first);
1471: }
1472: }
1473: return mapval;
1474: }
1475:
1476: //
1477: // compute the GC bit map for a class.
1478: // if it is big, then write it out as well. In any case,
1479: // return a string to use to initialize the gcMap field in the CVMClassBlock
1480: //
1481: private String classBitMap(CVMClass c) {
1482: if (c.isArrayClass()) {
1483: // either an array of primitive or an array of objects.
1484: ArrayClassInfo ac = (ArrayClassInfo) (c.ci);
1485: if ((ac.depth == 1) && (ac.baseType != T_CLASS))
1486: return "0"; // contains no references
1487: else
1488: return "1"; // contains nothing but references.
1489: }
1490: ClassInfo ci = c.ci;
1491: FieldInfo ft[] = ci.slottable;
1492: if ((ft == null) || (ft.length == 0))
1493: return "0";
1494: int nslots;
1495: if ((nslots = ft.length) <= 30) {
1496: // easy case. Small object. Map can be represented in a word.
1497: return "0x"
1498: + Integer.toHexString(GCbits(ft, 0, nslots) << 2);
1499: } else {
1500: // hard case.
1501: String myName = c.getNativeName() + "_gcBits";
1502: int nWords = (nslots + 31) / 32;
1503: classOut
1504: .print("STATIC const struct { CVMUint16 maplen; CVMUint32 map["
1505: + nWords + "]; } ");
1506: classOut.print(myName);
1507: classOut.print(" = { ");
1508: classOut.print(nWords);
1509: classOut.print(",\n {");
1510: for (int i = 0; i < nslots; i += 32) {
1511: classOut.print("0x"
1512: + Integer.toHexString(GCbits(ft, i, Math.min(
1513: i + 32, nslots))));
1514: classOut.print(", ");
1515: }
1516: classOut.println("} };");
1517: return "(CVMAddr)(((char*)&" + myName
1518: + ")+ CVM_GCMAP_LONGGCMAP_FLAG)";
1519: }
1520: }
1521:
1522: private void writeClassinfo(int classno, CVMClass c, int clinitIdx,
1523: int nStaticWords) {
1524:
1525: if (c.hasStaticInitializer) {
1526: nClinits++;
1527: }
1528: String super Name = (c.ci.super ClassInfo == null) ? ("0")
1529: : ("&" + cbName((CVMClass) (c.ci.super ClassInfo.vmClass)));
1530: String myStaticName = (c.nStaticWords == 0) ? ("0")
1531: : ("(CVMJavaVal32*)STATIC_STORE_ADDRESS(0)");
1532: int innerClassCount = (c.ci.innerClassAttr == null) ? (0)
1533: : (c.ci.innerClassAttr.getInnerClassCount());
1534: String runtimeFlags = (c.hasStaticInitializer || c.nStaticWords > 0) ? ("CVM_ROMCLASS_WCI_INIT")
1535: : ("CVM_ROMCLASS_INIT");
1536: MethodInfo vtbl[] = c.ci.methodtable;
1537: String methodTableName;
1538: int methodTableCount;
1539: String gcBits;
1540:
1541: /*
1542: * Note: If this is a primitive class, the
1543: * typecode is stored in the methodTableCount field.
1544: * Since these things cannot be instantiated, they need
1545: * no virtual methods.
1546: */
1547: if (c.isPrimitiveClass()) {
1548: methodTableCount = c.typecode();
1549: methodTableName = "0";
1550: } else {
1551: // vtbl == null may occur for array classes!
1552: methodTableCount = (vtbl == null) ? 0 : vtbl.length;
1553: if (methodTableCount > 0) {
1554: methodTableName = c.getNativeName() + "_mt";
1555: } else if (c.isArrayClass()) {
1556: methodTableName = "java_lang_Object_mt";
1557: } else { /* must be an interface */
1558: methodTableName = "0";
1559: }
1560: }
1561: // classBitMap may do output, so it needs
1562: // to be called before declareClassblock!
1563: gcBits = classBitMap(c);
1564:
1565: declareClassblock(c, innerClassCount);
1566:
1567: int classid = c.classid();
1568: //System.out.println( c.ci.className+" => "+Integer.toHexString(classid) );
1569:
1570: classOut.println(" = {\n CVM_INIT_CLASSBLOCK( " + gcBits
1571: + ", " + "RAW_TYPEID(0, 0x"
1572: + Integer.toHexString(classid) + "), \""
1573: + c.ci.className + "\",");
1574: classOut.println(" " + super Name + ",");
1575: classOut.println(" " + constantPoolName + ", ");
1576: classOut.println(" " + interfaceTableName + ",");
1577: classOut.println(" " + methodArrayName + ",");
1578: classOut.println(" " + fieldTableName + ", " + myStaticName
1579: + ",");
1580: classOut.println(" " + constantPoolSize + ", "
1581: + methodTableSize + ", " + fieldTableSize + ", "
1582: + methodTableCount + ", " + c.CVMflags() + ", "
1583: + runtimeFlags + ", " + nStaticWords + " + "
1584: + clinitIdx + ", OBJ_SIZE(" + c.instanceSize() + "), ");
1585: classOut.println(" (CVMClassICell*)(&CVM_classICell["
1586: + classno + "]), ");
1587: /* The slots for clinitEE is appended to 'staticStoreName'. */
1588: /*
1589: * Moved global variables to CVMROMGlobals
1590: */
1591: classOut.println(" (CVMExecEnv**)&CVMROMGlobals."
1592: + staticStoreName + "[" + nStaticWords + " + "
1593: + clinitIdx + "],");
1594: classOut.println(" " + checkedExceptionName + ", ");
1595: if (classDebug && c.ci.sourceFileAttr != null) {
1596: classOut.println(" \"" + c.ci.sourceFileAttr.sourceName
1597: + "\", ");
1598: } else {
1599: classOut.println(" 0, ");
1600: }
1601:
1602: /* write out the methodTablePtr. */
1603: classOut.println(" " + methodTableName + ",");
1604:
1605: /* write out the ClassLoader and ProtectionDomain */
1606: int id = c.ci.loader.getID();
1607: if (id != 0) {
1608: int clIDOff = 1; // first cl ID (boot == 0)
1609: int off = clRefOff + (id - clIDOff) * 2;
1610: classOut.println(" (CVMClassLoaderICell *)"
1611: + "STATIC_STORE_ADDRESS(" + off + "), "
1612: + "(CVMObjectICell *)" + "STATIC_STORE_ADDRESS("
1613: + (off + 1) + "),");
1614: } else {
1615: classOut.println(" 0, 0,");
1616: }
1617:
1618: /* write out the InnerClassesInfo */
1619: if (c.ci.innerClassAttr != null) {
1620: classOut.println(" &" + c.getNativeName()
1621: + "_Classblock.innerClassesCount),");
1622: writeInnerClasses(c);
1623: } else {
1624: classOut.println(" 0)");
1625: }
1626:
1627: classOut.println("};");
1628: }
1629:
1630: void writeMethodTable(CVMClass c) {
1631: MethodInfo vtbl[] = c.ci.methodtable;
1632: int vtblSize;
1633:
1634: /*
1635: * Note: If this is a primitive class, the
1636: * typecode is stored in the methodTableCount field.
1637: * Since these things cannot be instantiated, they need
1638: * no virtual methods.
1639: */
1640: if (c.isPrimitiveClass()) {
1641: return;
1642: } else {
1643: // vtbl == null may occur for array classes!
1644: vtblSize = (vtbl == null) ? 0 : vtbl.length;
1645: }
1646:
1647: if (vtblSize > 0) {
1648: /* write out the methodtable. */
1649: String methodTableName = c.getNativeName() + "_mt" + "["
1650: + vtblSize + "]";
1651: if (c.ci.super Class == null) { // is it java/lang/Object
1652: // java/lang/Object needs an extern methodTable declaration.
1653: /* Added another const (for the pointer, which is also
1654: * const here, not just the data)
1655: */
1656: declare("const CVMMethodBlock* const "
1657: + methodTableName, classOut);
1658: } else {
1659: /*
1660: * Added another const (for the pointer, which is also const here, not just the data)
1661: */
1662: classOut.print("STATIC const CVMMethodBlock* const "
1663: + methodTableName);
1664: }
1665: classOut.println(" = {");
1666: for (int i = 0; i < vtblSize; i++) {
1667: classOut.println(" (CVMMethodBlock*)"
1668: + methodBlockAddress(vtbl[i]) + ",");
1669: }
1670: classOut.println("};\n");
1671: }
1672: }
1673:
1674: /* (These two belong directly in the CCodeWriter) */
1675:
1676: private void writeIntegerValue(int v, CCodeWriter out) {
1677: // little things make gcc happy.
1678: if (v == 0x80000000)
1679: out.print("(CVMInt32)0x80000000");
1680: else
1681: out.print(v);
1682: }
1683:
1684: private void writeLongValue(String tag, int highval, int lowval,
1685: CCodeWriter out) {
1686: out.print(tag);
1687: out.write('(');
1688: writeIntegerValue(highval, out);
1689: out.print(", ");
1690: writeIntegerValue(lowval, out);
1691: out.write(')');
1692: }
1693:
1694: /*
1695: * Added prefix argument to differ between writing entries to the
1696: * constant pool (where prefix="CP_") and the rest (where prefix
1697: * is empty). Additionally we use the INTEGER/LONG/... macros now
1698: * everywhere in this function to indicate, what type we are writing
1699: * (may be hard to spot otherwise).
1700: */
1701: private void writeConstant(ConstantObject value, CCodeWriter out,
1702: String prefix) {
1703: switch (value.tag) {
1704: case Const.CONSTANT_INTEGER:
1705: case Const.CONSTANT_FLOAT:
1706: /*
1707: * add INTEGER macro like the one for LONG and DOUBLE
1708: * to have the possibility to change the representation
1709: * platform dependent
1710: */
1711: /*
1712: * Add prefix to macro to get correct version.
1713: */
1714: out.print(prefix + "INTEGER(");
1715: writeIntegerValue(((SingleValueConstant) value).value, out);
1716: out.print(")");
1717: break;
1718: case Const.CONSTANT_UTF8:
1719: out.print("(CVMInt32)");
1720: out.write('"');
1721: out.print(Util
1722: .unicodeToUTF(((UnicodeConstant) value).string));
1723: out.write('"');
1724: // also, not sharing here at all.
1725: break;
1726: case Const.CONSTANT_STRING:
1727: /*
1728: * Moved global variables to CVMROMGlobals
1729: */
1730: /* CVM_BIGTYPEID: RS, 10/08/02:
1731: * Use ADDR() macro to print out address.
1732: */
1733: out.print(prefix + "ADDR(&CVMROMGlobals." + stringArrayName
1734: + "[");
1735: if (((StringConstant) value).unicodeIndex == -1) {
1736: // Uninitialized, very bad
1737: throw new InternalError(
1738: "Uninitialized string constant " + value);
1739: } else {
1740: out.print(((StringConstant) value).unicodeIndex);
1741: }
1742:
1743: out.print("])");
1744: break;
1745: case Const.CONSTANT_LONG: {
1746: DoubleValueConstant dval = (DoubleValueConstant) value;
1747: /*
1748: * Add prefix to macro to get correct version.
1749: */
1750: writeLongValue("LONG", dval.highVal, dval.lowVal, out);
1751: }
1752: break;
1753: case Const.CONSTANT_DOUBLE: {
1754: DoubleValueConstant dval = (DoubleValueConstant) value;
1755: /*
1756: * Add prefix to macro to get correct version.
1757: */
1758: writeLongValue("DOUBLE", dval.highVal, dval.lowVal, out);
1759: }
1760: break;
1761: case Const.CONSTANT_CLASS:
1762: if (value.isResolved()) {
1763: /*
1764: * Use ADDR() macro to print out address.
1765: */
1766: out.print(prefix
1767: + "ADDR(&"
1768: + cbName((CVMClass) (((ClassConstant) value)
1769: .find().vmClass)) + ")");
1770: } else {
1771: int classid = CVMDataType
1772: .lookupClassname(getUTF(((ClassConstant) value).name));
1773: /*
1774: * Use TYPEID() macro to create typeid from type part.
1775: */
1776: out.print(prefix + "TYPEID(0, 0x"
1777: + Integer.toHexString(classid) + ")");
1778: }
1779: break;
1780: case Const.CONSTANT_METHOD:
1781: case Const.CONSTANT_INTERFACEMETHOD:
1782: if (value.isResolved()) {
1783: /*
1784: * Use ADDR() macro to print out address.
1785: */
1786: out.print(prefix + "ADDR(");
1787: out.print(methodBlockAddress(((MethodConstant) value)
1788: .find())
1789: + ")");
1790: } else {
1791: FMIrefConstant ref = (FMIrefConstant) value;
1792: /*
1793: * Use MEMBER_REF() macro to create entry for parts.
1794: * This is a pair of 16-bit indices into the cp.
1795: * They reference a Class constant and a NameAndType
1796: * constant.
1797: * It is not a typeId.
1798: */
1799: out
1800: .print(prefix
1801: + "MEMBER_REF(0x"
1802: + Integer.toHexString(ref.clas
1803: .getIndex())
1804: + ", 0x"
1805: + Integer.toHexString(ref.sig
1806: .getIndex()) + ")");
1807: }
1808: break;
1809: case Const.CONSTANT_FIELD:
1810: if (value.isResolved()) {
1811: FieldInfo ftarget = ((FieldConstant) value).find();
1812: ClassInfo ctarget = ftarget.parent;
1813: // ROMized code always use checkinit version of opcodes
1814: // to access fields including static fields.
1815: /*
1816: * Add prefix to macro to get correct version.
1817: */
1818: out.print(prefix + "ADDR(" + fieldBlockAddress(ftarget)
1819: + ")");
1820: } else {
1821: FMIrefConstant ref = (FMIrefConstant) value;
1822: /*
1823: * Use MEMBER_REF() macro to create entry for parts.
1824: * This is a pair of 16-bit indices into the cp.
1825: * They reference a Class constant and a NameAndType
1826: * constant.
1827: * It is not a typeId.
1828: */
1829: out
1830: .print(prefix
1831: + "MEMBER_REF(0x"
1832: + Integer.toHexString(ref.clas
1833: .getIndex())
1834: + ", 0x"
1835: + Integer.toHexString(ref.sig
1836: .getIndex()) + ")");
1837: }
1838: break;
1839: case CONSTANT_NAMEANDTYPE:
1840: NameAndTypeConstant ntcon = (NameAndTypeConstant) value;
1841: int nameid = CVMMemberNameEntry
1842: .lookupEnter(getUTF(ntcon.name));
1843: String sigString = getUTF(ntcon.type);
1844: int typeid = (sigString.charAt(0) == SIGC_METHOD) ? (CVMMethodType
1845: .parseSignature(sigString).entryNo)
1846: : (CVMDataType.parseSignature(sigString));
1847: /*
1848: * Use TYPEID() macro to create typeid from parts.
1849: */
1850: out.print("TYPEID(0x" + Integer.toHexString(nameid)
1851: + ", 0x" + Integer.toHexString(typeid) + ")");
1852: break;
1853: }
1854: }
1855:
1856: private int clRefOff;
1857:
1858: /*
1859: * Merge the static store for all classes into one area.
1860: * Sort static cells, refs first, and assign offsets.
1861: * Write the resulting master data glob and arrange for
1862: * it to be copied to writable at startup.
1863: */
1864: private int writeStaticStore(ClassClass cvec[]) {
1865: int nclass = cvec.length;
1866: int nStaticWords = 1; // 1 header word assumed
1867: int nRef = 0;
1868: /* The number of necessary slots for clinitEE + 1.
1869: * Index of a class that doesn't have <clinit> is always 0.
1870: * The 0th entry is reserved for it. */
1871: int maxClinitIdx = 1;
1872:
1873: int maxClIdx = 0;
1874:
1875: /*
1876: * Count all statics.
1877: * Count refs, and count number of words.
1878: */
1879: for (int cno = 0; cno < nclass; cno++) {
1880: CVMClass c = (CVMClass) (cvec[cno]);
1881: c.orderStatics();
1882: nRef += c.nStaticRef;
1883: nStaticWords += c.nStaticWords;
1884: /* Count the number of necessary slots for clinitEE. */
1885: if (c.hasStaticInitializer) {
1886: maxClinitIdx++;
1887: }
1888: }
1889:
1890: int ncl = components.ClassTable.getNumClassLoaders();
1891: nRef += ncl * 2;
1892: nStaticWords += ncl * 2;
1893:
1894: /*
1895: * Assign offsets and at the same time
1896: * record any initial values.
1897: * write it later.
1898: */
1899: int refOff = 1;
1900: int scalarOff = refOff + nRef;
1901:
1902: ConstantObject staticInitialValue[] = new ConstantObject[nStaticWords];
1903: short staticInitialSize[] = new short[nStaticWords];
1904:
1905: clRefOff = refOff;
1906: for (int i = 0; i < ncl; ++i) {
1907: staticInitialValue[refOff] = null;
1908: staticInitialSize[refOff] = 1;
1909: ++refOff;
1910: staticInitialValue[refOff] = null;
1911: staticInitialSize[refOff] = 1;
1912: ++refOff;
1913: }
1914:
1915: for (int cno = 0; cno < nclass; cno++) {
1916: CVMClass c = (CVMClass) (cvec[cno]);
1917: FieldInfo f[] = c.statics;
1918: if ((f == null) || (f.length == 0))
1919: continue; // this class has none
1920: int nFields = f.length;
1921: for (int i = 0; i < nFields; i++) {
1922: FieldInfo fld = f[i];
1923: short nslots = (short) (fld.nSlots);
1924: char toptype = fld.type.string.charAt(0);
1925: if ((toptype == 'L') || (toptype == '[')) {
1926: fld.instanceOffset = refOff;
1927: staticInitialValue[refOff] = fld.value;
1928: staticInitialSize[refOff] = 1;
1929: refOff += 1;
1930: } else {
1931: fld.instanceOffset = scalarOff;
1932: staticInitialValue[scalarOff] = fld.value;
1933: staticInitialSize[scalarOff] = nslots;
1934: scalarOff += nslots;
1935: }
1936: }
1937: }
1938:
1939: /*
1940: * Allocate writable space for the static store.
1941: * Start writing the static storage header.
1942: * Remember that the first word is the number of refs.
1943: * And many of those refs get initialized to zero.
1944: * A static final String constant gets initialized with a pointer.
1945: *
1946: * The buffer holds static field slots for the ROMized classes and
1947: * cliniEE (that includes runtime flags) slots for ROMized classes.
1948: * The slot allocation looks like this:
1949: *
1950: * CVM_StaticDataMaster[]
1951: * +---+---+-- --+---+-- --+---+---+---+-- --+---+
1952: * | 0 | 1 | ... | i | ... |n-1|n+0|n+1| ... |n+m|
1953: * +-^-+-^-+-- --+-^-+-- --+-^-+-^-+-^-+-- --+-^+
1954: * | | | | | | |
1955: * | | | | | | the last clinitEE slot for
1956: * | | | | | | ROMized class w/<clinit>
1957: * | | the last | | |
1958: * | | static ref | | the 1st clinitEE slot for
1959: * | | | | ROMized class w/<clinit>
1960: * | the 1st | |
1961: * | static ref | shared clinitEE slot
1962: * | | for ROMized classes w/o <clinit>
1963: * the number of |
1964: * static refs (== i) the end of static fields
1965: *
1966: * where:
1967: * i := the number of static reference slots
1968: * n := the number of static field slots (including the 0th slot)
1969: * m := the number of clinitEE slots
1970: */
1971: /*
1972: * Moved global variables to CVMROMGlobals
1973: */
1974: globalHeaderOut.println(" CVMAddr " + staticStoreName
1975: + "[CVM_STATIC_OFFSET(" + nStaticWords + " + "
1976: + maxClinitIdx + ")];");
1977: auxOut.println("const CVMUint32 " + numStaticStoreName + " = "
1978: + nStaticWords + " + " + maxClinitIdx + ";");
1979: auxOut.print("const CVMAddr " + masterStaticStoreName
1980: + "[] = {\n ");
1981: auxOut.print(nRef); // the initial count word.
1982: auxOut.print(",");
1983: //System.out.println(nRef + " reference statics, total words "+nStaticWords );
1984:
1985: short nslots = 1;
1986: int nConstPerLine = 1; // the initial count word.
1987: for (int i = 1; i < nStaticWords; i += nslots) {
1988: ConstantObject v = staticInitialValue[i];
1989: nslots = staticInitialSize[i];
1990: if (v == null) {
1991: /*
1992: * Use INTEGER() macro here for consistency.
1993: */
1994: auxOut.print("INTEGER(0)");
1995: if (nslots == 2)
1996: /*
1997: * Use INTEGER() macro here for consistency.
1998: */
1999: auxOut.print(", INTEGER(0)");
2000: } else {
2001: /*
2002: * Use normal macros (not the CP_-variants) for the constants.
2003: */
2004: writeConstant(v, auxOut, "");
2005: }
2006: auxOut.print(", ");
2007: nConstPerLine += nslots;
2008: if (nConstPerLine >= 8) {
2009: auxOut.print("\n ");
2010: nConstPerLine = 0;
2011: }
2012: }
2013:
2014: /* Append slots for clinitEE after static fields */
2015: auxOut.print("\n");
2016: auxOut.print(" /* clinitEEs */\n");
2017: auxOut.print(" CVM_CLINITEE_CLASS_INIT_FLAG");
2018: for (int i = 1; i < maxClinitIdx; i++) {
2019: auxOut.print(", ");
2020: if (i % 8 == 0) {
2021: auxOut.print("\n ");
2022: }
2023: /*
2024: * Use INTEGER() macro here for consistency.
2025: */
2026: auxOut.print("INTEGER(0)");
2027: }
2028: auxOut.println("\n};");
2029: /*
2030: * Moved globals to CVMROMGlobals.
2031: */
2032: initInfo.addInfo("&" + masterStaticStoreName, "CVMROMGlobals."
2033: + staticStoreName, "(" + nStaticWords + " + "
2034: + maxClinitIdx + ")" + "*sizeof(CVMAddr)");
2035:
2036: return nStaticWords;
2037: }
2038:
2039: /*
2040: * typedef struct {
2041: * char *hash; * the string for this entry *
2042: * unsigned long info; * high bit set if malloc'ed
2043: * * low 31 bits are the low 31 bits of hash *
2044: * #define MALLOCED_FLAG (1u << 31)
2045: * #define HASHBIT_MASK (MALLOCED_FLAG - 1)
2046: * } StrIDhashSlot;
2047: *
2048: * typedef struct StrIDhash {
2049: * int size; * number of entries *
2050: * hash_fn hash; * hash function for this table *
2051: * struct StrIDhash *next; * next bucket *
2052: * short used; * number of full entries *
2053: * short baseid; * ID for item in slot[0] *
2054: * void **params; * param table, if needed *
2055: * StrIDhashSlot slot[1]; * expanded to be number of slots *
2056: * } StrIDhash;
2057: */
2058:
2059: private String idTypeDecl[] = { "extern void default_hash();",
2060: "typedef struct {", " const char *hash;",
2061: " unsigned long info;", "} StrIDhashSlot;",
2062: "#define STR_ID_HASH(n) struct { \\", " int size; \\",
2063: " void (*hash)(); \\", " void *next; \\",
2064: " short used; \\", " short baseid; \\",
2065: " HString **params; \\",
2066: " StrIDhashSlot slot[ n ]; \\", "} " };
2067:
2068: /*
2069: * These are macros to encapsulate some of the messiness
2070: * of data definitions. They are, perhaps, compiler-specific.
2071: */
2072: private static String stdHeader[] = {
2073: "#define IN_ROMJAVA 1",
2074: "#include \"javavm/include/defs.h\"",
2075: "#include \"javavm/include/objects.h\"",
2076: "#include \"javavm/include/classes.h\"",
2077: "#include \"javavm/include/interpreter.h\"",
2078: "#include \"javavm/include/jni_impl.h\"",
2079: "#include \"javavm/include/typeid.h\"",
2080: "#include \"javavm/include/typeid_impl.h\"",
2081: "#include \"javavm/include/string_impl.h\"",
2082: "#include \"javavm/include/preloader_impl.h\"",
2083: "#include \"javavm/include/porting/endianness.h\"",
2084: "#ifdef CVM_JIT",
2085: "#include \"javavm/include/porting/jit/ccm.h\"",
2086: "#endif",
2087: /*
2088: * add possibility to change the INTEGER
2089: * representation per platform
2090: *
2091: * Linux s390x:
2092: * Loading an integer/float constant failed on 64 bit because
2093: * the integer representation in the constant pool array
2094: * includes the bits for the 4 byte int/float
2095: * but is casted to a 8 byte value for 64 bit platforms (CVMAddr)
2096: * which meens that the memory representation is changed.
2097: * Therefore make sure the int/float representation looks like
2098: * byte 0 4 8
2099: * |- int -|- pad -|
2100: * on 64 bit platforms with big endian.
2101: */
2102: "/* CVM_BIGTYPEID: RS, 10/14/02:",
2103: " * Added macros to put different data types safely into their designated",
2104: " * structures. Unprefixed macro put the types into unions of the same size",
2105: " * as CVMAddr and macros prefixed with CP_ are used to put the specific",
2106: " * types into the constant pool.",
2107: " *",
2108: " * INTEGER(i) : Use this, if you want to write an integer",
2109: " * LONG(high, low) : Use this, if you want to write a long",
2110: " * value consisting of the given high and low parts.",
2111: " * DOUBLE(high, low) : Use this, if you want to write a double",
2112: " * value consisting of the given high and low parts.",
2113: " * ADDR(addr) : Use this, if you want to write an address.",
2114: " * TYPEID(namePart, typePart) : Use this, if you want to write a typeid consisting",
2115: " * of the given name and type parts.",
2116: " *",
2117: " * The following just return the typeids and their parts as their native types:",
2118: " *",
2119: " * RAW_TYPEID_NAME_PART(namePart) : Use this, if you want to write the name part of a typeid.",
2120: " * RAW_TYPEID_TYPE_PART(typePart) : Use this, if you want to write the type part of a typeid.",
2121: " * RAW_TYPEID(namePart, typePart) : Use this, if you want to write a typeid consisting",
2122: " * of the given name and type parts.",
2123: " */",
2124: "",
2125: "#define RAW_TYPEID_NAME_PART(namePart) \\",
2126: " ((CVMTypeIDNamePart) (namePart))",
2127: "",
2128: "#define RAW_TYPEID_TYPE_PART(typePart) \\",
2129: " ((CVMTypeIDTypePart) (typePart))",
2130: "",
2131: "#define RAW_TYPEID(namePart, typePart) \\",
2132: " CVMtypeidCreateTypeIDFromParts(RAW_TYPEID_NAME_PART((namePart)), RAW_TYPEID_TYPE_PART((typePart)))",
2133: "",
2134: "",
2135: "#if !defined(CVM_64)",
2136: "# define TYPEID(namePart, typePart) RAW_TYPEID((namePart), (typePart))",
2137: "#else",
2138: "# define TYPEID(namePart, typePart) INTEGER(RAW_TYPEID((namePart), (typePart)))",
2139: "#endif",
2140: "",
2141: "",
2142: "#define ADDR(addr) ((CVMAddr) (addr))",
2143: "",
2144: "",
2145: "#ifdef CVM_64",
2146: "",
2147: "# define LONG(high, low) (((CVMAddr) (high) << 32) | ((CVMAddr) (low) & 0x0ffffffff)), 0",
2148: "# define DOUBLE(high, low) LONG((high), (low))",
2149: "",
2150: "# if (CVM_ENDIANNESS == CVM_BIG_ENDIAN)",
2151: "# define INTEGER(i) (((CVMAddr) (i)) << 32)",
2152: "# else",
2153: "# define INTEGER(i) ((CVMAddr) (i))",
2154: "# endif",
2155: "",
2156: "#else /* CVM_64 */",
2157: "",
2158: "# define INTEGER(i) ADDR(i)",
2159: "",
2160: "# if (CVM_ENDIANNESS == CVM_BIG_ENDIAN)",
2161: "# define LONG(high, low) ADDR(high), ADDR(low)",
2162: "# else",
2163: "# define LONG(high, low) ADDR(low), ADDR(high)",
2164: "# endif",
2165: "",
2166: "# if (CVM_DOUBLE_ENDIANNESS == CVM_BIG_ENDIAN)",
2167: "# define DOUBLE(high, low) ADDR(high), ADDR(low)",
2168: "# else",
2169: "# define DOUBLE(high, low) ADDR(low), ADDR(high)",
2170: "# endif",
2171: "",
2172: "#endif /* CVM_64 */",
2173: "",
2174: "",
2175: "#define CP_ADDR(addr) ADDR((addr))",
2176: "#define CP_INTEGER(i) INTEGER((i))",
2177: "#define CP_LONG(high, low) LONG((high), (low))",
2178: "#define CP_DOUBLE(high, low) DOUBLE((high), (low))",
2179: "#define CP_TYPEID(namePart, typePart) TYPEID((namePart), (typePart))",
2180: "#if (CVM_ENDIANNESS == CVM_BIG_ENDIAN)",
2181: "# define CP_MEMBER_REF(classPart,typePart) INTEGER((((classPart)<<16)+(typePart)))",
2182: "#else",
2183: "# define CP_MEMBER_REF(classPart,typePart) INTEGER((((typePart)<<16)+(classPart)))",
2184: "#endif",
2185: "",
2186: "",
2187:
2188: "#ifdef _MSC_VER",
2189: "#define STATIC /* static */",
2190: "#else",
2191: "#define STATIC static",
2192: "#endif",
2193:
2194: "#define SCALARTYPE_NO(n) (n)",
2195: //"#define MSIG_NO(n) ((struct methodTypeTableEntry*)&CVMMethodSigTable.typeSig[n])",
2196: "#define NAME_NO(n) (n)",
2197: "#define SIG_DETAIL_NO(n) (&msig_details[n])",
2198: /*
2199: * Moved globals to CVMROMGlobals.
2200: */
2201: "#define STATIC_STORE_ADDRESS(n) (&CVMROMGlobals."
2202: + staticStoreName + "[CVM_STATIC_OFFSET(n)])",
2203: "",
2204: /*
2205: * Moved globals to CVMROMGlobals.
2206: */
2207: /*
2208: "extern CVMInt32 "+staticStoreName+"[];",
2209: */
2210: /*
2211: * Added another const (for the pointer, which is also const
2212: * here, not just the data)
2213: */
2214: "extern const CVMMethodBlock* const java_lang_Object_mt[];",
2215: "",
2216:
2217: };
2218:
2219: /* this is target-dependent and belongs in a header file... */
2220: private static String targetHeader[] = {};
2221:
2222: /*
2223: * Added header file for globals
2224: */
2225: private void writeGlobalHeaderPrologue(BufferedPrintStream o) {
2226: o
2227: .println("/* This file contains all global and static variables that were");
2228: o.println(" * originally in the generated files.");
2229: o.println(" */");
2230: o.println("struct CVMROMGlobalState");
2231: o.println("{");
2232: }
2233:
2234: private void writeGlobalHeaderEpilogue(BufferedPrintStream o) {
2235: o.println("};");
2236: o.println("");
2237: o.println("extern struct CVMROMGlobalState CVMROMGlobals;");
2238: }
2239:
2240: private void writeHeaderPrologue(BufferedPrintStream o) {
2241:
2242: for (int i = 0; i < targetHeader.length; i++) {
2243: o.println(targetHeader[i]);
2244: }
2245: for (int i = 0; i < stdHeader.length; i++) {
2246: o.println(stdHeader[i]);
2247: }
2248:
2249: o.println("");
2250: }
2251:
2252: /*
2253: * Moved global variables to CVMROMGlobals
2254: */
2255: private void writeHeaderEpilogue(BufferedPrintStream o) {
2256: o.println("");
2257: o.println("/* Moved global variables to CVMROMGlobals");
2258: o.println(" */");
2259: o.println("");
2260: o.println("#include \"" + globalHeaderFileName + "\"");
2261: }
2262:
2263: private void writePrologue(BufferedPrintStream o) {
2264: if (headerFileName != null) {
2265: o.println("#include \"" + headerFileName + "\"");
2266: }
2267: }
2268:
2269: private static String cbName(CVMClass c) {
2270: return c.getNativeName() + "_Classblock.classclass";
2271: }
2272:
2273: private void writeClass(int classno, CVMClass c, int clinitIdx,
2274: int nStaticWords) {
2275:
2276: classOut.println("\n/* ******** Class " + c.getNativeName()
2277: + " ******** */");
2278:
2279: classBlockName = cbName(c);
2280:
2281: writeMethods(c);
2282: // writeInterfaces(c);
2283: interfaceTableName = (c.inf.iv.length == 0) ? "0" : ("&"
2284: + c.inf.name + ".interfaces");
2285:
2286: writeFields(c);
2287:
2288: if (c.isArrayClass()) {
2289: ArrayClassInfo info = (ArrayClassInfo) c.ci;
2290: constantPoolName = writeArrayInfo(info, c.getNativeName());
2291: constantPoolSize = 0;
2292: } else {
2293: if (doShared) {
2294: constantPoolName = sharedConstantPoolName + "_cp";
2295: constantPoolSize = sharedConstantPoolSize;
2296: } else {
2297: ConstantPool cpool = c.ci.getConstantPool();
2298: constantPoolName = writeConstants(cpool, c
2299: .getNativeName(), false);
2300: constantPoolSize = cpool.getLength();
2301: }
2302: }
2303:
2304: writeMethodTable(c);
2305: writeClassinfo(classno, c, clinitIdx, nStaticWords);
2306:
2307: }
2308:
2309: private void processStrings(ConstantPool cp) {
2310: int n = cp.getLength();
2311: for (int i = 1; i < n;) {
2312: ConstantObject obj = cp.elementAt(i);
2313: if (obj instanceof StringConstant) {
2314: stringTable.intern((StringConstant) obj);
2315: }
2316: i += obj.nSlots;
2317: }
2318: }
2319:
2320: private void classProcessStrings(ClassInfo c, boolean doShared) {
2321: FieldInfo f[] = c.fields;
2322: int fieldCount = (f == null) ? 0 : f.length;
2323: if (!doShared) {
2324: processStrings(c.getConstantPool());
2325: }
2326: //
2327: // make sure that strings appearing ONLY as static final
2328: // initializer values get processed, too.
2329: //
2330: for (int i = 0; i < fieldCount; i++) {
2331: FieldInfo fi = f[i];
2332: if (fi.isStaticMember()
2333: && fi.value instanceof StringConstant) {
2334: stringTable.intern((StringConstant) (fi.value));
2335: }
2336: }
2337: }
2338:
2339: private void instantiateAllStrings() {
2340: njavastrings = stringTable.writeStrings(auxOut,
2341: masterStringArrayName);
2342: globalHeaderOut.println(" struct java_lang_String "
2343: + stringArrayName + "[" + njavastrings + "];");
2344: auxOut.println("const int CVM_nROMStrings = " + njavastrings
2345: + ";");
2346: auxOut
2347: .println("CVMArrayOfChar* const CVM_ROMStringsMasterDataPtr = (CVMArrayOfChar* const)&CVM_ROMStringsMaster_data.hdr;");
2348:
2349: /*
2350: * Moved global variables to CVMROMGlobals
2351: * That makes it necessary to pass the global header out file into writeStringInternTable.
2352: */
2353: stringTable.writeStringInternTable(auxOut, globalHeaderOut,
2354: "CVMInternTable", stringArrayName);
2355: }
2356:
2357: /*
2358: * Our representation of method types has four variations:
2359: * 0: inline form, inline details;
2360: * 1: inline form, outboard details;
2361: * 2: outboard form, inline details (rare);
2362: * 3: outboard form, outboard details, too.
2363: * For our own convenience, we are going to segregate them
2364: * by type. This affects the indexing scheme, so we must
2365: * assign that, too, after the sort.
2366: */
2367: private static int variety(CVMMethodType mt) {
2368: int v = 0;
2369: if (mt.form.nSyllables > CVMSigForm.SYLLABLESPERDATUM)
2370: v += 2;
2371: if (mt.nDetails > 2)
2372: v += 1;
2373: return v;
2374: }
2375:
2376: private void enumerateMethodTypes() {
2377: methodTypes = new CVMMethodType[4];
2378: nMethodTypes = new int[4];
2379: Enumeration e = CVMMethodType.methodTypes.elements();
2380: while (e.hasMoreElements()) {
2381: CVMMethodType mt = (CVMMethodType) (e.nextElement());
2382: int v = variety(mt);
2383: mt.listNext = methodTypes[v];
2384: methodTypes[v] = mt;
2385: nMethodTypes[v] += 1;
2386: }
2387: int curTypeNo = 0;
2388: for (int i = 0; i < 4; i++) {
2389: for (CVMMethodType mt = methodTypes[i]; mt != null; mt = mt.listNext) {
2390: mt.entryNo = curTypeNo++;
2391: }
2392: }
2393: totalMethodTypes = curTypeNo;
2394: }
2395:
2396: /*
2397: * The CVM type structures are built up as a side effect of
2398: * turning signatures and names into 16-bit cookies while writing out
2399: * other structures. Thus they must be written AFTER all the entries are
2400: * computed. Fortunately there will be no forward-references to them,
2401: * as all references are by index values, not addresses.
2402: */
2403: private void writeCVMNameAndTypeTables() {
2404: writeCVMpkgHeader();
2405: writeCVMDataTypeTable();
2406: writeCVMpkg();
2407: writeCVMMethodTypeTable();
2408: writeCVMMemberNameTable();
2409: }
2410:
2411: /*
2412: * The value-type table is one of the larger type structures, as it also
2413: * holds class names. It has variant records. It contains an internal linked
2414: * list for lookup-by-name. It has reference counts, but we will set these
2415: * to the magic maximum value so that this can be READONLY.
2416: */
2417: private void writeCVMDataTypeTable() {
2418: Vector allDataTypes = CVMDataType.dataTypes;
2419: int nData = allDataTypes.size();
2420: /*
2421: * May need to do an iteration through to determine the layout, in case
2422: * we have some trouble initializing union types and have to do more
2423: * specific declarations!
2424: */
2425: /*
2426: * Moved global variables to CVMROMGlobals
2427: */
2428: globalHeaderOut
2429: .println(" struct scalarTableSegment * dummyNextCell;");
2430: initInfo.addInfo("NULL", "&CVMROMGlobals.dummyNextCell",
2431: "sizeof(CVMROMGlobals.dummyNextCell)");
2432: auxOut
2433: .println("const struct { SCALAR_TABLE_SEGMENT_HEADER struct scalarTableEntry data["
2434: + nData + "]; }\nCVMFieldTypeTable = {");
2435: auxOut.println("\t" + (CVMTypeCode.CVMtypeLastScalar + 1)
2436: + ", 0, -1," + nData
2437: + ", &CVMROMGlobals.dummyNextCell, {");
2438: for (int i = 0; i < nData; i++) {
2439: CVMDataType o = (CVMDataType) allDataTypes.elementAt(i);
2440: /* Yet more debugging output ....
2441: if ( o != null && i != o.entryNo ){
2442: System.out.println("Datatype entry "+o+" misplaced: is at vector["+i+"] and expected at ["+o.entryNo+"]");
2443: }
2444: */
2445: if (o instanceof CVMClassDataType) {
2446: CVMClassDataType ctype = (CVMClassDataType) o;
2447: String next;
2448: next = (ctype.next == null) ? "TYPEID_NOENTRY"
2449: : ("SCALARTYPE_NO(" + ctype.next.typeNo + ")");
2450: // int nameHash = CVMDataType.computeHash(ctype.classInPackage);
2451: int nameLength = ctype.classInPackage.length();
2452: if (nameLength > 255)
2453: nameLength = 255;
2454: auxOut.println(" INIT_CLASSTYPE( " + next + ", PKG_NO("
2455: + ctype.pkg.entryNo + "), \""
2456: + ctype.classInPackage + "\", " + nameLength
2457: + "),");
2458: } else {
2459: CVMArrayDataType atype = (CVMArrayDataType) o;
2460: String next;
2461: next = (atype.next == null) ? "TYPEID_NOENTRY"
2462: : ("SCALARTYPE_NO(" + atype.next.typeNo + ")");
2463: auxOut.println(" INIT_ARRAYTYPE( " + next + ", "
2464: + atype.depth + ", " + atype.baseType + "),");
2465: }
2466: }
2467: auxOut.println("}};");
2468:
2469: }
2470:
2471: /*
2472: * The package name data structures and hash tables have to go after the
2473: * general value-type table, as it contains little hash tables
2474: * of pointers to the latter.
2475: * These are used for lookup by class name.
2476: */
2477: private void writeCVMpkgHeader() {
2478: int nPkg = CVMpkg.pkgVector.size();
2479: /*
2480: * Moved global variables to CVMROMGlobals
2481: */
2482: globalHeaderOut.println(" struct pkg CVM_ROMpackages["
2483: + (nPkg) + "];");
2484: auxOut
2485: .println("#define PKG_NO(n) &CVMROMGlobals.CVM_ROMpackages[n]");
2486: auxOut.println("const int CVM_nROMpackages = " + nPkg + ";");
2487: }
2488:
2489: private void writeCVMpkg() {
2490: Vector allPackages = CVMpkg.pkgVector;
2491: int nPkg = allPackages.size();
2492:
2493: auxOut.println("STATIC const struct pkg CVM_ROMpackagesMaster["
2494: + (nPkg) + "] = {");
2495: for (int i = 0; i < nPkg; i++) {
2496: CVMpkg p = (CVMpkg) (allPackages.elementAt(i));
2497: writeAnCVMpkg(p);
2498: /* DEBUG
2499: if ( p.entryNo != i ){
2500: System.out.println("Package entry "+p.pkgName+" misplaced: is at vector["+i+"] and expected at ["+p.entryNo+"]");
2501: }
2502: */
2503: }
2504: auxOut.println("};");
2505:
2506: initInfo.addInfo("CVM_ROMpackagesMaster",
2507: "CVMROMGlobals.CVM_ROMpackages", nPkg
2508: + "*sizeof(struct pkg)");
2509:
2510: // that was the packages themselves.
2511: // this is the hash table that is the basis of looking them up.
2512: // this needs to be writable, since we add at the front of the
2513: // linked list.
2514: auxOut
2515: .print("STATIC const struct pkg * const CVM_PkgHashtableMaster["
2516: + CVMpkg.NPACKAGEHASH + "] = {");
2517: for (int i = 0; i < CVMpkg.NPACKAGEHASH; i++) {
2518: CVMpkg p = CVMpkg.packages[i];
2519: if (i % 5 == 0) {
2520: auxOut.print("\n\t");
2521: }
2522: auxOut.print((p == null) ? "0, "
2523: : ("PKG_NO(" + (p.entryNo) + "), "));
2524: }
2525: auxOut.println("\n};");
2526: /*
2527: * Moved globals to CVMROMGlobals.
2528: */
2529: globalHeaderOut.println(" struct pkg *CVM_pkgHashtable["
2530: + CVMpkg.NPACKAGEHASH + "];");
2531: initInfo.addInfo("CVM_PkgHashtableMaster",
2532: "CVMROMGlobals.CVM_pkgHashtable", CVMpkg.NPACKAGEHASH
2533: + "*sizeof(struct pkg*)");
2534:
2535: /*
2536: * Made this const (never changed)
2537: */
2538: auxOut
2539: .println("struct pkg * const CVMnullPackage = PKG_NO(0);");
2540: }
2541:
2542: private void writeAnCVMpkg(CVMpkg p) {
2543: String next = (p.next == null) ? "0" : ("PKG_NO("
2544: + p.next.entryNo + ")");
2545: //int nameHash = CVMDataType.computeHash(p.pkgName);
2546: auxOut.print(" { \"" + p.pkgName + "\", " + next
2547: + ", INROM, MAX_COUNT, {");
2548: for (int i = 0; i < CVMpkg.NCLASSHASH; i++) {
2549: String hashp = (p.typeData[i] == null) ? "TYPEID_NOENTRY"
2550: : ("SCALARTYPE_NO(" + p.typeData[i].typeNo + ")");
2551: if (i % 3 == 0) {
2552: auxOut.print("\n\t");
2553: }
2554: auxOut.print(hashp);
2555: auxOut.print(", ");
2556: }
2557: auxOut.println("\n }},");
2558: }
2559:
2560: /*
2561: * The CVMMethodTypes are complex, multi-part beasts.
2562: * The first part is the Form or Terse Signature,
2563: * Then we need the details array
2564: * And finally the table of method types. There are 4 kinds of them!:
2565: * 0: inline form, inline details;
2566: * 1: inline form, outboard details;
2567: * 2: outboard form, inline details (rare);
2568: * 3: outboard form, outboard details, too.
2569: * They are all the same size!
2570: */
2571: public void writeCVMMethodTypeTable() {
2572: // The first part is the Form or Terse Signature.
2573: writeCVMForms();
2574:
2575: // then the details array.
2576: writeCVMMethodDetails();
2577:
2578: // write the indirect dummy.
2579: /*
2580: * Moved global variables to CVMROMGlobals
2581: */
2582: globalHeaderOut
2583: .println(" struct methodTypeTableSegment *methodTypeDummy;");
2584: initInfo.addInfo("NULL", "&CVMROMGlobals.methodTypeDummy",
2585: "sizeof(CVMROMGlobals.methodTypeDummy)");
2586:
2587: // write the specific declaration we need for this
2588: // set of types.
2589: /*
2590: * CVMMethodTypeTable is a structure that holds
2591: * arrays of struct methodTypeTableEntry (see typeid_impl.h)
2592: * which are initialized in different ways because
2593: * struct methodTypeTableEntry contains two unions.
2594: *
2595: * Unfortunately the original implementation does only
2596: * fit for 32 bit platforms (because all four
2597: * struct declarations have the same byte size;
2598: * unsigned int formdata is as long as struct sigForm *
2599: * and unsigned short data[2] is as long as short* datap).
2600: * But that does not fit for 64 bit platforms. Therefore
2601: * the struct declaration from typeid_impl.h is used to be
2602: * sure the initialization is also correct for other platforms.
2603: */
2604: auxOut.println("const struct { METHOD_TABLE_SEGMENT_HEADER");
2605: for (int i = 0; i < 4; i++) {
2606: if (nMethodTypes[i] == 0)
2607: continue;
2608: auxOut.print(" struct { METHOD_TYPE_HEADER ");
2609: if ((i & 2) == 0) {
2610: // inline form
2611: // This used to be auxOut.print("unsigned int formdata; ");
2612: auxOut
2613: .print("union {CVMUint32 formdata; struct sigForm * formp;} form; ");
2614: } else {
2615: // outline form
2616: // This used to be auxOut.print("struct sigForm * formp; ");
2617: auxOut
2618: .print("union {struct sigForm * formp; CVMUint32 formdata;} form; ");
2619: }
2620: if ((i & 1) == 0) {
2621: // inline details
2622: // This used to be auxOut.print("unsigned short data[2]; ");
2623: auxOut
2624: .print("union {CVMTypeIDTypePart data[2]; const CVMTypeIDTypePart * datap; } details; ");
2625: } else {
2626: // outline details
2627: // This used to be auxOut.print("const short* datap; ");
2628: auxOut
2629: .print("union {const CVMTypeIDTypePart * datap; CVMTypeIDTypePart data[2]; } details; ");
2630: }
2631: auxOut.print(" }typesig");
2632: auxOut.println(i + "[" + nMethodTypes[i] + "];");
2633: }
2634: auxOut.println("} CVMMethodTypeTable = {");
2635:
2636: // now the header info
2637: /*
2638: * Moved global variables to CVMROMGlobals
2639: */
2640: auxOut.println(" 0, 0, -1, " + totalMethodTypes
2641: + ", &CVMROMGlobals.methodTypeDummy,");
2642:
2643: // and the actual data.
2644: for (int i = 0; i < 4; i++) {
2645: if (nMethodTypes[i] == 0)
2646: continue;
2647: auxOut.println(" {");
2648: for (CVMMethodType m = methodTypes[i]; m != null; m = m.listNext) {
2649: String next = (m.next == null) ? "TYPEID_NOENTRY"
2650: : String.valueOf(m.next.entryNo);
2651: auxOut.print(" {" + next + ", MAX_COUNT, ROMSTATE "
2652: + (m.form.nSyllables - 2));
2653: CVMSigForm f = m.form;
2654: if ((i & 2) == 0) {
2655: // inline form
2656: // This used to be auxOut.print(", 0x"+Integer.toHexString( f.data[0] ));
2657: auxOut.print(", {0x"
2658: + Integer.toHexString(f.data[0]) + "}");
2659: } else {
2660: // outline form
2661: // This used to be auxOut.print(", (struct sigForm*)(&CVM_ROMforms.form"+f.listNo+"["+f.entryNo+"])");
2662: auxOut
2663: .print(", {(struct sigForm*)(&CVM_ROMforms.form"
2664: + f.listNo
2665: + "["
2666: + f.entryNo
2667: + "])}");
2668: }
2669: if ((i & 1) == 0) {
2670: // inline details
2671: auxOut.print(", {{");
2672: for (int j = 0; j < 2; j++) {
2673: auxOut.print("RAW_TYPEID_TYPE_PART(0x");
2674: auxOut
2675: .print(Integer
2676: .toHexString((j < m.nDetails) ? m.details[j]
2677: : 0));
2678: auxOut.print("),");
2679: }
2680: auxOut.print("}}");
2681: } else {
2682: // outline details
2683: auxOut.print(", {SIG_DETAIL_NO(" + (m.detailOffset)
2684: + ")}");
2685: }
2686: auxOut.println("},");
2687: }
2688: auxOut.println(" },");
2689: }
2690: auxOut.println("};");
2691:
2692: /*
2693: * A signature search begins with a hash.
2694: * The hash table must be writeable.
2695: */
2696: /*
2697: * Moved global variables to CVMROMGlobals
2698: */
2699: globalHeaderOut
2700: .println(" CVMTypeIDTypePart CVMMethodTypeHash[NMETHODTYPEHASH];");
2701: /*
2702: * Added extra precautions to ensure we use the same hash function.
2703: */
2704: auxOut.println("#if NMETHODTYPEHASH != " + CVMMethodType.NHASH);
2705: auxOut
2706: .println("#error \"CVMMethodType.NHASH and NMETHODTYPEHASH are not the same\"");
2707: auxOut.println("#endif");
2708:
2709: auxOut
2710: .print("STATIC const CVMTypeIDTypePart CVMMethodTypeHashMaster[NMETHODTYPEHASH]={");
2711:
2712: for (int i = 0; i < CVMMethodType.NHASH; i++) {
2713: CVMMethodType mt = CVMMethodType.hashTable[i];
2714: if (i % 4 == 0) {
2715: auxOut.print("\n ");
2716: }
2717: if (mt == null) {
2718: auxOut.print("TYPEID_NOENTRY, ");
2719: } else {
2720: auxOut.print(mt.entryNo);
2721: auxOut.print(", ");
2722: }
2723: }
2724: auxOut.println("};");
2725: /*
2726: * Moved global variables to CVMROMGlobals
2727: */
2728: initInfo
2729: .addInfo(
2730: "CVMMethodTypeHashMaster",
2731: "CVMROMGlobals.CVMMethodTypeHash",
2732: CVMMethodType.NHASH
2733: + "*sizeof(CVMROMGlobals.CVMMethodTypeHash[0])");
2734: }
2735:
2736: /*
2737: * Method signature varieties 1 & 3 have details written in an
2738: * array-of-short.
2739: */
2740: private void writeCVMMethodDetails() {
2741: if (nMethodTypes[1] + nMethodTypes[3] == 0)
2742: return; // nothing to do.
2743: // We could search for shared sub-sequences of detail sequences.
2744: // On the other hand, these so seldom occur at all
2745: // that it would make very little difference.
2746: int curOffset = 0;
2747: auxOut
2748: .print("STATIC const CVMTypeIDTypePart msig_details[] = {");
2749: for (int i = 1; i < 4; i += 2) { // i.e. for i in {1,3}
2750: for (CVMMethodType m = methodTypes[i]; m != null; m = m.listNext) {
2751: m.detailOffset = curOffset;
2752: int ndetail = m.nDetails;
2753: int details[] = m.details;
2754: for (int j = 0; j < ndetail; j++) {
2755: if (curOffset % 6 == 0) {
2756: auxOut.print("\n ");
2757: }
2758: auxOut.print("RAW_TYPEID_TYPE_PART(0x"
2759: + Integer.toHexString(details[j]) + ")");
2760: auxOut.write(',');
2761: auxOut.write(' ');
2762: curOffset += 1;
2763: }
2764: }
2765: }
2766: auxOut.println("\n};");
2767: }
2768:
2769: private void writeCVMForms() {
2770: /*
2771: * Declare a data structure to contain all the "big" forms.
2772: * Since they are of varying lengths, this will require a
2773: * custom declaration.
2774: */
2775: auxOut.println("STATIC const struct {");
2776: for (int i = 1; i < CVMSigForm.listLength.length; i++) {
2777: if (CVMSigForm.listLength[i] == 0)
2778: continue; // never mind...
2779: /*
2780: * Added symbol DUMMY (which is never used, but in VC++ on Win32 the preprocessor barks
2781: * if it doesn't get an argument here)
2782: */
2783: auxOut.println(" DECLARE_SIG_FORM_N( DUMMY" + i
2784: + " /* never used */, " + (i + 1) + ") form" + i
2785: + "[" + CVMSigForm.listLength[i] + "];");
2786: }
2787: auxOut.println("} CVM_ROMforms = {");
2788: /*
2789: * Now supply the data. They're all on a single linked list,
2790: * which we construct (last-to-first) as we go.
2791: */
2792: String link = "0";
2793: for (int i = 1; i < CVMSigForm.listLength.length; i++) {
2794: int n = CVMSigForm.listLength[i];
2795: if (n == 0)
2796: continue; // never mind...
2797: String segname = "&CVM_ROMforms.form" + i;
2798: auxOut.println(" {");
2799: int fno = 0;
2800: for (CVMSigForm f = CVMSigForm.formList[i]; f != null; f = f.listNext) {
2801: auxOut.print(" ");
2802: auxOut.print("{ (struct sigForm*)" + link
2803: + ", MAX_COUNT, ROMSTATE ");
2804: auxOut.print((f.nSyllables - 2) + ", { ");
2805: int nWordsLess1 = f.data.length - 1;
2806: for (int k = 0; k <= nWordsLess1; k++) {
2807: auxOut.printHexInt(f.data[k]);
2808: if (k < nWordsLess1)
2809: auxOut.print(", ");
2810: }
2811: auxOut.println("} },");
2812: //f.listNo = i;
2813: f.entryNo = fno;
2814: link = segname + "[" + (fno++) + "]";
2815: }
2816: auxOut.println(" },");
2817: }
2818: auxOut.println("};");
2819:
2820: /*
2821: * Finally, the root of the form list.
2822: */
2823: /*
2824: * Moved globals to CVMROMGlobals.
2825: */
2826: globalHeaderOut.println(" struct sigForm * CVMformTable;");
2827: auxOut
2828: .println("STATIC const struct sigForm * const CVMformTableMaster = (struct sigForm *)"
2829: + link + ";");
2830: initInfo.addInfo("&CVMformTableMaster",
2831: "&CVMROMGlobals.CVMformTable",
2832: "sizeof(CVMformTableMaster)");
2833: }
2834:
2835: private void writeCVMMemberNameTable() {
2836: int ndata = CVMMemberNameEntry.tableSize();
2837: /*
2838: * Moved global variables to CVMROMGlobals
2839: */
2840: globalHeaderOut
2841: .println(" struct memberNameTableSegment * dummyNextMembernameCell;");
2842: initInfo.addInfo("NULL",
2843: "&CVMROMGlobals.dummyNextMembernameCell",
2844: "sizeof(CVMROMGlobals.dummyNextMembernameCell)");
2845: auxOut
2846: .println("const struct { MEMBER_NAME_TABLE_SEGMENT_HEADER struct memberName data["
2847: + ndata + "]; }\nCVMMemberNames = {");
2848: auxOut.println(" 0, 0, -1, " + ndata
2849: + ", &CVMROMGlobals.dummyNextMembernameCell, {");
2850: for (int i = 0; i < ndata; i++) {
2851: CVMMemberNameEntry mne = (CVMMemberNameEntry) (CVMMemberNameEntry.table
2852: .elementAt(i));
2853: String next = (mne.next == null) ? "TYPEID_NOENTRY"
2854: : ("NAME_NO(" + mne.next.entryNo + ")");
2855: auxOut.println("\t{" + next + ", MAX_COUNT, ROMSTATE \""
2856: + mne.name + "\"},");
2857: }
2858: auxOut.println("}};");
2859:
2860: /*
2861: * Moved global variables to CVMROMGlobals
2862: */
2863: globalHeaderOut
2864: .println(" CVMTypeIDNamePart CVMMemberNameHash[NMEMBERNAMEHASH];");
2865:
2866: auxOut
2867: .print("STATIC const CVMTypeIDNamePart CVMMemberNameHashMaster[NMEMBERNAMEHASH]={");
2868: for (int i = 0; i < CVMMemberNameEntry.NMEMBERNAMEHASH; i++) {
2869: CVMMemberNameEntry mne = CVMMemberNameEntry.hash[i];
2870: if (i % 4 == 0) {
2871: auxOut.print("\n ");
2872: }
2873: if (mne == null) {
2874: auxOut.print("TYPEID_NOENTRY, ");
2875: } else {
2876: auxOut.print(mne.entryNo);
2877: auxOut.print(", ");
2878: }
2879: }
2880: auxOut.println("};");
2881: /*
2882: * Moved global variables to CVMROMGlobals
2883: */
2884: initInfo
2885: .addInfo(
2886: "CVMMemberNameHashMaster",
2887: "CVMROMGlobals.CVMMemberNameHash",
2888: CVMMemberNameEntry.NMEMBERNAMEHASH
2889: + "*sizeof(CVMROMGlobals.CVMMemberNameHash[0])");
2890: }
2891:
2892: /* Write the invokeCost array for romized methods. */
2893: private void writeMethodInvokeCostArray() {
2894: globalHeaderOut
2895: .println("#if defined(CVM_JIT) && defined(CVM_MTASK)");
2896: globalHeaderOut
2897: .println(" CVMUint16 CVMROMMethodInvokeCosts["
2898: + nTotalMethods + "];");
2899: globalHeaderOut.println("#endif");
2900: auxOut.println("#if defined(CVM_JIT) && defined(CVM_MTASK)");
2901: auxOut.println("const int CVM_nROMMethods = " + nTotalMethods
2902: + ";");
2903: auxOut.println("#endif");
2904: }
2905:
2906: class ClassTable {
2907: String name;
2908: int nClasses;
2909: CVMClass classVector[];
2910: boolean foundFirstVector;
2911: boolean foundLastVector;
2912: boolean foundFirstNonPrimitive;
2913: int firstVector;
2914: int lastVector;
2915: int firstNonPrimitive;
2916:
2917: ClassTable(int nMax, String nm) {
2918: name = nm;
2919: classVector = new CVMClass[nMax];
2920: nClasses = 0;
2921: foundFirstVector = false;
2922: foundLastVector = false;
2923: }
2924:
2925: void addClass(CVMClass c) {
2926: int hashCode = 0;
2927: int classid = c.classid();
2928: if ((!foundFirstNonPrimitive) & !c.isPrimitiveClass()) {
2929: firstNonPrimitive = nClasses;
2930: foundFirstNonPrimitive = true;
2931: }
2932: int classid_depth = classid & CVMTypeCode.CVMtypeArrayMask;
2933: if ((classid_depth != 0)
2934: && (classid_depth != CVMTypeCode.CVMtypeBigArray)) {
2935: if (!foundFirstVector) {
2936: firstVector = nClasses;
2937: foundFirstVector = true;
2938: }
2939: if (((classid >> CVMTypeCode.CVMtypeArrayShift) > 1)
2940: && !foundLastVector) {
2941: lastVector = nClasses - 1;
2942: foundLastVector = true;
2943: }
2944: }
2945: classVector[nClasses++] = c;
2946: }
2947:
2948: void writeClasslistInfo() {
2949: if (!foundFirstVector) {
2950: // If, by now, we've not found the first vector, then there is no
2951: // preloaded array type. Point the first vector to the end of
2952: // the array:
2953: firstVector = nClasses;
2954: foundFirstVector = true;
2955: lastVector = nClasses;
2956: foundLastVector = true;
2957: } else if (!foundLastVector) {
2958: // If we get here, then we must have found the first vector but
2959: // have not found the last vector. This means that there are
2960: // array types of depth 1 in the list but no array types of
2961: // depth greater than 1. Point the last vector to the last
2962: // entry in the list:
2963: lastVector = nClasses - 1;
2964: foundLastVector = true;
2965: }
2966: auxOut.println("const int CVM_n" + name + "ROMClasses = "
2967: + String.valueOf(nClasses) + ";");
2968: auxOut.print("const int CVM_" + name
2969: + "firstROMVectorClass = ");
2970: auxOut.print(firstVector);
2971: auxOut.print(";\nconst int CVM_" + name
2972: + "lastROMVectorClass = ");
2973: auxOut.print(lastVector);
2974: auxOut.println(";");
2975: auxOut.print("const int CVM_" + name
2976: + "firstROMNonPrimitiveClass = ");
2977: auxOut.print(firstNonPrimitive);
2978: auxOut.println(";");
2979: }
2980:
2981: void writeClasslist() {
2982: int n = nClasses;
2983: CVMClass classes[] = classVector;
2984: //auxOut.println("const CVMClassBlock * const CVM_"+name+"ROMClassBlocks[] = {" );
2985: for (int i = 0; i < n; i++) {
2986: CVMClass c = classVector[i];
2987: auxOut.print(" &");
2988: auxOut.print(cbName(c));
2989: auxOut.println(",");
2990: }
2991: //auxOut.println("};");
2992: }
2993:
2994: }
2995:
2996: public void writeClassList() {
2997: boolean foundFirstNonPrimitive = false;
2998: int firstNonPrimitive = 0;
2999: int n = (classes == null) ? 0 : classes.length;
3000: ClassTable classTable = new ClassTable(n, "");
3001: globalHeaderOut
3002: .println(" struct java_lang_Class CVM_ROMClassBlocks["
3003: + String.valueOf(n) + "];");
3004: auxOut.println("const int CVM_nTotalROMClasses = "
3005: + String.valueOf(n) + ";");
3006: /*
3007: * Moved globals to CVMROMGlobals
3008: */
3009: globalHeaderOut
3010: .println(" struct java_lang_Class CVM_ROMClasses["
3011: + n + "];");
3012: for (int i = 0; i < n; i++) {
3013: int hashCode = 0;
3014: CVMClass c = classes[i];
3015: int classid = c.classid();
3016: classTable.addClass(c);
3017: }
3018: auxOut
3019: .println("const CVMClassBlock * const CVM_ROMClassblocks[] = {");
3020: classTable.writeClasslist();
3021: auxOut.println("};");
3022: classTable.writeClasslistInfo();
3023:
3024: //
3025: // array of stack map indirect cells
3026: //
3027: /*
3028: * Moved global variables to CVMROMGlobals
3029: */
3030: declare("const CVMClassICell CVM_classICell[]", auxOut);
3031: auxOut.println(" = {");
3032: for (int i = 0; i < n; i++) {
3033: auxOut
3034: .println(" { (CVMObject*)(&CVMROMGlobals.CVM_ROMClasses["
3035: + i + "])},");
3036: }
3037: auxOut.println("};");
3038: }
3039:
3040: public boolean writeClasses(ConstantPool sharedconsts,
3041: boolean doWrite) {
3042:
3043: // getClassVector sorts the classes with
3044: // super before sub, for reasonable processing without recursion.
3045: ClassClass arrayOfClasses[] = ClassClass
3046: .getClassVector(classMaker);
3047: ClassClass.setTypes();
3048: int nClasses = arrayOfClasses.length;
3049:
3050: classes = new CVMClass[nClasses];
3051:
3052: if (sharedconsts != null) {
3053: doShared = true;
3054: sharedConstantPoolName = "CVMSharedConstantPool";
3055: sharedConstantPoolSize = sharedconsts.getLength();
3056: if (sharedConstantPoolSize > 0xffff) {
3057: // More than 64K constants are not allowed
3058: throw new Error("Constant pool overflow: 64k constants"
3059: + " allowed, have " + sharedConstantPoolSize);
3060: }
3061: }
3062:
3063: /*
3064: * sort the array by classid. This makes it easier do lookups
3065: * at runtime.
3066: * The mechanics of this whole writer assume a single
3067: * ordering for these classes, as they are often
3068: * referred to by their class number.
3069: * This is it.
3070: * To avoid finding the primitive classes at all, they are
3071: * placed at the very end.
3072: */
3073: System.arraycopy(arrayOfClasses, 0, classes, 0, nClasses);
3074: Arrays.sort(classes, (java.util.Comparator) classMaker);
3075:
3076: enumerateMethodTypes();// after all classes processed once by classMaker
3077: // ... but before we write the classes.
3078:
3079: // write out some constant pool stuff here,
3080: // if we're doing one big shared one...
3081: // gutted out for now...
3082: if (doShared)
3083: processStrings(sharedconsts);
3084:
3085: if (verbose && doWrite) {
3086: System.out.println(Localizer
3087: .getString("cwriter.writing_classes"));
3088: }
3089: try {
3090: //mungeAllIDsAndWriteExternals(classes);
3091: for (int i = 0; i < nClasses; i++) {
3092: classProcessStrings(classes[i].ci, doShared);
3093: }
3094:
3095: if (doWrite) {
3096: instantiateAllStrings();
3097: CVMInterfaceMethodTable.writeInterfaceTables(classes,
3098: auxOut, headerOut);
3099: int nStaticWords = writeStaticStore(classes);
3100:
3101: /* The number of necessary slots for clinitEE + 1.
3102: * Index of a class that doesn't have <clinit> is always 0.
3103: * The 0th entry is reserved for it. */
3104: int maxClinitIdx = 1;
3105: /*
3106: * First off, check compression opportunities. Look over all
3107: * methods to see variations
3108: */
3109: for (int i = 0; i < nClasses; i++) {
3110: CVMClass c = classes[i];
3111: analyzeMethodsForCompression(c);
3112: }
3113: //
3114: // Sort in order of decreasing refcount
3115: //
3116: methStats.sort();
3117: //
3118: // This is shared between our segments
3119: //
3120: methStats.dump(auxOut);
3121: /*
3122: * Now do the writing
3123: */
3124: for (int i = 0; i < nClasses; i++) {
3125: CVMClass c = classes[i];
3126: int clinitIdx = c.hasStaticInitializer ? maxClinitIdx++
3127: : 0;
3128: writeClass(i, c, clinitIdx, nStaticWords);
3129: if (segmentedOutput && (curClasses++ >= maxClasses)) {
3130: curClasses = 0;
3131: openNextClassFile();
3132: }
3133: }
3134:
3135: if (doShared) {
3136: // Dump the shared constant pool
3137: writeConstants(sharedconsts,
3138: sharedConstantPoolName, true /* export c.p. ref */);
3139: }
3140:
3141: writeClassList();
3142:
3143: writeCVMNameAndTypeTables();
3144:
3145: /* Write method invokeCost array */
3146: writeMethodInvokeCostArray();
3147:
3148: initInfo.write(auxOut,
3149: "struct CVM_preloaderInitTriple",
3150: "CVM_preloaderInitMap");
3151: initInfoForMBs.write(auxOut, "void* const",
3152: "CVM_preloaderInitMapForMbs");
3153:
3154: auxOut
3155: .println("const char *CVMROMClassLoaderNames = \""
3156: + components.ClassTable
3157: .getClassLoaderNames() + "\";");
3158: auxOut
3159: .println("CVMAddr * const CVMROMClassLoaderRefs = "
3160: + "STATIC_STORE_ADDRESS("
3161: + clRefOff
3162: + ");");
3163: auxOut.println("const int CVMROMNumClassLoaders = "
3164: + components.ClassTable.getNumClassLoaders()
3165: + ";");
3166: }
3167: } catch (java.io.IOException e) {
3168: failureMode = e;
3169: formatError = true;
3170: } finally {
3171: if (doWrite) {
3172: classOut.flush();
3173: headerOut.flush();
3174: }
3175: }
3176: return (!formatError)
3177: && (!doWrite || ((!classOut.checkError()) && (!headerOut
3178: .checkError())));
3179: }
3180:
3181: public boolean writeClasses(boolean doWrite) {
3182: return writeClasses(null, doWrite);
3183: }
3184:
3185: public void printSpaceStats(java.io.PrintStream o) {
3186: //ClassClass classes[] = ClassClass.getClassVector( classMaker );
3187: o.println(" "
3188: + Localizer.getString("cwriter.total_classes", Integer
3189: .toString(classes.length)));
3190: o.println(" ... of which " + nClinits
3191: + " classes have static initializers ");
3192: o.println(" (" + CodeHacker.checkinitQuickenings + "/"
3193: + CodeHacker.quickenings + " quickening sites)");
3194: o.println(" "
3195: + Localizer.getString("cwriter.method_blocks", Integer
3196: .toString(nmethods)));
3197: if (nWritableMethodBlocks != 0) {
3198: o.println(" ... of which " + nWritableMethodBlocks
3199: + " blocks are writable");
3200: o.println(" ... for " + nClassesWithWritableMethodBlocks
3201: + " classes");
3202: }
3203: if (nMethodsWithCheckinitInvokes > 0) {
3204: o.println(" ... of which " + nMethodsWithCheckinitInvokes
3205: + " have checkinit opcodes in the code");
3206: }
3207: o.println(" "
3208: + Localizer.getString("cwriter.bytes_java_code",
3209: Integer.toString(ncodebytes)));
3210: o.println(" "
3211: + Localizer.getString("cwriter.catch_frames", Integer
3212: .toString(ncatchframes)));
3213: o.println(" "
3214: + Localizer.getString("cwriter.field_blocks", Integer
3215: .toString(nfields)));
3216: o.println(" "
3217: + Localizer.getString("cwriter.inner_classes", Integer
3218: .toString(ninnerclasses)));
3219: o.println(" "
3220: + Localizer.getString("cwriter.constant_pool_entries",
3221: Integer.toString(nconstants)));
3222: o.println(" "
3223: + Localizer.getString("cwriter.java_strings", Integer
3224: .toString(njavastrings)));
3225: }
3226:
3227: }
|