package js.tinyvm; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.ArrayList; import js.tinyvm.io.IByteWriter; import js.tinyvm.io.IOUtilities; import js.tinyvm.util.HashVector; import org.apache.bcel.Constants; import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.Constant; import org.apache.bcel.classfile.ConstantClass; import org.apache.bcel.classfile.ConstantDouble; import org.apache.bcel.classfile.ConstantFloat; import org.apache.bcel.classfile.ConstantInteger; import org.apache.bcel.classfile.ConstantInterfaceMethodref; import org.apache.bcel.classfile.ConstantLong; import org.apache.bcel.classfile.ConstantMethodref; import org.apache.bcel.classfile.ConstantNameAndType; import org.apache.bcel.classfile.ConstantPool; import org.apache.bcel.classfile.ConstantString; import org.apache.bcel.classfile.Field; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; /** * Abstraction for a class record (see vmsrc/language.h). */ public class ClassRecord implements WritableData { int iIndex = -1; String iName; /** * On-demand size of the class. */ int iClassSize = -1; JavaClass iCF; Binary iBinary; RecordTable<MethodRecord> iMethodTable = new RecordTable<MethodRecord>("methods", false, false); final RecordTable<InstanceFieldRecord> iInstanceFields = new RecordTable<InstanceFieldRecord>("instance fields", true, false); final HashMap<String, StaticValue> iStaticValues = new HashMap<String, StaticValue>(); final HashMap<String, StaticFieldRecord> iStaticFields = new HashMap<String, StaticFieldRecord>(); HashMap<Signature, MethodRecord> iMethods = new HashMap<Signature, MethodRecord>(); final ArrayList<String> iUsedMethods = new ArrayList<String>(); InterfaceMap iInterfaceMap; int iParentClassIndex; ClassRecord iArrayElementClass; int iNumDims; TinyVMType iType; int iFlags; boolean iUseAllMethods = false; boolean isInstanceUsed = false; HashSet<ClassRecord> iImplementedBy = new HashSet<ClassRecord>(); boolean isUsed = false; static final String[] wrappers = {"java/lang/Integer", "java/lang/Boolean", "java/lang/Character", "java/lang/Float", "java/lang/Byte", "java/lang/Short", "java/lang/Double", "java/lang/Long", "java/lang/Void" }; static final String[] primitive = {"int", "boolean", "char", "float", "byte", "short", "double", "long", "void" }; public void useAllMethods () { iUseAllMethods = true; } public String getName () { return iCF.getClassName(); } public int getLength () { return IOUtilities.adjustedSize(2 + // Object header 2 + // class size 2 + // method table offset 2 + // instance field table offset 1 + // number of fields 1 + // number of methods 1 + // parent class 1, // flags 2); } public void dump (IByteWriter aOut) throws TinyVMException { try { int classIndex = iBinary.getClassIndex("java/lang/Class"); aOut.writeU2(TinyVMConstants.OBJ_HEADER | classIndex); int pAllocSize = getAllocationSize(); assert pAllocSize != 0: "Check: alloc ok"; aOut.writeU2(pAllocSize); if (isArray()) { aOut.writeU2(iNumDims); aOut.writeU2(iBinary.getClassIndex(iArrayElementClass)); aOut.writeU1(0); aOut.writeU1(0); } else if (isInterface()) { aOut.writeU2(iInterfaceMap.getOffset()); aOut.writeU2(iInterfaceMap.getFirst()); aOut.writeU1(iInterfaceMap.getSize()); aOut.writeU1(0); } else { // Normal class record int pMethodTableOffset = iMethodTable.getOffset(); aOut.writeU2(pMethodTableOffset); aOut.writeU2(iInstanceFields.getOffset()); int pNumMethods = iMethodTable.size(); if (pNumMethods > TinyVMConstants.MAX_METHODS) { throw new TinyVMException("Class " + iName + ": No more than " + TinyVMConstants.MAX_METHODS + " methods expected"); } aOut.writeU1(pNumMethods); int pNumFields = iInstanceFields.size(); if (pNumFields > TinyVMConstants.MAX_FIELDS) { throw new TinyVMException("Class " + iName + ": No more than " + TinyVMConstants.MAX_FIELDS + " fields expected"); } aOut.writeU1(pNumFields); } aOut.writeU1(iParentClassIndex); //aOut.writeU1 (iArrayElementType); aOut.writeU1(iFlags | (hasReference() ? 0 : TinyVMConstants.C_NOREFS)); IOUtilities.writePadding(aOut, 2); } catch (IOException e) { throw new TinyVMException(e.getMessage(), e); } } public boolean isArray () { return iNumDims != 0; } public boolean isInterface () { return iCF.isInterface(); } public boolean isPrimitive() { return this.iType != TinyVMType.T_REFERENCE; } public boolean hasStaticInitializer () { Method[] methods = iCF.getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals(Constants.STATIC_INITIALIZER_NAME)) { return true; } } return false; } /** * (Call only after record has been processed). * @param aSignature * @param aStatic * @return */ public boolean hasMethod (Signature aSignature, boolean aStatic) { MethodRecord pRec = iMethods.get(aSignature); if (pRec == null) return false; return ((pRec.getFlags() & TinyVMConstants.M_STATIC) == 0) ^ aStatic; } public void initFlags () { iFlags = 0; if (isArray()) iFlags |= TinyVMConstants.C_ARRAY; if (isInterface()) iFlags |= TinyVMConstants.C_INTERFACE; if (hasStaticInitializer()) iFlags |= TinyVMConstants.C_HASCLINIT; if (isPrimitive()) iFlags |= TinyVMConstants.C_PRIMITIVE; } /** * @return Number of bytes required for object allocation. * @throws TinyVMException */ public int getAllocationSize () throws TinyVMException { return (getClassSize() + 4); } /** * @return Number of bytes occupied by instance fields. * @throws TinyVMException */ public int getClassSize () throws TinyVMException { if (iClassSize != -1) return iClassSize; iClassSize = computeClassSize(); return iClassSize; } /** * @return The size of the class in bytes, including any VM space. * This is the exact size required for memory allocation. * @throws TinyVMException */ public int computeClassSize () throws TinyVMException { int pSize = hasParent()? getParent().getClassSize() : 0; for (Iterator<InstanceFieldRecord> iter = iInstanceFields.iterator(); iter.hasNext();) { InstanceFieldRecord pRec = iter.next(); pSize += pRec.getFieldSize(); } return pSize; } public boolean hasReference() throws TinyVMException { if (hasParent() && getParent().hasReference()) return true; for (Iterator<InstanceFieldRecord> iter = iInstanceFields.iterator(); iter.hasNext();) { InstanceFieldRecord pRec = iter.next(); if (pRec.iType.type() == TinyVMType.T_REFERENCE_TYPE) return true; } return false; } public boolean hasParent () { return !"java.lang.Object".equals(iCF.getClassName()); } public ClassRecord getParent () { assert hasParent(): "Precondition: hasParent()"; ClassRecord result = iBinary.getClassRecord(iCF.getSuperclassName().replace('.', '/')); assert result != null: "Postconditon: result != null"; return result; } public void initParent () throws TinyVMException { if (hasParent()) { iParentClassIndex = iBinary.getClassIndex(getParent()); if (iParentClassIndex == -1) { throw new TinyVMException("Superclass of " + iCF.getClassName() + " not found"); } } else // only java.lang.Object has no super class... { iParentClassIndex = 0; if (!iCF.getClassName().equals("java.lang.Object")) { throw new TinyVMException("Expected java.lang.Object: " + iCF.getClassName()); } } } public static String getArrayClassName(String aName) { //System.out.println("process array name " + aName); int i = 0; while (aName.charAt(i) == '[') i++; TinyVMType typ = TinyVMType.tinyVMTypeFromSignature(aName.substring(i)); // if it is an object we return the name, otherwise we return null if (typ == TinyVMType.T_OBJECT || typ == TinyVMType.T_REFERENCE) return aName.substring(i+1, aName.length()-1); else return typ.cname(); } static ClassRecord storeArrayClass(String className, HashMap<String, ClassRecord> aClasses, RecordTable<ClassRecord> aClassRecords, ClassPath classPath, Binary iBinary) throws TinyVMException { // find the number of dims int dims = 0; while(className.charAt(dims) == '[') dims++; String elementClassName = getArrayClassName(className); ClassRecord crec = aClasses.get(elementClassName); if (crec == null) { crec = ClassRecord.getClassRecord(elementClassName, classPath, iBinary); aClasses.put(elementClassName, crec); aClassRecords.add(crec); } for(int i = dims-1; i >= 0; i--) { String name = className.substring(i); ClassRecord pRec = aClasses.get(name); if (pRec == null) { pRec = PrimitiveClassRecord.getArrayClassRecord(name, iBinary, dims-i, crec); aClasses.put(name, pRec); aClassRecords.add(pRec); } crec = pRec; } return crec; } public void storeReferredClasses (HashMap<String, ClassRecord> aClasses, RecordTable<ClassRecord> aClassRecords, ClassPath aClassPath, ArrayList<String> aInterfaceMethods) throws TinyVMException { // _logger.log(Level.INFO, "Processing CONSTANT_Class entries in " + // iName); ConstantPool pPool = iCF.getConstantPool(); Constant[] constants = pPool.getConstantPool(); for (int i = 0; i < constants.length; i++) { Constant pEntry = constants[i]; if (pEntry instanceof ConstantClass) { String pClassName = ((ConstantClass) pEntry).getBytes(pPool); if (aClasses.get(pClassName) == null) { if (pClassName.startsWith("[")) storeArrayClass(pClassName, aClasses, aClassRecords, aClassPath, iBinary); else if (aClasses.get(pClassName) == null) { ClassRecord pRec = ClassRecord.getClassRecord(pClassName, aClassPath, iBinary); aClasses.put(pClassName, pRec); aClassRecords.add(pRec); } } } else if (pEntry instanceof ConstantMethodref) { String className = ((ConstantMethodref) pEntry).getClass(pPool) .replace('.', '/'); ClassRecord pClassRec = aClasses.get(className); if (pClassRec == null) { if (className.startsWith("[")) pClassRec = storeArrayClass(className, aClasses, aClassRecords, aClassPath, iBinary); else { pClassRec = ClassRecord.getClassRecord(className, aClassPath, iBinary); aClasses.put(className, pClassRec); aClassRecords.add(pClassRec); } } ConstantNameAndType cnat = (ConstantNameAndType) iCF .getConstantPool().getConstant( ((ConstantMethodref) pEntry).getNameAndTypeIndex()); pClassRec.addUsedMethod(cnat.getName(iCF.getConstantPool()) + ":" + cnat.getSignature(iCF.getConstantPool())); } else if (pEntry instanceof ConstantInterfaceMethodref) { ConstantNameAndType cnat = (ConstantNameAndType) iCF .getConstantPool().getConstant( ((ConstantInterfaceMethodref) pEntry).getNameAndTypeIndex()); aInterfaceMethods.add(cnat.getName(iCF.getConstantPool()) + ":" + cnat.getSignature(iCF.getConstantPool())); } else if (pEntry instanceof ConstantNameAndType) { //System.out.println("N&T: " + ((ConstantNameAndType) pEntry).getName(iCF.getConstantPool()) + " sig " + ((ConstantNameAndType) pEntry).getSignature( //iCF.getConstantPool())); String sig = ((ConstantNameAndType) pEntry).getSignature(iCF.getConstantPool()); if (sig.charAt(0) == '[') storeArrayClass(sig, aClasses, aClassRecords, aClassPath, iBinary); else if (sig.substring(0, 1).equals("(")) { if (!((ConstantNameAndType) pEntry).getName( iCF.getConstantPool()).substring(0, 1).equals("<")) { aInterfaceMethods.add(((ConstantNameAndType) pEntry) .getName(iCF.getConstantPool()) + ":" + sig); } } } } } public void addUsedMethod (String aRef) { iUsedMethods.add(aRef); } public static String cpEntryId (Constant aEntry) { String pClassName = aEntry.getClass().getName(); int pDotIdx = pClassName.lastIndexOf('.'); return pDotIdx == -1? pClassName : pClassName.substring(pDotIdx + 1); } MethodRecord getMethodRecord (Signature aSig) { return iMethods.get(aSig); } MethodRecord getActualVirtualMethodRecord (Signature aSig) { MethodRecord pRec = getMethodRecord(aSig); if (pRec != null) return pRec; if (!hasParent()) { return null; } return getParent().getActualVirtualMethodRecord(aSig); } MethodRecord getVirtualMethodRecord (Signature aSig) { /* Search for all methods that may be implemented by this class (including * interfaces and parent classes. */ MethodRecord pRec = getInterfaceMethodRecord(aSig); if (pRec != null) return pRec; if (!hasParent()) { return null; } return getParent().getVirtualMethodRecord(aSig); } MethodRecord getInterfaceMethodRecord (Signature aSig) { /* Search for a method defined by an interface. First search the current * interface then search all super interfaces. */ MethodRecord pRec = getMethodRecord(aSig); if (pRec != null) return pRec; String []interfaces = iCF.getInterfaceNames(); if (interfaces == null) return null; for(int i = 0; i < interfaces.length; i++) { // _logger.log(Level.INFO, "Interface name " + interfaces[i]); ClassRecord pInterfaceRecord = iBinary.getClassRecord(interfaces[i].replace('.', '/')); pRec = pInterfaceRecord.getInterfaceMethodRecord(aSig); if (pRec != null) return pRec; } return null; } int getMethodIndex (MethodRecord aRecord) { return iMethodTable.indexOf(aRecord); } int getApparentInstanceFieldOffset (String aName) throws TinyVMException { /* Locate the record for the field called aName starting at the current * class and if needed searching parent fields. When found return the * offset of the field within the current class. */ int pOffset = hasParent()? getParent().getClassSize() : 0; for (Iterator<InstanceFieldRecord> iter = iInstanceFields.iterator(); iter.hasNext();) { InstanceFieldRecord pRec = iter.next(); if (pRec.getName().equals(aName)) return pOffset; pOffset += pRec.getFieldSize(); } if (hasParent()) return getParent().getApparentInstanceFieldOffset(aName); return -1; } public int getInstanceFieldOffset (String aName) throws TinyVMException { int offset = getApparentInstanceFieldOffset(aName); if (offset < 0) return offset; // Return the offset allowing for the class header. return offset + 4; } /** * @param aName * @return Offset relative to the start of the static state block. * @throws TinyVMException */ public int getStaticFieldOffset (String aName) throws TinyVMException { StaticValue pValue = iStaticValues.get(aName); if (pValue == null) return -1; return pValue.getOffset() - iBinary.iStaticState.getOffset(); } /** * @param aName the name of the static field. * @return The StaticValue for the given name * @throws TinyVMException */ public StaticValue getStaticValue (String aName) throws TinyVMException { return iStaticValues.get(aName); } public int getStaticFieldIndex (String aName) { StaticFieldRecord pRecord = iStaticFields.get(aName); if (pRecord == null) return -1; // TBD: This indexOf call is slow return iBinary.iStaticFields.indexOf(pRecord); } public StaticFieldRecord getStaticFieldRecord(String aName) { /* Locate the record for the static field call aName. First search the * current class, then if it is not found examine any interfaces and * parent classes. */ // First look to see if it is local StaticFieldRecord pRec = iStaticFields.get(aName); if (pRec != null) return pRec; // now search any interfaces String []interfaces = iCF.getInterfaceNames(); if (interfaces != null) for(int i = 0; i < interfaces.length; i++) { ClassRecord pInterfaceRecord = iBinary.getClassRecord(interfaces[i].replace('.', '/')); pRec = pInterfaceRecord.getStaticFieldRecord(aName); if (pRec != null) return pRec; } // Now try any parent class if (hasParent()) return getParent().getStaticFieldRecord(aName); return null; } public void storeConstants (RecordTable<ConstantRecord> aConstantTable, RecordTable<ConstantValue> aConstantValues) throws TinyVMException { // _logger.log(Level.INFO, "Processing other constants in " + iName); ConstantPool pPool = iCF.getConstantPool(); Constant[] constants = pPool.getConstantPool(); for (int i = 0; i < constants.length; i++) { Constant pEntry = constants[i]; if (pEntry instanceof ConstantString || pEntry instanceof ConstantDouble || pEntry instanceof ConstantFloat || pEntry instanceof ConstantInteger || pEntry instanceof ConstantLong || pEntry instanceof ConstantClass) { ConstantRecord pRec = new ConstantRecord(pPool, pEntry, iBinary); if (aConstantTable.indexOf(pRec) == -1) { aConstantTable.add(pRec); aConstantValues.add(pRec.constantValue()); } } } } public void storeMethods (RecordTable<RecordTable<MethodRecord>> aMethodTables, RecordTable<RecordTable<ExceptionRecord>> aExceptionTables, HashVector<Signature> aSignatures, boolean aAll) throws TinyVMException { // _logger.log(Level.INFO, "Processing methods in " + iName); Method[] methods = iCF.getMethods(); for (int i = 0; i < methods.length; i++) { Method pMethod = methods[i]; Signature pSignature = new Signature(pMethod.getName(), pMethod .getSignature()); String meth = pMethod.getName() + ":" + pMethod.getSignature(); if (aAll || iUseAllMethods || iUsedMethods.indexOf(meth) >= 0 || pMethod.getName().substring(0, 1).equals("<") || meth.equals("run:()V")) { MethodRecord pMethodRecord = new MethodRecord(pMethod, pSignature, this, iBinary, aExceptionTables, aSignatures); iMethodTable.add(pMethodRecord); iMethods.put(pSignature, pMethodRecord); } else { // _logger.log(Level.INFO, "Omitting " + meth + " for class " + // iName); } } aMethodTables.add(iMethodTable); } public void storeOptimizedMethods (RecordTable<RecordTable<MethodRecord>> aMethodTables, RecordTable<RecordTable<ExceptionRecord>> aExceptionTables, HashVector<Signature> aSignatures) throws TinyVMException { if (isInterface()) return; // _logger.log(Level.INFO, "Processing methods in " + iName); RecordTable<MethodRecord> iOptMethodTable = new RecordTable<MethodRecord>("methods", false, false); HashMap<Signature, MethodRecord> iOptMethods = new HashMap<Signature, MethodRecord>(); for (Iterator<MethodRecord> iter = iMethodTable.iterator(); iter.hasNext();) { MethodRecord pRec = iter.next(); if (iBinary.useAll() || pRec.isCalled()) { iOptMethodTable.add(pRec); iOptMethods.put(aSignatures.elementAt(pRec.iSignatureId), pRec); if (pRec.getExceptions() != null) aExceptionTables.add(pRec.getExceptions()); } } iMethodTable = iOptMethodTable; iMethods = iOptMethods; aMethodTables.add(iMethodTable); } public void storeOptimizedStaticFields (RecordTable<StaticFieldRecord> aStaticFields, RecordTable<StaticValue> aStaticState, int align) throws TinyVMException { Field[] fields = iCF.getFields(); for (int i = 0; i < fields.length; i++) { Field pField = fields[i]; if (pField.isStatic()) { String pName = pField.getName().toString(); StaticFieldRecord pRec = iStaticFields.get(pName); StaticValue pValue = iStaticValues.get(pName); if (pValue.getAlignment() == align && (iBinary.useAll() || pRec.used())) { aStaticState.add(pValue); aStaticFields.add(pRec); } } } } public void storeOptimizedFields (RecordTable<RecordTable<InstanceFieldRecord>> aInstanceFieldTables) throws TinyVMException { aInstanceFieldTables.add(iInstanceFields); } public void storeFields (RecordTable<RecordTable<InstanceFieldRecord>> aInstanceFieldTables, RecordTable<StaticFieldRecord> aStaticFields, RecordTable<StaticValue> aStaticState) throws TinyVMException { Field[] fields = iCF.getFields(); for (int i = 0; i < fields.length; i++) { Field pField = fields[i]; if (pField.isStatic()) { StaticValue pValue = new StaticValue(pField); StaticFieldRecord pRec = new StaticFieldRecord(pField, this); String pName = pField.getName().toString(); assert !iStaticValues.containsKey(pName): "Check: value not static"; iStaticValues.put(pName, pValue); iStaticFields.put(pName, pRec); aStaticState.add(pValue); aStaticFields.add(pRec); } else { iInstanceFields.add(new InstanceFieldRecord(pField)); } } aInstanceFieldTables.add(iInstanceFields); } public void storeCode (RecordTable<CodeSequence> aCodeSequences, boolean aPostProcess) throws TinyVMException { for (Iterator<MethodRecord> iter = iMethodTable.iterator(); iter.hasNext();) { MethodRecord pRec = iter.next(); if (aPostProcess) pRec.postProcessCode(aCodeSequences, iCF, iBinary); else pRec.copyCode(aCodeSequences, iCF, iBinary); } } public void markMethods () throws TinyVMException { for (Iterator<MethodRecord> iter = iMethodTable.iterator(); iter.hasNext();) { MethodRecord pRec = iter.next(); pRec.markCalled(iCF, iBinary); } } public void markMethod(MethodRecord pRec, boolean directCall) throws TinyVMException { // Is this a simple class? if (directCall) iBinary.markClassUsed(this, (pRec.getFlags() & TinyVMConstants.M_STATIC) == 0); pRec.markCalled(iCF, iBinary); if (!iImplementedBy.isEmpty()) { // Must be an interface. We need to mark all possible methods that // could be called via this interface for (Iterator<ClassRecord> iter = iImplementedBy.iterator(); iter.hasNext();) { ClassRecord pClass = iter.next(); // _logger.log(Level.INFO, "Mark interface class " + pClass.getName()); // Does this class (or a super class), have this method? MethodRecord pActualMethod = pClass.getActualVirtualMethodRecord(iBinary.iSignatures.elementAt(pRec.getSignatureId())); // If so then we need to mark it... if (pActualMethod != null) pActualMethod.iClassRecord.markMethod(pActualMethod, false); } } } public static ClassRecord getClassRecord (String className, ClassPath aCP, Binary aBinary) throws TinyVMException { assert className != null: "Precondition: aName != null"; assert aCP != null: "Precondition: aCP != null"; assert aBinary != null: "Precondition: aBinary != null"; assert className.indexOf('.') == -1: "Precondition: className is in correct form: " + className; InputStream pIn; try { pIn = aCP.getInputStream(className); assert pIn != null: "Check: pIn != null"; } catch (IOException e) { throw new TinyVMException("Class " + className.replace('/', '.') + " (file " + className + ".class) not found in CLASSPATH " + aCP); } ClassRecord pCR = new ClassRecord(); try { pCR.iBinary = aBinary; pCR.iName = className; InputStream pBufIn = new BufferedInputStream(pIn, 4096); pCR.iCF = new ClassParser(pBufIn, className).parse(); pBufIn.close(); } catch (Exception e) { // TODO refactor exceptions throw new TinyVMException(e.getMessage(), e); } pCR.iType = TinyVMType.T_REFERENCE; pCR.iNumDims = 0; pCR.iArrayElementClass = null; return pCR; } @Override public String toString () { return iName; } @Override public int hashCode () { return iName.hashCode(); } @Override public boolean equals (Object aObj) { if (!(aObj instanceof ClassRecord)) return false; ClassRecord pOther = (ClassRecord) aObj; return pOther.iName.equals(iName); } public void addInterfaces(ClassRecord pUserClass) { String []interfaces = iCF.getInterfaceNames(); if (interfaces == null) return; for(int i = 0; i < interfaces.length; i++) { // _logger.log(Level.INFO, "Interface name " + interfaces[i]); ClassRecord pInterfaceRecord = iBinary.getClassRecord(interfaces[i].replace('.', '/')); pInterfaceRecord.addInterfaceUser(pUserClass); // If this interface extends an existing interface then the parent // interfaces do not show up as super-classes instead they show up // as interfaces, implemented by this interface. So we add this // class to those inetrafces as well. pInterfaceRecord.addInterfaces(pUserClass); } if (hasParent()) getParent().addInterfaces(pUserClass); } public void addInterfaceUser(ClassRecord pRec) { // Add the supplied class to the list of classes known to implement this // interface. // _logger.log(Level.INFO, "Adding class " + pRec.getName() + " to interface " + getName()); if (iImplementedBy.contains(pRec)) return; iImplementedBy.add(pRec); } public void findHiddenMethods () throws TinyVMException { // If this class is a sub class and it contains methods that over-ride // methods, then we need to add the over-ridding method to the list of // methods to be marked that is associated with the over-ridden method! for (Iterator<MethodRecord> iter = iMethodTable.iterator(); iter.hasNext();) { MethodRecord pRec = iter.next(); if (hasParent () && (pRec.getFlags() & (TinyVMConstants.M_STATIC | TinyVMConstants.M_STATIC)) == 0 && !(iBinary.iSignatures.elementAt(pRec.iSignatureId)).getImage().substring(0, 1).equals("<")) { MethodRecord pOverridden = getParent().getVirtualMethodRecord(iBinary.iSignatures.elementAt(pRec.getSignatureId())); if (pOverridden != null) { pOverridden.setHiddenBy(pRec); // _logger.log(Level.INFO, "Set " + pOverridden.iClassRecord.getName() + " : " + ((Signature)iBinary.iSignatures.elementAt(pOverridden.iSignatureId)).getImage() + " hidden by " // + getName() + " : " + ((Signature)iBinary.iSignatures.elementAt(pRec.iSignatureId)).getImage()); } } } } public void markUsed() { if (!isUsed) { if(hasParent()) getParent().markUsed(); if (isArray()) { iArrayElementClass.markUsed(); } } isUsed = true; } public void markInstanceUsed() { if (!isInstanceUsed) { if(hasParent()) getParent().markInstanceUsed(); if (isArray()) { iArrayElementClass.markInstanceUsed(); } } isInstanceUsed = true; markUsed(); } public boolean used() { return isUsed; } public boolean instanceUsed() { return isInstanceUsed; } public int getArrayDimension() { return iNumDims; } public ClassRecord getArrayElementClass() { return iArrayElementClass; } public String signature() { String sig = ""; if (isArray()) { sig = "[" + iArrayElementClass.signature(); } else if(isPrimitive()) sig = iType.signature(); else sig = iType.signature() + this.iName + ";"; return sig; } /** * Helper method return the wrapper index, if this is a wrapper class * @return The wrapper index or -1 if this class is not a wrapper class */ private int getWrapperIndex() { for(int i = 0; i < wrappers.length; i++) if (iName.equals(wrappers[i])) return i; return -1; } /** * Determine if this class is a wrapper * @return true if the class is a wrapper, otherwise false */ public boolean isWrapper() { return getWrapperIndex() >= 0; } /** * Return the wrapped class if this class is a wrapper * @return the primitive class or null if this class is not a wrapper */ public PrimitiveClassRecord getPrimitiveClass() { int idx = getWrapperIndex(); if (idx < 0) return null; return (PrimitiveClassRecord) iBinary.getClassRecord(primitive[idx]); } /** * Add the classes which implement this interface into the the set of * class records. * @param aClassRecords Set of records */ public void storeOptimizedImplementingClasses(RecordTable<ClassRecord> aClassRecords) { HashSet<ClassRecord> iNewImplementedBy = new HashSet<ClassRecord>(); for(ClassRecord cr : iImplementedBy) if (cr.used() || iBinary.useAll()) { iNewImplementedBy.add(cr); aClassRecords.add(cr); } iImplementedBy = iNewImplementedBy; } /** * Create and store the inetrface map for this interface class. * The interface map provides a mechanism for quickly testing if a particular * class implements this interface (or a super interface). * @param maps the set of ineterface maps. * @throws TinyVMException */ public void storeInterfaceMap(RecordTable<InterfaceMap> maps) throws TinyVMException { if (!isInterface()) throw new TinyVMException("Attempt to store an interface map for a non interface class " + this.iName); iInterfaceMap = new InterfaceMap(iBinary, this); maps.add(iInterfaceMap); } }