0001: /*
0002: *
0003: *
0004: * Copyright 1990-2007 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 components;
0028:
0029: import jcc.Util;
0030: import jcc.Const;
0031: import util.*;
0032:
0033: import java.io.DataInput;
0034: import java.io.DataOutput;
0035: import java.io.IOException;
0036: import java.io.PrintStream;
0037: import java.util.Hashtable;
0038: import java.util.Enumeration;
0039: import java.util.Vector;
0040:
0041: //
0042: // container for stuff about a class.
0043: // can be in a classfile or in a module.
0044: //
0045:
0046: public class ClassInfo {
0047: public String className;
0048: public int access;
0049: public ClassConstant this Class;
0050: public ClassConstant super Class;
0051: public ClassInfo super ClassInfo;
0052:
0053: // Tables for all fields, methods and constants of this class
0054: public FieldInfo fields[];
0055: public MethodInfo methods[];
0056: public ConstantObject constants[];
0057: private ConstantObject oldConstants[];
0058: public ConstantObject symbols[];
0059: public ClassConstant interfaces[];
0060: public FieldConstant refFieldtable[];
0061: public MethodConstant refMethodtable[];
0062:
0063: // In case we lay it all out here
0064: public FieldInfo fieldtable[];
0065: public MethodInfo methodtable[];
0066: public UnicodeConstant fieldtableName;
0067: public UnicodeConstant methodtableName;
0068:
0069: // Class attributes that we do not interpret
0070: public Attribute[] classAttributes;
0071: public SourceFileAttribute sourceFileAttr;
0072:
0073: public vm.ClassClass vmClass; // used by in-core output writers
0074:
0075: public Vector allInterfaces;
0076:
0077: protected boolean verbose;
0078: protected PrintStream log = System.out;
0079: public ConstantPool externalPool;
0080: public static boolean classDebug = false;
0081:
0082: public int flags;
0083: public static final int INCLUDE_ALL = 1;
0084:
0085: public ClassInfo(boolean v) {
0086: verbose = v;
0087: flags = INCLUDE_ALL; // by default, we want all members.
0088: // what else should be here?
0089: }
0090:
0091: private String genericNativeName;
0092:
0093: public final String getGenericNativeName() {
0094: if (genericNativeName == null)
0095: genericNativeName = createGenericNativeName();
0096: return genericNativeName;
0097: }
0098:
0099: // This will be overridden by subclasses
0100: protected String createGenericNativeName() {
0101: return Util.convertToClassName(className);
0102: }
0103:
0104: // Read in the constants from a classfile
0105: void readConstantPool(DataInput in) throws IOException {
0106: int num = in.readUnsignedShort();
0107:
0108: if (verbose) {
0109: log.println(Localizer.getString(
0110: "classinfo.reading_entries_in_constant_pool",
0111: Integer.toString(num)));
0112: }
0113: constants = new ConstantObject[num];
0114: for (int i = 1; i < num; i += constants[i].nSlots) {
0115: constants[i] = ConstantObject.readObject(in);
0116: constants[i].index = i;
0117: }
0118: }
0119:
0120: private void resolveConstants() {
0121: if (verbose) {
0122: log.println(Localizer
0123: .getString("classinfo.>>>resolving_constants"));
0124: }
0125: for (int i = 1; i < constants.length; i += constants[i].nSlots) {
0126: constants[i].resolve(symbols);
0127: }
0128: }
0129:
0130: protected void externalizeConstants(ConstantPool externalPool) {
0131: if (verbose) {
0132: log.println(Localizer
0133: .getString("classinfo.>>>externalizing_constants"));
0134: }
0135: // externalize immediately certain kinds of constants
0136: // we know to have no direct references.
0137: for (int i = 1; i < constants.length; i += constants[i].nSlots) {
0138: switch (constants[i].tag) {
0139: case Const.CONSTANT_UTF8:
0140: case Const.CONSTANT_NAMEANDTYPE:
0141: // unquestionably, share these.
0142: constants[i] = externalPool.add(constants[i]);
0143: // FALLTHROUGH
0144: default:
0145: constants[i].externalize(externalPool);
0146: break;
0147: }
0148: }
0149: }
0150:
0151: /*
0152: * If we are using an external string table, then
0153: * we can make our own table smaller. At this point,
0154: * all non-code references into it are by object reference, NEVER
0155: * by index -- everything has been resolved! Thus we can
0156: * compact our table, deleting all the UnicodeConstants.
0157: * We adjust each constant's index entry accordingly.
0158: * Naturally, we preserve the null entries.
0159: *
0160: */
0161: public void smashConstantPool() {
0162: int nOld = constants.length;
0163: int nNew = 1;
0164: ConstantObject o;
0165: // first, count and index.
0166: for (int i = 1; i < nOld; i += o.nSlots) {
0167: o = constants[i];
0168: if (!o.shared) {
0169: if (o.references == 0) {
0170: o.index = -1; // trouble.
0171: } else {
0172: // we're keeping it.
0173: o.index = nNew;
0174: nNew += o.nSlots;
0175: }
0176: }
0177: }
0178: // now reallocate and copy.
0179: ConstantObject newConstants[] = new ConstantObject[nNew];
0180: int j = 1;
0181: for (int i = 1; i < nOld; i += o.nSlots) {
0182: o = constants[i];
0183: if ((!o.shared) && (o.references != 0)) {
0184: // we're keeping it.
0185: newConstants[j] = o;
0186: j += o.nSlots;
0187: }
0188: }
0189: oldConstants = constants;
0190: constants = newConstants;
0191: }
0192:
0193: // write constants back out, just like we read them in.
0194: void writeConstantPool(DataOutput out) throws IOException {
0195: int num = constants == null ? 0 : constants.length;
0196: if (verbose) {
0197: log.println(Localizer.getString(
0198: "classinfo.writing_constant_pool_entries", Integer
0199: .toString(num)));
0200: }
0201: out.writeShort(num);
0202: for (int i = 1; i < num; i += constants[i].nSlots) {
0203: constants[i].write(out);
0204: }
0205: }
0206:
0207: // Read the list of interfaces this class supports
0208: void readInterfaces(DataInput in) throws IOException {
0209: int count = in.readUnsignedShort();
0210: if (verbose) {
0211: log.println(Localizer.getString(
0212: "classinfo.reading_interfaces_implemented", Integer
0213: .toString(count)));
0214: }
0215: interfaces = new ClassConstant[count];
0216: for (int i = 0; i < count; i++) {
0217: //interfaces[i] = (ClassConstant) symbols[in.readUnsignedShort()];
0218: // interfaces not external -- they use own constant pool!
0219: interfaces[i] = (ClassConstant) constants[in
0220: .readUnsignedShort()];
0221: }
0222: }
0223:
0224: void externalizeInterfaces(ConstantPool p) {
0225: int count = interfaces == null ? 0 : interfaces.length;
0226: if (verbose) {
0227: log
0228: .println(Localizer
0229: .getString("classinfo.>>>externalizing_interfaces_implemented"));
0230: }
0231: for (int i = 0; i < count; i++) {
0232: interfaces[i] = (ClassConstant) p.dup(interfaces[i]);
0233: }
0234: }
0235:
0236: void writeInterfaces(DataOutput out) throws IOException {
0237: int count = interfaces == null ? 0 : interfaces.length;
0238: if (verbose) {
0239: log.println(Localizer.getString(
0240: "classinfo.writing_interfaces_implemented", Integer
0241: .toString(count)));
0242: }
0243: out.writeShort(count);
0244: for (int i = 0; i < count; i++) {
0245: out.writeShort(interfaces[i].index);
0246: }
0247: }
0248:
0249: // Read the list of fields
0250: void readFields(DataInput in) throws IOException {
0251: int count = in.readUnsignedShort();
0252: fields = new FieldInfo[count];
0253: if (verbose) {
0254: log.println(Localizer.getString(
0255: "classinfo.reading_field_members", Integer
0256: .toString(count)));
0257: }
0258:
0259: for (int i = 0; i < count; i++) {
0260: fields[i] = FieldInfo.readField(in, this );
0261: fields[i].index = i;
0262: }
0263: }
0264:
0265: void externalizeFields(ConstantPool p) {
0266: int count = fields == null ? 0 : fields.length;
0267: if (verbose) {
0268: log
0269: .println(Localizer
0270: .getString("classinfo.>>>externalizing_field_members"));
0271: }
0272: for (int i = 0; i < count; i++) {
0273: fields[i].externalize(p);
0274: }
0275: }
0276:
0277: void writeFields(DataOutput out) throws IOException {
0278: int count = fields == null ? 0 : fields.length;
0279: if (verbose) {
0280: log.println(Localizer.getString(
0281: "classinfo.writing_field_members", Integer
0282: .toString(count)));
0283: }
0284: out.writeShort(count);
0285: for (int i = 0; i < count; i++) {
0286: fields[i].write(out);
0287: }
0288: }
0289:
0290: // Read the list of methods from classfile
0291: void readMethods(DataInput in, boolean readCode) throws IOException {
0292: int count = in.readUnsignedShort();
0293: methods = new MethodInfo[count];
0294:
0295: if (verbose) {
0296: log.println(Localizer.getString(
0297: "classinfo.reading_methods", Integer
0298: .toString(count)));
0299: }
0300: for (int i = 0; i < count; i++) {
0301: methods[i] = MethodInfo.readMethod(in, this , readCode);
0302: methods[i].index = i;
0303: }
0304: }
0305:
0306: void externalizeMethods(ConstantPool p) {
0307: int count = methods == null ? 0 : methods.length;
0308: if (verbose) {
0309: log.println(Localizer
0310: .getString("classinfo.>>>externalizing_methods"));
0311: }
0312: for (int i = 0; i < count; i++) {
0313: methods[i].externalize(p);
0314: }
0315: }
0316:
0317: void writeMethods(DataOutput out) throws IOException {
0318: int count = methods == null ? 0 : methods.length;
0319: if (verbose) {
0320: log.println(Localizer.getString(
0321: "classinfo.writing_methods", Integer
0322: .toString(count)));
0323: }
0324: out.writeShort(count);
0325: for (int i = 0; i < count; i++) {
0326: methods[i].write(out);
0327: }
0328: }
0329:
0330: void readAttributes(DataInput in) throws IOException {
0331: int count = in.readUnsignedShort();
0332: Vector clssAttr = new Vector();
0333:
0334: if (verbose) {
0335: log.println(Localizer.getString(
0336: "classinfo.reading_attributes", Integer
0337: .toString(count)));
0338: }
0339:
0340: for (int i = 0; i < count; i++) {
0341: int nameIndex = in.readUnsignedShort();
0342: int bytes = in.readInt();
0343: UnicodeConstant name = (UnicodeConstant) symbols[nameIndex];
0344: if (name.string.equals(/*NOI18N*/"fieldtable")) {
0345: fieldtableName = name;
0346: if (verbose) {
0347: log.println(Localizer.getString(
0348: "classinfo.reading_name", name));
0349: }
0350: int n = bytes / 2;
0351: refFieldtable = new FieldConstant[n];
0352: for (int j = 0; j < n; j++) {
0353: refFieldtable[j] = (FieldConstant) symbols[in
0354: .readUnsignedShort()];
0355: }
0356: } else if (name.string.equals(/*NOI18N*/"methodtable")) {
0357: methodtableName = name;
0358: if (verbose) {
0359: log.println(Localizer.getString(
0360: "classinfo.reading_name", name));
0361: }
0362: int n = bytes / 2;
0363: refMethodtable = new MethodConstant[n];
0364: for (int j = 0; j < n; j++) {
0365: refMethodtable[j] = (MethodConstant) symbols[in
0366: .readUnsignedShort()];
0367: }
0368: } else if (name.string.equals(/*NOI18N*/"SourceFile")) {
0369: if (ClassInfo.classDebug) {
0370: UnicodeConstant srcName = (UnicodeConstant) symbols[in
0371: .readUnsignedShort()];
0372: sourceFileAttr = new SourceFileAttribute(name,
0373: bytes, srcName);
0374: clssAttr.addElement(sourceFileAttr);
0375: } else {
0376: byte[] b = new byte[bytes];
0377: in.readFully(b);
0378: clssAttr.addElement(new UninterpretedAttribute(
0379: name, bytes, b));
0380: }
0381: } else {
0382: byte[] b = new byte[bytes];
0383: in.readFully(b);
0384: clssAttr.addElement(new UninterpretedAttribute(name,
0385: bytes, b));
0386: }
0387: }
0388: int nattr = clssAttr.size();
0389: if (nattr > 0) {
0390: this .classAttributes = new Attribute[nattr];
0391: clssAttr.copyInto(classAttributes);
0392: }
0393: }
0394:
0395: void externalizeAttributes(ConstantPool p) {
0396: Attribute.externalizeAttributes(classAttributes, p);
0397: }
0398:
0399: public void allocateFieldsFromFieldtable() {
0400: if (refFieldtable == null)
0401: return; // no can do.
0402:
0403: int n = refFieldtable.length;
0404: int nsuper ;
0405: int fieldoff = 0;
0406: nsuper = (super ClassInfo == null) ? 0
0407: : super ClassInfo.refFieldtable.length;
0408: if (nsuper == 0) {
0409: fieldoff = 0;
0410: } else {
0411: FieldInfo f = refFieldtable[nsuper - 1].find();
0412: if (f.instanceOffset < 0) {
0413: super ClassInfo.allocateFieldsFromFieldtable();
0414: }
0415: fieldoff = f.instanceOffset + f.nSlots;
0416: }
0417: for (int i = nsuper ; i < n; i++) {
0418: FieldInfo f = refFieldtable[i].find();
0419: if (f == null) {
0420: // this is not supposed to happen.
0421: System.out.println(Localizer
0422: .getString("classinfo.cannot_find_field",
0423: refFieldtable[i]));
0424: continue;
0425: }
0426: f.instanceOffset = fieldoff;
0427: fieldoff += f.nSlots;
0428: }
0429: //
0430: // and while we're here, do methodtable as well.
0431: //
0432: n = refMethodtable.length;
0433: int methodoff = 0; // 1=>0 EJVM
0434:
0435: for (int i = 0; i < n; i++) {
0436: MethodInfo m = refMethodtable[i].find();
0437:
0438: if (m == null) {
0439: // this is not supposed to happen.
0440: System.out.println(Localizer.getString(
0441: "classinfo.cannot_find_field",
0442: refMethodtable[i]));
0443: continue;
0444: } else if (m.methodTableIndex != methodoff) {
0445: if (m.parent != this ) {
0446: // this method is in a superclass.
0447: // which apparently hasn't set up its methodtable yet.
0448: // so go do it.
0449: super ClassInfo.allocateFieldsFromFieldtable();
0450: } else {
0451: // we do it here.?
0452: System.out
0453: .println("Inconsistent refMethodtable in class "
0454: + this .toString());
0455: m.methodTableIndex = methodoff;
0456: }
0457: }
0458: methodoff += 1;
0459: }
0460: }
0461:
0462: void writeTableAttribute(DataOutput out, UnicodeConstant name,
0463: FMIrefConstant table[]) throws IOException {
0464: if (verbose) {
0465: log.println(Localizer.getString("classinfo.writing_name",
0466: name.string));
0467: }
0468: out.writeShort(name.index);
0469: int n = table.length;
0470: out.writeInt(2 * n);
0471: for (int i = 0; i < n; i++) {
0472: out.writeShort(table[i].index);
0473: }
0474: }
0475:
0476: void writeAttributes(DataOutput out) throws IOException {
0477: int count = 0;
0478: if (fieldtableName != null)
0479: count++;
0480: if (methodtableName != null)
0481: count++;
0482:
0483: if (classAttributes != null) {
0484: count += classAttributes.length;
0485: }
0486: out.writeShort(count);
0487:
0488: if (fieldtableName != null) {
0489: writeTableAttribute(out, fieldtableName, refFieldtable);
0490: }
0491: if (methodtableName != null) {
0492: writeTableAttribute(out, methodtableName, refMethodtable);
0493: }
0494: if (classAttributes != null) {
0495: for (int k = 0; k < classAttributes.length; k++) {
0496: classAttributes[k].write(out);
0497: }
0498: }
0499: }
0500:
0501: // Read in the entire class
0502: // assume file is open, magic numbers are o.k.
0503: // read assumes reading from class file
0504: //
0505: private void doRead(DataInput in, boolean readCode,
0506: ConstantPool externalSymbols) throws IOException {
0507:
0508: externalPool = externalSymbols; // for convenience, later
0509: resolveConstants();
0510:
0511: access = in.readUnsignedShort();
0512: this Class = (ClassConstant) symbols[in.readUnsignedShort()];
0513: int sup = in.readUnsignedShort();
0514: if (sup != 0)
0515: super Class = (ClassConstant) symbols[sup];
0516: className = this Class.name.string;
0517:
0518: // Read the various parts of the class file
0519: readInterfaces(in);
0520: readFields(in);
0521: readMethods(in, readCode);
0522: readAttributes(in);
0523: enterClass(className);
0524: }
0525:
0526: public void read(DataInput in, boolean readCode,
0527: ConstantPool externalSymbols) throws IOException {
0528: readConstantPool(in);
0529: symbols = constants; // symbol table == constant pool
0530: doRead(in, readCode, externalSymbols);
0531: }
0532:
0533: public void externalize(ConstantPool p) {
0534: if (verbose) {
0535: log.println(Localizer.getString(
0536: "classinfo.externalizing_class", className));
0537: }
0538: externalizeConstants(p);
0539: this Class = (ClassConstant) p.dup(this Class);
0540: //thisClass.externalize(p);//redundant?
0541: if (super Class != null) {
0542: super Class = (ClassConstant) p.dup(super Class);
0543: //superClass.externalize(p);//redundant?
0544: }
0545: //externalizeInterfaces( p ); // interfaces NOT externalized!
0546: externalizeMethods(p);
0547: externalizeFields(p);
0548: externalizeAttributes(p);
0549: }
0550:
0551: // Compute the fieldtable for a class. This requires laying
0552: // out the fieldtable for our parent, then adding any fields
0553: // that are not inherited.
0554: public void buildFieldtable(ConstantPool cp) {
0555: if (this .fieldtable != null)
0556: return; // already done.
0557: FieldInfo fieldtable[];
0558: int n;
0559: int fieldoff;
0560: int fieldtableLength = 0;
0561: FieldInfo candidate[] = this .fields;
0562: for (int i = 0; i < candidate.length; i++) {
0563: if ((candidate[i].access & Const.ACC_STATIC) == 0) {
0564: fieldtableLength++;
0565: }
0566: }
0567: if (super ClassInfo != null) {
0568: super ClassInfo.buildFieldtable(cp);
0569: n = super ClassInfo.fieldtable.length;
0570: fieldtableLength += n;
0571: fieldoff = (n == 0) ? 0
0572: : (super ClassInfo.fieldtable[n - 1].instanceOffset + super ClassInfo.fieldtable[n - 1].nSlots);
0573: fieldtable = new FieldInfo[fieldtableLength];
0574: System.arraycopy(super ClassInfo.fieldtable, 0, fieldtable,
0575: 0, n);
0576: } else {
0577: fieldtable = new FieldInfo[fieldtableLength];
0578: n = 0;
0579: fieldoff = 0;
0580: }
0581: for (int i = 0; i < candidate.length; i++) {
0582: if ((candidate[i].access & Const.ACC_STATIC) == 0) {
0583: fieldtable[n++] = candidate[i];
0584: candidate[i].instanceOffset = fieldoff;
0585: fieldoff += candidate[i].nSlots;
0586: }
0587: }
0588: this .fieldtable = fieldtable;
0589: //
0590: // here, we make the gross assumption that
0591: // if we're building a fieldtable, we're using a shared
0592: // external Constant Pool
0593: fieldtableName = (UnicodeConstant) cp.add(new UnicodeConstant(
0594: /*NOI18N*/"fieldtable"));
0595:
0596: }
0597:
0598: private FMIrefConstant buildReference(ClassMemberInfo m,
0599: boolean isMethod, ConstantPool cp) {
0600: ClassConstant c = (ClassConstant) cp.dup(m.parent.this Class);
0601: FMIrefConstant x;
0602: NameAndTypeConstant n = (NameAndTypeConstant) cp
0603: .add(new NameAndTypeConstant((UnicodeConstant) cp
0604: .add(m.name), (UnicodeConstant) cp.add(m.type)));
0605: if (isMethod) {
0606: x = new MethodConstant(c, n);
0607: } else {
0608: x = new FieldConstant(c, n);
0609: }
0610: return (FMIrefConstant) cp.add(x);
0611: }
0612:
0613: public void buildReferenceFieldtable(ConstantPool cp) {
0614: if (refFieldtable != null)
0615: return; // already done, it says here.
0616: if (fieldtableName == null) {
0617: fieldtableName = (UnicodeConstant) cp
0618: .add(new UnicodeConstant(/*NOI18N*/"fieldtable"));
0619: }
0620: buildFieldtable(cp);
0621: int n = fieldtable.length;
0622: refFieldtable = new FieldConstant[n];
0623: for (int i = 0; i < n; i++) {
0624: refFieldtable[i] = (FieldConstant) buildReference(
0625: fieldtable[i], false, cp);
0626: }
0627: }
0628:
0629: // Compute the method table for a class. This requires laying
0630: // out the method table for our parent, then adding any methods
0631: // that are not inherited.
0632: public void buildMethodtable(ConstantPool cp) {
0633: if (this .methodtable != null)
0634: return; // already done.
0635: MethodInfo table[];
0636: MethodInfo methods[] = this .methods;
0637: ClassInfo sup = super ClassInfo;
0638: if ((sup != null)
0639: && ((sup.access & Const.ACC_INTERFACE) == (this .access & Const.ACC_INTERFACE))) {
0640: sup.buildMethodtable(cp);
0641: table = sup.methodtable;
0642: } else {
0643: table = new MethodInfo[0];
0644: }
0645:
0646: // allocate a temporary table that is certainly large enough.
0647: MethodInfo newTable[] = new MethodInfo[table.length
0648: + methods.length];
0649: int index = table.length;
0650: System.arraycopy(table, 0, newTable, 0, index);
0651:
0652: if (sup == null) {
0653: // finalize() goes into slot 0 of java.lang.Object
0654: // FY: Removed for KVM. We have no finalize() in slot 0.
0655: // index++;
0656: }
0657:
0658: method_loop: for (int i = 0; i < methods.length; i++) {
0659: if ((methods[i].access & (Const.ACC_STATIC | Const.ACC_PRIVATE)) != 0) {
0660: continue method_loop;
0661: } else if (methods[i].name.string
0662: .equals(/*NOI18N*/"<init>")) {
0663: continue method_loop;
0664: } else if (sup == null
0665: && methods[i].name.string
0666: .equals(/*NOI18N*/"finalize")
0667: && methods[i].type.string.equals(/*NOI18N*/"()V")) {
0668: newTable[0] = methods[i];
0669: newTable[0].methodTableIndex = 0; // 1=>0 EJVM
0670: continue method_loop;
0671: }
0672: int j;
0673: int this ID = methods[i].getID();
0674: for (j = 0; j < table.length; j++) {
0675: if (this ID == table[j].getID()) {
0676: newTable[j] = methods[i];
0677: newTable[j].methodTableIndex = j + 0; // 1=>0 EJVM
0678: continue method_loop;
0679: }
0680: }
0681: // If we're not overriding our parent's method we do add
0682: // a new entry to the method table.
0683: newTable[index] = methods[i];
0684: newTable[index].methodTableIndex = index + 0; // 1=>0 EJVM
0685: index++;
0686: }
0687:
0688: // now allocate a table of the correct size.
0689: MethodInfo methodTable[] = new MethodInfo[index];
0690: System.arraycopy(newTable, 0, methodTable, 0, index);
0691:
0692: this .methodtable = methodTable;
0693: //
0694: // here, we make the gross assumption that
0695: // if we're building a methodtable, we're using a shared
0696: // external Constant Pool
0697: methodtableName = (UnicodeConstant) cp.add(new UnicodeConstant(
0698: /*NOI18N*/"methodtable"));
0699: }
0700:
0701: public void buildReferenceMethodtable(ConstantPool cp) {
0702: if (refMethodtable != null)
0703: return; // already done, it says here.
0704: if (methodtableName == null) {
0705: methodtableName = (UnicodeConstant) cp
0706: .add(new UnicodeConstant(/*NOI18N*/"methodtable"));
0707: }
0708: buildMethodtable(cp);
0709: int n = methodtable.length;
0710: refMethodtable = new MethodConstant[n];
0711: for (int i = 0; i < n; i++) {
0712: refMethodtable[i] = (MethodConstant) buildReference(
0713: methodtable[i], true, cp);
0714: }
0715: }
0716:
0717: private static boolean conditionalAdd(Vector v, Object o) {
0718: if (v.contains(o))
0719: return false;
0720: v.addElement(o);
0721: return true;
0722: }
0723:
0724: /*
0725: * Compute the vector of all interfaces this class implements (or
0726: * this interface extends). Not only the interfaced declared in
0727: * the implements clause, which is what the interfaces[] field
0728: * represents, but all interfaces, including those of our superclasses
0729: * and those extended/implemented by any interfaces we implement.
0730: *
0731: */
0732: public void findAllInterfaces() {
0733: /*
0734: * This works recursively, by computing parent's interface
0735: * set first. THIS ASSUMES NON-CIRCULARITY, as does the rest
0736: * of the Java system. This assumption will fail loudly, if
0737: * at all.
0738: */
0739: if (super ClassInfo == null) {
0740: // we must be java.lang.Object!
0741: allInterfaces = new Vector(5); // a generous size.
0742: } else {
0743: if (super ClassInfo.allInterfaces == null)
0744: super ClassInfo.findAllInterfaces();
0745: allInterfaces = (Vector) (super ClassInfo.allInterfaces
0746: .clone());
0747: }
0748: if (interfaces == null)
0749: return; // all done!
0750: for (int i = 0; i < interfaces.length; i++) {
0751: ClassInfo interf = interfaces[i].find();
0752: if ((interf == null)
0753: || ((interf.access & Const.ACC_INTERFACE) == 0)) {
0754: System.err
0755: .println(Localizer
0756: .getString(
0757: "classinfo.class_which_should_be_an_interface_but_is_not",
0758: className, interfaces[i]));
0759: continue;
0760: }
0761: if (interf.allInterfaces == null)
0762: interf.findAllInterfaces();
0763: if (!conditionalAdd(allInterfaces, interf)) {
0764: // if this interface was already in the set,
0765: // then all the interfaces that it extend/implement
0766: // will be, too.
0767: continue;
0768: }
0769: Enumeration interfInterf = interf.allInterfaces.elements();
0770: while (interfInterf.hasMoreElements()) {
0771: conditionalAdd(allInterfaces, interfInterf
0772: .nextElement());
0773: }
0774: }
0775: }
0776:
0777: public boolean findReferences() {
0778: try {
0779: for (int i = 0; i < methods.length; i++) {
0780: methods[i].findConstantReferences();
0781: }
0782: } catch (DataFormatException e) {
0783: return false;
0784: }
0785: return true;
0786: }
0787:
0788: public boolean countReferences(boolean isRelocatable) {
0789: this Class.incReference();
0790: if (super Class != null)
0791: super Class.incReference();
0792: // count interface references
0793: if (interfaces != null) {
0794: for (int i = 0; i < interfaces.length; i++) {
0795: interfaces[i].incReference();
0796: }
0797: }
0798: // then count references from fields.
0799: if (fields != null) {
0800: for (int i = 0; i < fields.length; i++) {
0801: fields[i].countConstantReferences(isRelocatable);
0802: }
0803: }
0804: // then count references from code
0805: if (methods != null) {
0806: for (int i = 0; i < methods.length; i++) {
0807: methods[i].countConstantReferences(constants,
0808: isRelocatable);
0809: }
0810: }
0811: Attribute.countConstantReferences(classAttributes,
0812: isRelocatable);
0813: return true;
0814: }
0815:
0816: public boolean relocateReferences() {
0817: try {
0818: for (int i = 0; i < methods.length; i++) {
0819: methods[i].relocateConstantReferences(oldConstants);
0820: }
0821: } catch (DataFormatException e) {
0822: return false;
0823: }
0824: return true;
0825: }
0826:
0827: public void clearMemberFlags(int flagsToClear) {
0828: int mask = ~flagsToClear;
0829: int n;
0830: ClassMemberInfo members[];
0831: if (fields != null) {
0832: members = fields;
0833: n = members.length;
0834: for (int i = 0; i < n; i++) {
0835: members[i].flags &= mask;
0836: }
0837: }
0838: if (fields != null) {
0839: members = methods;
0840: n = members.length;
0841: for (int i = 0; i < n; i++) {
0842: members[i].flags &= mask;
0843: }
0844: }
0845: }
0846:
0847: public void write(DataOutput o) throws IOException {
0848: writeConstantPool(o);
0849: o.writeShort(access);
0850: o.writeShort(this Class.index);
0851: o.writeShort(super Class == null ? 0 : super Class.index);
0852: writeInterfaces(o);
0853: writeFields(o);
0854: writeMethods(o);
0855: writeAttributes(o);
0856: }
0857:
0858: private static void dumpComponentTable(PrintStream o, String title,
0859: ClassComponent t[]) {
0860: int n;
0861: if ((t == null) || ((n = t.length) == 0))
0862: return;
0863: o.print(title);
0864: o.println(/*NOI18N*/"[" + n + "]:");
0865: for (int i = 0; i < n; i++) {
0866: if (t[i] != null)
0867: o.println(/*NOI18N*/"\t[" + i + /*NOI18N*/"]\t"
0868: + t[i]);
0869: }
0870: }
0871:
0872: private static void dumpConstantTable(PrintStream o, String title,
0873: ConstantObject t[]) {
0874: int n;
0875: if ((t == null) || ((n = t.length) == 0))
0876: return;
0877: o.print(title);
0878: o.println(/*NOI18N*/"[" + n + /*NOI18N*/"]:");
0879: o.println(/*NOI18N*/"\tPosition Index\tNrefs");
0880: for (int i = 0; i < n; i++) {
0881: if (t[i] != null)
0882: o.println(/*NOI18N*/"\t[" + i + /*NOI18N*/"]\t"
0883: + t[i].index + /*NOI18N*/"\t"
0884: + t[i].references + /*NOI18N*/"\t" + t[i]);
0885: }
0886: }
0887:
0888: private static void dumpMemberTable(PrintStream o, String title,
0889: ClassMemberInfo t[]) {
0890: int n;
0891: if ((t == null) || ((n = t.length) == 0))
0892: return;
0893: o.print(title);
0894: o.println(/*NOI18N*/":");
0895: for (int i = 0; i < n; i++) {
0896: if (t[i] != null)
0897: o.println(/*NOI18N*/"\t[" + i + /*NOI18N*/"]\t"
0898: + t[i].qualifiedName());
0899: }
0900: }
0901:
0902: public void dump(PrintStream o) {
0903: o.print(Util.accessToString(access) + /*NOI18N*/"Class "
0904: + this Class);
0905: if (super Class != null)
0906: o.print(/*NOI18N*/" extends " + super Class);
0907: if (interfaces != null && interfaces.length != 0) {
0908: o.print(/*NOI18N*/" implements ");
0909: for (int i = 0; i < interfaces.length; i++) {
0910: o.print(" " + interfaces[i]);
0911: }
0912: }
0913: o.println();
0914: dumpComponentTable(o, /*NOI18N*/"Methods", methods);
0915: dumpComponentTable(o, /*NOI18N*/"Fields", fields);
0916: if (fieldtable != null)
0917: dumpMemberTable(o, /*NOI18N*/"Fieldtable", fieldtable);
0918: else
0919: dumpComponentTable(o, /*NOI18N*/"Fieldtable-by-reference",
0920: refFieldtable);
0921: if (methodtable != null)
0922: dumpMemberTable(o, /*NOI18N*/"Methodtable", methodtable);
0923: else
0924: dumpComponentTable(o, /*NOI18N*/
0925: "Methodtable-by-reference", refMethodtable);
0926: dumpConstantTable(o, /*NOI18N*/"Constants", constants);
0927: }
0928:
0929: /**
0930: * We keep track of classes by hashing them by name when
0931: * we read them. They can be looked up using lookupClass,
0932: * which will take a classname string as parameter.
0933: */
0934: public static Hashtable classtable = new Hashtable();
0935:
0936: protected void enterClass(String key) {
0937: // should check to see if a class of this name is already there...
0938: if (classtable.containsKey(className)) {
0939: System.err.println(Localizer
0940: .getString(
0941: "classinfo.class_table_already_contains",
0942: className));
0943: return;
0944: }
0945: classtable.put(key, this );
0946: // if a classvector has been created, we need to add this.
0947: // at end should be sufficient.
0948: vm.ClassClass.appendClassElement(this );
0949: }
0950:
0951: public static ClassInfo lookupClass(String key) {
0952: return (ClassInfo) classtable.get(key);
0953: }
0954:
0955: public static int nClasses() {
0956: return classtable.size();
0957: }
0958:
0959: public static Enumeration allClasses() {
0960: return classtable.elements();
0961: }
0962:
0963: public static boolean resolveSupers() {
0964: Enumeration allclasses = allClasses();
0965: boolean ok = true;
0966: while (allclasses.hasMoreElements()) {
0967: ClassInfo c = (ClassInfo) allclasses.nextElement();
0968: if (c.super Class == null) {
0969: // only java.lang.Object can be parentless
0970: if (!c.className.equals( /*NOI18N*/"java/lang/Object")) {
0971: System.out.println(Localizer.getString(
0972: "classinfo.class_is_parent-less",
0973: c.className));
0974: ok = false;
0975: }
0976: } else {
0977: ClassInfo s = ClassInfo
0978: .lookupClass(c.super Class.name.string);
0979: if (s == null) {
0980: System.out.println(Localizer.getString(
0981: "classinfo.class_is_missing_parent",
0982: c.className, c.super Class.name.string));
0983: ok = false;
0984: } else {
0985: c.super ClassInfo = s;
0986: }
0987: }
0988: }
0989: return ok;
0990: }
0991:
0992: public String toString() {
0993: return /*NOI18N*/"ClassInfo-\"" + className + /*NOI18N*/"\"";
0994: }
0995:
0996: // Convert ldc to ldc2
0997: public void relocateAndPackCode() {
0998: for (int i = 0; i < methods.length; i++)
0999: methods[i].relocateAndPackCode(constants);
1000: }
1001: }
|