/** * Read a single element_value structure. * * @param data * @param cp */ private static Object readElementValue(ByteBuffer data, VmCP cp) { final int tag = data.get() & 0xFF; switch (tag) { case 'B': return (byte) cp.getInt(data.getChar()); case 'C': return (char) cp.getInt(data.getChar()); case 'D': return cp.getDouble(data.getChar()); case 'F': return cp.getFloat(data.getChar()); case 'I': return cp.getInt(data.getChar()); case 'J': return cp.getLong(data.getChar()); case 'S': return (short) cp.getInt(data.getChar()); case 'Z': return cp.getInt(data.getChar()) != 0; case 's': return cp.getAny(data.getChar()); case 'e': // enum { final String typeDescr = cp.getUTF8(data.getChar()); final String constName = cp.getUTF8(data.getChar()); return new VmAnnotation.EnumValue(typeDescr, constName); } case 'c': // class { final String classDescr = cp.getUTF8(data.getChar()); return new VmAnnotation.ClassInfo(classDescr); } case '@': // annotation return readAnnotation(data, cp, true); case '[': // array { final int numValues = data.getChar(); final Object[] arr = new Object[numValues]; for (int i = 0; i < numValues; i++) { arr[i] = readElementValue(data, cp); } return arr; } default: throw new ClassFormatError("Unknown element_value tag '" + (char) tag + '\''); } }
/** * 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; }