/** * Read the interfaces table * * @param data * @param cls * @param cp * @return Some flags */ private static int readInterfaces(ByteBuffer data, VmType cls, VmCP cp) { int flags = 0; final int icount = data.getChar(); if (icount > 0) { final VmImplementedInterface[] itable = new VmImplementedInterface[icount]; for (int i = 0; i < icount; i++) { final VmConstClass icls = cp.getConstClass(data.getChar()); final String iclsName = icls.getClassName(); itable[i] = new VmImplementedInterface(iclsName); for (PragmaInterface pi : INTERFACE_PRAGMAS) { if (iclsName.equals(pi.className)) { flags |= pi.flags; } } } cls.setInterfaceTable(itable); } return flags; }
/** * Decode the data of a Exceptions attribute * * @param data * @param cls * @param cp * @return The read exceptions */ private static final VmExceptions readExceptions(ByteBuffer data, VmType cls, VmCP cp) { // Read the exceptions char pragmaFlags = 0; int pragmas = 0; final int ecount = data.getChar(); final VmConstClass[] list = new VmConstClass[ecount]; for (int i = 0; i < ecount; i++) { final int idx = data.getChar(); final VmConstClass ccls = cp.getConstClass(idx); list[i] = ccls; for (MethodPragmaException mp : METHOD_PRAGMA_EXCEPTIONS) { if (ccls.getClassName().equals(mp.className)) { pragmaFlags |= mp.flags; pragmas++; list[i] = null; break; } } } if (pragmas > 0) { final int newCnt = ecount - pragmas; if (newCnt == 0) { return new VmExceptions(null, pragmaFlags); } else { final VmConstClass[] newList = new VmConstClass[newCnt]; int k = 0; for (int i = 0; i < ecount; i++) { final VmConstClass ccls = list[i]; if (ccls != null) { newList[k++] = ccls; } } return new VmExceptions(newList, pragmaFlags); } } else { return new VmExceptions(list, pragmaFlags); } }
/** * Decode a given class. * * @param data * @param rejectNatives * @param clc * @param protectionDomain * @return The decoded class * @throws ClassFormatError */ private static final VmType decodeClass( ByteBuffer data, boolean rejectNatives, VmClassLoader clc, ProtectionDomain protectionDomain) throws ClassFormatError { final VmSharedStatics sharedStatics = clc.getSharedStatics(); final VmIsolatedStatics isolatedStatics = clc.getIsolatedStatics(); final int slotSize = clc.getArchitecture().getReferenceSize(); final int magic = data.getInt(); if (magic != 0xCAFEBABE) { throw new ClassFormatError("invalid magic"); } final int min_version = data.getChar(); final int maj_version = data.getChar(); if (false) { BootLogInstance.get().debug("Class file version " + maj_version + ';' + min_version); } final int cpcount = data.getChar(); // allocate enough space for the CP final byte[] tags = new byte[cpcount]; final VmCP cp = new VmCP(cpcount); for (int i = 1; i < cpcount; i++) { final int tag = data.get() & 0xFF; tags[i] = (byte) tag; switch (tag) { case 1: // Utf8 cp.setUTF8(i, readUTF(data)); break; case 3: // int cp.setInt(i, data.getInt()); break; case 4: // float // cp.setInt(i, data.getInt()); final int ival = data.getInt(); final float fval = Float.intBitsToFloat(ival); cp.setFloat(i, fval); break; case 5: // long cp.setLong(i, data.getLong()); i++; break; case 6: // double // cp.setLong(i, data.getLong()); final long lval = data.getLong(); final double dval = Double.longBitsToDouble(lval); cp.setDouble(i, dval); i++; break; case 7: // class cp.setInt(i, data.getChar()); break; case 8: // String cp.setInt(i, data.getChar()); break; case 9: // Fieldref case 10: // Methodref case 11: // IMethodref { final int clsIdx = data.getChar(); final int ntIdx = data.getChar(); cp.setInt(i, clsIdx << 16 | ntIdx); break; } case 12: // Name and Type { final int nIdx = data.getChar(); final int dIdx = data.getChar(); cp.setInt(i, nIdx << 16 | dIdx); break; } default: throw new ClassFormatError("Invalid constantpool tag: " + tags[i]); } } // Now patch the required entries (level 1) for (int i = 1; i < cpcount; i++) { switch (tags[i]) { case 7: { // Class final int idx = cp.getInt(i); final VmConstClass constClass = new VmConstClass(cp.getUTF8(idx)); cp.setConstClass(i, constClass); break; } case 8: { // String final int idx = cp.getInt(i); final int staticsIdx = sharedStatics.allocConstantStringField(cp.getUTF8(idx)); final VmConstString constStr = new VmConstString(staticsIdx); cp.setString(i, constStr); break; } } } // Now patch the required entries (level 2) for (int i = 1; i < cpcount; i++) { final int tag = tags[i]; if ((tag >= 9) && (tag <= 11)) { final int v = cp.getInt(i); final VmConstClass constClass = cp.getConstClass(v >>> 16); final int nat = cp.getInt(v & 0xFFFF); final String name = cp.getUTF8(nat >>> 16); final String descriptor = cp.getUTF8(nat & 0xFFFF); switch (tag) { case 9: // FieldRef cp.setConstFieldRef(i, new VmConstFieldRef(constClass, name, descriptor)); break; case 10: // MethodRef cp.setConstMethodRef(i, new VmConstMethodRef(constClass, name, descriptor)); break; case 11: // IMethodRef cp.setConstIMethodRef(i, new VmConstIMethodRef(constClass, name, descriptor)); break; } } } // Cleanup the unwantend entries for (int i = 1; i < cpcount; i++) { switch (tags[i]) { case 12: // Name and Type cp.reset(i); break; } } final int classModifiers = data.getChar(); final VmConstClass this_class = cp.getConstClass(data.getChar()); final String clsName = this_class.getClassName(); final VmConstClass super_class = cp.getConstClass(data.getChar()); final String superClassName; if (super_class != null) { superClassName = super_class.getClassName(); } else { superClassName = null; } // Allocate the class object final VmType cls; if (Modifier.isInterface(classModifiers)) { cls = new VmInterfaceClass(clsName, superClassName, clc, classModifiers, protectionDomain); } else { cls = new VmNormalClass(clsName, superClassName, clc, classModifiers, protectionDomain); } cls.setCp(cp); // Determine if we can safely align the fields // int pragmaFlags = 0; if (isBootType(cls)) { cls.addPragmaFlags(TypePragmaFlags.NO_FIELD_ALIGNMENT); } cls.addPragmaFlags(getClassNamePragmaFlags(clsName)); // Interface table cls.addPragmaFlags(readInterfaces(data, cls, cp)); // Field table final FieldData[] fieldData = readFields(data, cp, slotSize, clc); // Method Table readMethods(data, rejectNatives, cls, cp, sharedStatics, clc); // Read class attributes final int acount = data.getChar(); VmAnnotation[] rVisAnn = null; VmAnnotation[] rInvisAnn = null; String sourceFile = null; String signature = null; for (int a = 0; a < acount; a++) { final String attrName = cp.getUTF8(data.getChar()); final int length = data.getInt(); if (VmArray.equals(RuntimeVisibleAnnotationsAttrName, attrName)) { byte[] buf = new byte[length]; data.slice().get(buf); cls.setRawAnnotations(buf); rVisAnn = readRuntimeAnnotations(data, cp, true, clc); } else if (VmArray.equals(RuntimeInvisibleAnnotationsAttrName, attrName)) { rInvisAnn = readRuntimeAnnotations(data, cp, false, clc); } else if (VmArray.equals(SourceFileAttrName, attrName)) { sourceFile = cp.getUTF8(data.getChar()); } else if (VmArray.equals(SignatureAttrName, attrName)) { signature = cp.getUTF8(data.getChar()); } else { skip(data, length); } } cls.setRuntimeAnnotations(rVisAnn); cls.setSourceFile(sourceFile); cls.setSignature(signature); if (rInvisAnn != null) { cls.addPragmaFlags(getClassPragmaFlags(rInvisAnn, clsName)); } if (rVisAnn != null) { cls.addPragmaFlags(getClassPragmaFlags(rVisAnn, clsName)); } // Create the fields if (fieldData != null) { createFields(cls, fieldData, sharedStatics, isolatedStatics, slotSize, cls.getPragmaFlags()); } return cls; }