美文网首页
解析 JVM 字节码结构

解析 JVM 字节码结构

作者: stefanJi | 来源:发表于2020-01-31 21:58 被阅读0次

    按照JVM 字节码的存储格式 https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html 规范,使用 Java 实现 https://github.com/stefanJi/BytecodeParser 解析字节码结构。

    结果输出

    ========== Start Parse=========
    == Magic Number ======================================
    MagicNumber{b1=CA, b2=FE, b3=BA, b4=BE}
    == Version ======================================
    Version{minorVersion=0, majorVersion=52}
    == Constant Pool ======================================
    ConstantPool{poolCount=214, constantsSize=2376, mConstantItems=
      #1 MethodRef{classInfoIndex=65, nameAndTypeIndex=130}
      #2 String{index=131}
      ...
      #213 Utf8{attributeLength=20, value='()Ljava/lang/String;'}
    }
    == Access Flags ======================================
    AccessFlags: public,final,super,
    bytecode.AccessFlags@27bc2616
    == This class ======================================
    ClassIndex{classInfoIndex=49 -> 171 -> bytecode/BytecodeParser}
    == Super class ======================================
    ClassIndex{classInfoIndex=65 -> 185 -> java/lang/Object}
    == Interfaces ======================================
    Interface count: 0
    Interface Indexes: []
    == Fields ======================================
    FieldOrMethod{count=2, name='Fields', mEntities=[Entity{accessFlag=[Public,Static,], nameIndex=66, name=constantItemHashMap, descriptorIndex=67, attributesCount=1, mAttributeInfos=[AttributeInfo{nameIndex=68, attributeLength=2, mInfo=Signature{signatureIndex=69 -> Ljava/util/HashMap<Ljava/lang/Integer;Lbytecode/ConstantItem;>;}}]}, Entity{accessFlag=[Private,Static,Final,], nameIndex=70, name=path, descriptorIndex=71, attributesCount=1, mAttributeInfos=[AttributeInfo{nameIndex=72, attributeLength=2, mInfo=ConstantValue{constantValueIndex=4}}]}]}
    == Methods ======================================
    FieldOrMethod{count=4, name='Methods', mEntities=[Entity{accessFlag=[Public,], nameIndex=73,...
    == This class attribute_info ======================================
    [AttributeInfo{nameIndex=128, attributeLength=2, mInfo=SourceFile{sourceFileIndex=129 -> BytecodeParser.java}}]
    

    实现

    整体流程

    ClassFile {
        u4             magic;
        u2             minor_version;
        u2             major_version;
        u2             constant_pool_count;
        cp_info        constant_pool[constant_pool_count-1];
        u2             access_flags;
        u2             this_class;
        u2             super_class;
        u2             interfaces_count;
        u2             interfaces[interfaces_count];
        u2             fields_count;
        field_info     fields[fields_count];
        u2             methods_count;
        method_info    methods[methods_count];
        u2             attributes_count;
        attribute_info attributes[attributes_count];
    }
    

    按照字节码的储存顺序依次解析每一块内容。所有解析过程都共用一个 byte[] 数组,每个具体的解析过程,通过控制 offset 实现解析不同部分的数据。

    public final class BytecodeParser {
        // 用来在常量池解析完之后,存在全局方便后面使用
        public static HashMap<Integer, ConstantItem> constantItemHashMap;
    
        private void parse(final byte[] bytes) {
            printSectionDivider("Magic Number");
            Section magicNumber = new MagicNumber(0, bytes);
            magicNumber.parse();
            System.out.println(magicNumber);
    
            printSectionDivider("Version");
            Section version = new Version(magicNumber.end(), bytes);
            version.parse();
            System.out.println(version);
    
            printSectionDivider("Constant Pool");
            ConstantPool constantPool = new ConstantPool(version.end(), bytes);
            constantPool.parse();
            System.out.println(constantPool);
            constantItemHashMap = constantPool.getConstantItems();
    
            printSectionDivider("Access Flags");
            Section accessFlags = new AccessFlags(constantPool.end(), bytes);
            accessFlags.parse();
            System.out.println(accessFlags);
    
            printSectionDivider("This class");
            Section thisClass = new ClassIndex(accessFlags.end(), bytes);
            thisClass.parse();
            System.out.println(thisClass);
    
            printSectionDivider("Super class");
            Section superClass = new ClassIndex(thisClass.end(), bytes);
            superClass.parse();
            System.out.println(superClass);
    
            printSectionDivider("Interfaces");
            Interfaces interfaces = new Interfaces(superClass.end(), bytes);
            interfaces.parse();
            System.out.println(interfaces);
    
            printSectionDivider("Fields");
            FieldOrMethod fields = new FieldOrMethod("Fields", interfaces.end(), bytes);
            fields.parse();
            System.out.println(fields);
    
            printSectionDivider("Methods");
            FieldOrMethod methods = new FieldOrMethod("Methods", fields.end(), bytes);
            methods.parse();
            System.out.println(methods);
    
            printSectionDivider("This class attribute_info");
            int offset = methods.end();
            int attributeCount = Utils.read2Number(bytes, offset);
            offset += 2;
            AttributeInfo[] attributeInfos = new AttributeInfo[attributeCount];
            for (int i = 0; i < attributeCount; i++) {
                attributeInfos[i] = new AttributeInfo();
                attributeInfos[i].parse(bytes, offset);
                offset += attributeInfos[i].size();
            }
            System.out.println(Arrays.toString(attributeInfos));
        }
    }
    
    public static void main(String[] args) {
        if (args.length < 1) {
            throw new IllegalArgumentException("Must pass class file path.");
        }
        String path = args[0];
        System.out.println("========== Start Parse=========");
        try {
            FileInputStream fis = new FileInputStream(new File(path));
            int count = fis.available();
            byte[] buff = new byte[count];
            int read = fis.read(buff);
            if (read != count) {
                return;
            }
            new BytecodeParser().parse(buff);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private static void printSectionDivider(String name) {
        System.out.println("== " + name + " ======================================");
    }
    

    提取了一些抽象

    方便后面实现时生成统一的方法

    interface Parsable {
        public void parse(byte[] bytes, int offset);
    }
    
    abstract class Section {
        final int start;    //记录每一块结构的开始位置
        final byte[] bytes; // 所有人共用的数据
    
        public Section(int start, byte[] bytes) {
            this.start = start;
            this.bytes = bytes;
        }
    
        public final int start() {
            return start;
        }
    
        public final int end() {
            return start + size();
        }
    
        abstract int size();    //每一块结构需要返回自己占用了多少字节
    
        abstract public void parse();
    }
    

    解析魔数

    class MagicNumber extends Section {
    
        public MagicNumber(int start, byte[] bytes) {
            super(start, bytes);
        }
    
        @Override
        int size() {
            return 4;
        }
    
        private int b1, b2, b3, b4;//u1
    
        @Override
        public void parse() {
            b1 = Utils.readUnsignedByte(bytes, start);
            b2 = Utils.readUnsignedByte(bytes, start + 1);
            b3 = Utils.readUnsignedByte(bytes, start + 2);
            b4 = Utils.readUnsignedByte(bytes, start + 3);
        }
    
        @Override
        public String toString() {
            return "MagicNumber{" +
                    "b1=" + Integer.toHexString(b1).toUpperCase() +
                    ", b2=" + Integer.toHexString(b2).toUpperCase() +
                    ", b3=" + Integer.toHexString(b3).toUpperCase() +
                    ", b4=" + Integer.toHexString(b4).toUpperCase() +
                    '}';
        }
    }
    

    解析版本号

    class Version extends Section {
    
        public Version(int start, byte[] bytes) {
            super(start, bytes);
        }
    
        @Override
        int size() {
            return 4;
        }
    
        private int minorVersion, majorVersion; //u2
    
        @Override
        public void parse() {
            minorVersion = Utils.read2Number(bytes, start);
            majorVersion = Utils.read2Number(bytes, start + 2);
        }
    
        @Override
        public String toString() {
            return "Version{" +
                    "minorVersion=" + minorVersion +
                    ", majorVersion=" + majorVersion +
                    '}';
        }
    }
    

    解析常量池

    常量池这里有一点要注意:代表常量池有多少常量的 poolCount,是包括了 poolCount 它本身的。也就是真正的常量池的常量其实是 poolCount -1 个。

    每个常量项都有一个 u1 的 tag 表示其类型。解析时需要先解析 tag, 然后根据 tag 做对应类型的解析。

    class ConstantPool extends Section {
    
        int poolCount; //u2
        private int constantsSize;
    
        private HashMap<Integer, ConstantItem> mConstantItems = new HashMap<>();
    
        public HashMap<Integer, ConstantItem> getConstantItems() {
            return mConstantItems;
        }
    
        public ConstantPool(int start, byte[] bytes) {
            super(start, bytes);
        }
    
        @Override
        int size() {
            return 2/*u2 的常量池计数占用*/ + constantsSize;
        }
    
        @Override
        public void parse() {
            poolCount = Utils.read2Number(bytes, start);
            // 遍历常量表的每一项常量
            int offset = 2;
            for (int i = 1; i <= poolCount - 1; i++) {
                int tag = Utils.readUnsignedByte(bytes, start + offset);
                // 根据 tag 找到匹配的常量
                ConstantItem item = ConstantItem.getConstantItemTags(tag);
                if (item == null) {
                    System.err.println("Not found ConstantItem for " + tag);
                    return;
                }
                item.parse(bytes, start + offset);
                offset += item.size();
                constantsSize += item.size();
                mConstantItems.put(i, item);
            }
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            for (int i = 1; i <= poolCount - 1; i++) {
                sb.append("  #").append(i).append(" ").append(mConstantItems.get(i)).append("\n");
            }
            return "ConstantPool{" +
                    "poolCount=" + poolCount +
                    ", constantsSize=" + constantsSize +
                    ", mConstantItems=\n" + sb.toString() +
                    '}';
        }
    }
    

    每个常量项

    /**
     * 常量项
     * 每个常量项都有 u1 的 tag, 表示其类型
     * <pre>
     * cp_info {
     *     u1 tag;
     *     u1 info[];
     * }
     * </pre>
     */
    abstract class ConstantItem implements Parsable {
        final int tag;
    
        ConstantItem(int tag) {
            this.tag = tag;
        }
    
        abstract protected int contentSize();
    
        int size() {
            return 1/*u1的tag*/ + contentSize();
        }
    
        @Nullable
        static ConstantItem getConstantItemTags(int tag) {
            switch (tag) {
                case 1:
                    return new UTF8();
                case 3:
                    return new INTEGER();
                case 4:
                    return new FLOAT();
                case 5:
                    return new LONG();
                case 6:
                    return new DOUBLE();
                case 7:
                    return new CLASS();
                case 8:
                    return new STRING();
                case 9:
                    return new FIELD_REF();
                case 10:
                    return new METHOD_REF();
                case 11:
                    return new Interface_Method_Ref();
                case 12:
                    return new NAME_AND_TYPE();
                case 15:
                    return new Method_Handle();
                case 16:
                    return new Method_Type();
                case 18:
                    return new Invoke_Dynamic();
                default:
                    return null;
            }
        }
    
    }
    

    CONSTANT_Utf8

    所有的字面量都储存在 UTF8 常量中。value 存储着以 UTF-8 编码的字符串的原始字节数据。

    //region Constants
    
    class UTF8 extends ConstantItem {
        private int length;
        public String value;
    
        UTF8() {
            super(1);
        }
    
        @Override
        protected int contentSize() {
            return length /* 字符串占用的字节数 */ + 2 /* u2 的字符串长度 attributeLength*/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            length = Utils.read2Number(bytes, start + 1);
            value = new String(bytes, start + 3, length);
        }
    
        @Override
        public String toString() {
            return "Utf8{" +
                    "attributeLength=" + length +
                    ", value='" + value + '\'' +
                    '}';
        }
    }
    

    CONSTANT_Integer

    class INTEGER extends ConstantItem {
        int value;
    
        protected INTEGER() {
            super(3);
        }
    
        @Override
        protected int contentSize() {
            return 4 /*u4 值*/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            value = Utils.read4Number(bytes, start + 1);
        }
    
        @Override
        public String toString() {
            return "Integer{" +
                    "value=" + value +
                    '}';
        }
    }
    

    CONSTANT_Float

    class FLOAT extends ConstantItem {
        float value;
    
        FLOAT() {
            super(4);
        }
    
        @Override
        protected int contentSize() {
            return 4 /* 同 INTEGER 的注释 */;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            value = Utils.read4Number(bytes, start + 1);
        }
    
        @Override
        public String toString() {
            return "Float{" +
                    "value=" + value +
                    '}';
        }
    }
    

    CONSTANT_Long

    class LONG extends ConstantItem {
        long value;
    
        LONG() {
            super(5);
        }
    
        @Override
        protected int contentSize() {
            return 8 /* u8 值*/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            value = Utils.read8Number(bytes, start);
        }
    
        @Override
        public String toString() {
            return "Long{" +
                    "value=" + value +
                    '}';
        }
    }
    

    CONSTANT_Double

    class DOUBLE extends ConstantItem {
    
        DOUBLE() {
            super(6);
        }
    
        double value;
    
        @Override
        protected int contentSize() {
            return 8 /*u8 值*/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            value = Utils.read8Number(bytes, start + 1);
        }
    
        @Override
        public String toString() {
            return "Double{" +
                    "value=" + value +
                    '}';
        }
    }
    

    CONSTANT_Class

    存储指向类的全限定名在常量池中的索引 index

    class CLASS extends ConstantItem {
    
        CLASS() {
            super(7);
        }
    
        int index;
    
        @Override
        protected int contentSize() {
            return 2 /*u2 常量池索引*/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            index = Utils.read2Number(bytes, start + 1);
        }
    
        @Override
        public String toString() {
            return "Class{" +
                    "index=" + index +
                    '}';
        }
    }
    

    CONSTANT_String

    存储指向 Constant_UTF8 的索引 index

    class STRING extends ConstantItem {
        STRING() {
            super(8);
        }
    
        int index; //u2
    
        @Override
        protected int contentSize() {
            return 2/*u2 常量池索引*/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            index = Utils.read2Number(bytes, start + 1);
        }
    
        @Override
        public String toString() {
            return "String{" +
                    "index=" + index +
                    '}';
        }
    }
    

    CONSTANT_Fieldref

    • classInfoIndex 声明字段的类的信息,指向 CONSTANT_Class
    • nameAndTypeIndex 字段的信息,指向 CONSTANT_NameAndType 类型的索引
    class FIELD_REF extends ConstantItem {
    
        int classInfoIndex, nameAndTypeIndex;
    
        FIELD_REF() {
            super(9);
        }
    
        @Override
        protected int contentSize() {
            return 2/*u2 类信息常量池索引*/ + 2/*u2 名字和类型常量池索引*/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            classInfoIndex = Utils.read2Number(bytes, start + 1);
            nameAndTypeIndex = Utils.read2Number(bytes, start + 3);
        }
    
        @Override
        public String toString() {
            return "FileRef{" +
                    "classInfoIndex=" + classInfoIndex +
                    ", nameAndTypeIndex=" + nameAndTypeIndex +
                    '}';
        }
    }
    

    CONSTANT_Methodref

    • classInfoIndex 声明方法的类的信息,指向 CONSTANT_Class
    • nameAndTypeIndex 方法的信息,指向 CONSTANT_NameAndType 类型的索引
    class METHOD_REF extends ConstantItem {
        int classInfoIndex, nameAndTypeIndex;
    
        METHOD_REF() {
            super(10);
        }
    
        @Override
        protected int contentSize() {
            return 4 /*同 FIELD_REF*/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            classInfoIndex = Utils.read2Number(bytes, start + 1);
            nameAndTypeIndex = Utils.read2Number(bytes, start + 3);
        }
    
        @Override
        public String toString() {
            return "MethodRef{" +
                    "classInfoIndex=" + classInfoIndex +
                    ", nameAndTypeIndex=" + nameAndTypeIndex +
                    '}';
        }
    }
    

    CONSTANT_InterfaceMethodref

    • classInfoIndex 声明接口的类的信息,指向 CONSTANT_Class
    • nameAndTypeIndex 接口的信息,指向 CONSTANT_NameAndType 类型的索引
    class Interface_Method_Ref extends ConstantItem {
        int classInfoIndex, nameAndTypeIndex;
    
        Interface_Method_Ref() {
            super(11);
        }
    
        @Override
        protected int contentSize() {
            return 4/*同FIELD_REF*/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            classInfoIndex = Utils.read2Number(bytes, start + 1);
            nameAndTypeIndex = Utils.read2Number(bytes, start + 3);
        }
    
        @Override
        public String toString() {
            return "InterfaceMethodRef{" +
                    "classInfoIndex=" + classInfoIndex +
                    ", nameAndTypeIndex=" + nameAndTypeIndex +
                    '}';
        }
    }
    

    CONSTANT_NameAndType

    • nameIndex 指向方法或字段的名称在常量池中的索引
    • descriptorIndex 指向方法或字段的描述符在常量池中的索引
    class NAME_AND_TYPE extends ConstantItem {
        int nameIndex, descriptorIndex; //u2
    
        NAME_AND_TYPE() {
            super(12);
        }
    
        @Override
        protected int contentSize() {
            return 2/*u2 名称在常量池的索引*/ + 2/*u2 描述符在常量池的索引*/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            nameIndex = Utils.read2Number(bytes, start + 1);
            descriptorIndex = Utils.read2Number(bytes, start + 3);
        }
    
        @Override
        public String toString() {
            return "NameAndType{" +
                    "nameIndex=" + nameIndex +
                    ", descriptorIndex=" + descriptorIndex +
                    '}';
        }
    }
    

    CONSTANT_MethodHandle

    详细信息参考 https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.8

    • referenceKind 方法句柄的类型,代表字节码被执行时的行为. ? 不太懂这个... 还没有遇到出现的情况
    • referenceIndex
    class Method_Handle extends ConstantItem {
    
        int referenceKind; //u1
        int referenceIndex; //u2
    
        Method_Handle() {
            super(15);
        }
    
        @Override
        protected int contentSize() {
            return 1/**/ + 2/**/;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            referenceKind = Utils.readUnsignedByte(bytes, start + 1);
            referenceIndex = Utils.read2Number(bytes, start + 2);
        }
    
        @Override
        public String toString() {
            return "MethodHandle{" +
                    "referenceKind=" + referenceKind +
                    ", referenceIndex=" + referenceIndex +
                    '}';
        }
    }
    

    CONSTANT_MethodType

    • descriptorIndex 指向常量池中 UTF8 类型的索引,表示方法的描述符
    class Method_Type extends ConstantItem {
        int descriptorIndex; //u2
    
        Method_Type() {
            super(16);
        }
    
        @Override
        protected int contentSize() {
            return 2;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            descriptorIndex = Utils.read2Number(bytes, start + 1);
        }
    
        @Override
        public String toString() {
            return "MethodType{" +
                    "descriptorIndex=" + descriptorIndex +
                    '}';
        }
    }
    

    CONSTANT_InvokeDynamic

    https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.10

    与 Java 的动态方法调用有关。

    class Invoke_Dynamic extends ConstantItem {
        int bootstrapAttrIndex, nameAndTypeIndex;
    
        Invoke_Dynamic() {
            super(18);
        }
    
        @Override
        protected int contentSize() {
            return 4;
        }
    
        @Override
        public void parse(byte[] bytes, int start) {
            bootstrapAttrIndex = Utils.read2Number(bytes, start + 1);
            nameAndTypeIndex = Utils.read2Number(bytes, start + 3);
        }
    
        @Override
        public String toString() {
            return "InvokeDynamic{" +
                    "bootstrapAttrIndex=" + bootstrapAttrIndex +
                    ", nameAndTypeIndex=" + nameAndTypeIndex +
                    '}';
        }
    }
    
    //endregion
    

    解析访问标志

    一个字段或方法或类的访问标志都是使用一个 u2 类型的数字表示,通过位运算 | 赋予,通过 &运算判断是否拥有某种访问标志。

    class AccessFlags extends Section {
    
        private static final int PUBLIC = 0x0001;    // 0000 0000 0000 0001
        private static final int FINAL = 0x0010;     // 0000 0000 0001 0000
        private static final int SUPER = 0x0020;     // 0000 0000 0010 0000
        private static final int INTERFACE = 0x0200; // 0000 0010 0000 0000
        private static final int ABSTRACT = 0x0400;  // 0000 0100 0000 0000
        private static final int SYNTHETIC = 0x1000; // 0001 0000 0000 0000
        private static final int ANNOTATION = 0x2000;// 0010 0000 0000 0000
        private static final int ENUM = 0x4000;      // 0100 0000 0000 0000
        private static final int PRIVATE = 0x0002;
    
        private int accessFlags; //u2
    
        public AccessFlags(int start, byte[] bytes) {
            super(start, bytes);
        }
    
        @Override
        int size() {
            return 2;
        }
    
        @Override
        public void parse() {
            accessFlags = Utils.read2Number(bytes, start);
            System.out.println("AccessFlags: " + printAccess(accessFlags));
        }
    
        public static String printAccess(int access) {
            ArrayList<String> accessFlags = new ArrayList<>();
            if ((access & PUBLIC) == PUBLIC) {
                accessFlags.add("public");
            }
            if ((access & FINAL) == FINAL) {
                accessFlags.add("final");
            }
            if ((access & SUPER) == SUPER) {
                accessFlags.add("super");
            }
            if ((access & INTERFACE) == INTERFACE) {
                accessFlags.add("interface");
            }
            if ((access & ABSTRACT) == ABSTRACT) {
                accessFlags.add("abstract");
            }
            if ((access & SYNTHETIC) == SYNTHETIC) {
                accessFlags.add("synthetic");
            }
            if ((access & ANNOTATION) == ANNOTATION) {
                accessFlags.add("annotation");
            }
            if ((access & ENUM) == ENUM) {
                accessFlags.add("enum");
            }
            if ((access & PRIVATE) == PRIVATE) {
                accessFlags.add("private");
            }
            StringBuilder sb = new StringBuilder();
            accessFlags.forEach(s -> sb.append(s).append(","));
            return sb.toString();
        }
    }
    

    解析类信息

    类自身和其父类都存储在 class_info 结构中,classInfoIndex 指向常量池中 Constant_Class 类型的常量

    /**
     * 类索引
     * 用于解析自身类和父类在常量池的索引
     */
    class ClassIndex extends Section {
    
        private int classInfoIndex;
    
        public ClassIndex(int start, byte[] bytes) {
            super(start, bytes);
        }
    
        @Override
        int size() {
            return 2;
        }
    
        @Override
        public void parse() {
            classInfoIndex = Utils.read2Number(bytes, start);
        }
    
        @Override
        public String toString() {
            CLASS clasz = (CLASS) BytecodeParser.constantItemHashMap.get(classInfoIndex);
            UTF8 utf8 = (UTF8) BytecodeParser.constantItemHashMap.get(clasz.index);
            return "ClassIndex{" +
                    "classInfoIndex=" + classInfoIndex +
                    " -> " + clasz.index + " -> " + utf8.value +
                    '}';
        }
    }
    

    解析接口

    类实现的所有接口在常量池的 Constant_class 类型索引

    class Interfaces extends Section {
    
        int interfaceCount; //u2
        int[] indexs; // u2[interfaceCount]
    
        public Interfaces(int start, byte[] bytes) {
            super(start, bytes);
        }
    
        @Override
        int size() {
            return interfaceCount * 2 + 2;
        }
    
        @Override
        public void parse() {
            interfaceCount = Utils.read2Number(bytes, start);
            int offset = 2;
            indexs = new int[interfaceCount];
            for (short i = 0; i < interfaceCount; i++) {
                int index = Utils.read2Number(bytes, start + offset);
                indexs[i] = index;
            }
        }
    
        @Override
        public String toString() {
            return "Interfaces{" +
                    "interfaceCount=" + interfaceCount +
                    ", indexs=" + Arrays.toString(indexs) +
                    '}';
        }
    }
    

    解析方法和字段

    /**
     * <pre>
     * field_info {
     *     u2             access_flags;
     *     u2             name_index;
     *     u2             descriptor_index;
     *     u2             attributes_count;
     *     attribute_info attributes[attributes_count];
     * }
     * </pre>
     */
    class FieldOrMethod extends Section {
    
        private int infoSize = 0;
    
        int count; //u2
    
        static class Entity {
    
            int accessFlag;  //u2
            int nameIndex;   //u2
            int descriptorIndex; //u2
            int attributesCount; //u2
    
            private ArrayList<AttributeInfo> mAttributeInfos = new ArrayList<>();
    
            public int size() {
                int infoSize = 0;
                for (AttributeInfo info : mAttributeInfos) {
                    infoSize += info.size();
                }
                return 8 + infoSize;
            }
    
            public void parse(byte[] bytes, int offset) {
                accessFlag = Utils.read2Number(bytes, offset);
                offset += 2;
                nameIndex = Utils.read2Number(bytes, offset);
                offset += 2;
                descriptorIndex = Utils.read2Number(bytes, offset);
                offset += 2;
                attributesCount = Utils.read2Number(bytes, offset);
                offset += 2;
                for (int i = 0; i < attributesCount; i++) {
                    AttributeInfo attributeInfo = new AttributeInfo();
                    attributeInfo.parse(bytes, offset);
                    mAttributeInfos.add(attributeInfo);
                    offset += attributeInfo.size();
                }
            }
    
            static final int PUBLIC = 0x0001;
            static final int PRIVATE = 0x0002;
            static final int PROTECTED = 0x0004;
            static final int STATIC = 0x0008;
            static final int FINAL = 0x0010;
            // field special
            static final int VOLATILE = 0x0040;
            static final int TRANSIENT = 0x0080;
            static final int SYNTHETIC = 0x1000;
            static final int ENUM = 0x4000;
            // method special
            static final int SYNCHRONIZED = 0x0020;
            static final int BRIDGE = 0x0040;
            static final int VARARGS = 0x0080;
            static final int NATIVE = 0x0100;
            static final int ABSTRACT = 0x0400;
            static final int STRICTFP = 0x0500;
    
            private static String accessFlagReadable(int access) {
                StringBuilder sb = new StringBuilder();
                sb.append("[");
                if ((access & PUBLIC) == PUBLIC) sb.append("Public,");
                if ((access & PRIVATE) == PRIVATE) sb.append("Private,");
                if ((access & PROTECTED) == PROTECTED) sb.append("Protected,");
                if ((access & STATIC) == STATIC) sb.append("Static,");
                if ((access & FINAL) == FINAL) sb.append("Final,");
                if ((access & VOLATILE) == VOLATILE) sb.append("Volatile,");
                if ((access & TRANSIENT) == TRANSIENT) sb.append("Transient,");
                if ((access & SYNTHETIC) == SYNTHETIC) sb.append("Synthetic,");
                if ((access & ENUM) == ENUM) sb.append("Enum,");
                if ((access & SYNCHRONIZED) == SYNCHRONIZED) sb.append(", Synchronized");
                if ((access & BRIDGE) == BRIDGE) sb.append(",Bridge");
                if ((access & VARARGS) == VARARGS) sb.append(",Varargs");
                if ((access & NATIVE) == NATIVE) sb.append(",Native");
                if ((access & ABSTRACT) == ABSTRACT) sb.append(",Abstract");
                if ((access & STRICTFP) == STRICTFP) sb.append(",Strictfp");
    
                sb.append("]");
                return sb.toString();
            }
    
            @Override
            public String toString() {
                return "Entity{" +
                        "accessFlag=" + accessFlagReadable(accessFlag) +
                        ", nameIndex=" + nameIndex +
                        ", name=" + ((UTF8) BytecodeParser.constantItemHashMap.get(nameIndex)).value +
                        ", descriptorIndex=" + descriptorIndex +
                        ", attributesCount=" + attributesCount +
                        ", mAttributeInfos=" + mAttributeInfos +
                        '}';
            }
        }
    
        private final String name;
        private final ArrayList<Entity> mEntities = new ArrayList<>();
    
        public FieldOrMethod(String name, int start, byte[] bytes) {
            super(start, bytes);
            this.name = name;
        }
    
        @Override
        int size() {
            return infoSize + 2;
        }
    
        @Override
        public void parse() {
            int offset = start;
            count = Utils.read2Number(bytes, offset);
            offset += 2;
            for (int i = 0; i < count; i++) {
                Entity entity = new Entity();
                entity.parse(bytes, offset);
                mEntities.add(entity);
                infoSize += entity.size();
                offset += entity.size();
            }
        }
    
        @Override
        public String toString() {
            return "FieldOrMethod{" +
                    "count=" + count +
                    ", name='" + name + '\'' +
                    ", mEntities=" + mEntities +
                    '}';
        }
    }
    

    解析属性表

    字段、方法、类都能拥有自己的属性表。只是某些属性只会出现在字段上(比如 volatile)或方法上(比如 synchronized)。

    u2 attribute_name_index;
    u4 attribute_length;
    

    attribute_name_indexattribute_length 是每个属性都有的两个字段,所以提出来由父类实现解析。

    /**
     * <pre>
     * attribute_info {
     *     u2 attribute_name_index;
     *     u4 attribute_length;
     *     u1 info[attribute_length];
     * }
     * </pre>
     */
    class AttributeInfo implements Parsable {
        private int nameIndex;  //u2
        private int attributeLength; //u4
        private Info mInfo;
    
        @Override
        public void parse(byte[] bytes, int offset) {
            nameIndex = Utils.read2Number(bytes, offset);
            offset += 2;
            attributeLength = Utils.read4Number(bytes, offset);
            offset += 4;
            // 根据属性名称找到匹配的属性
            ConstantItem constantItem = BytecodeParser.constantItemHashMap.get(nameIndex);
            UTF8 utf8 = (UTF8) constantItem;
            String infoName = utf8.value;
            mInfo = Info.getMatchInfo(infoName);
            if (mInfo == null) {
                System.err.println("Not found matching Attributes: " + infoName);
                return;
            }
            mInfo.parse(bytes, offset);
        }
    
        public int size() {
            return 2 + 4 + attributeLength;
        }
    
        @Override
        public String toString() {
            return "AttributeInfo{" +
                    "nameIndex=" + nameIndex +
                    ", attributeLength=" + attributeLength +
                    ", mInfo=" + mInfo +
                    '}';
        }
    }
    
    abstract class Info implements Parsable {
        public int size() {
            return contentSize();
        }
    
        abstract protected int contentSize();
    
        abstract public void parseInner(byte[] bytes, int offset);
    
        @Override
        public void parse(byte[] bytes, int offset) {
            parseInner(bytes, offset);
        }
    
        @Nullable
        public static Info getMatchInfo(String name) {
            switch (name) {
                case "Code":
                    return new CodeInfo();
                case "ConstantValue":
                    return new ConstantValue();
                case "Exceptions":
                    return new Exceptions();
                case "LineNumberTable":
                    return new LineNumberTable();
                case "LocalVariableTable":
                    return new LocalVariableTable();
                case "LocalVariableTypeTable":
                    return new LocalVariableTypeTable();
                case "SourceFile":
                    return new SourceFile();
                case "InnerClasses":
                    return new InnerClasses();
                case "Deprecated":
                    return new Deprecated();
                case "Synthetic":
                    return new Synthetic();
                case "StackMapTable":
                    // TODO StackMapTable 待实现
                    return null;
                case "Signature":
                    return new Signature();
                default:
                    return null;
            }
        }
    }
    

    Code 属性

    //region Info
    /**
     * <pre>
     * Code_attribute {
     *     u2 attribute_name_index;
     *     u4 attribute_length;
     *     u2 max_stack;
     *     u2 max_locals;
     *     u4 code_length;
     *     u1 code[code_length];
     *     u2 exception_table_length;
     *     {   u2 start_pc;
     *         u2 end_pc;
     *         u2 handler_pc;
     *         u2 catch_type;
     *     } exception_table[exception_table_length];
     *     u2 attributes_count;
     *     attribute_info attributes[attributes_count];
     * }
     * </pre>
     */
    class CodeInfo extends Info {
    
        class ExceptionTable implements Parsable {
            int startPc; //u2
            int endPc; //u2
            int handlePc; // u2
            int catchType; //u2
    
            public int size() {
                return 2 + 2 + 2 + 2;
            }
    
            @Override
            public void parse(byte[] bytes, int offset) {
                startPc = Utils.read2Number(bytes, offset);
                offset += 2;
                endPc = Utils.read2Number(bytes, offset);
                offset += 2;
                handlePc = Utils.read2Number(bytes, offset);
                offset += 2;
                catchType = Utils.read2Number(bytes, offset);
            }
    
            @Override
            public String toString() {
                return "ExceptionTable{" +
                        "startPc=" + startPc +
                        ", endPc=" + endPc +
                        ", handlePc=" + handlePc +
                        ", catchType=" + catchType +
                        '}';
            }
        }
    
        int maxStack; //u2
        int maxLocals; //u2
        int codeLength; //u4
        int[] code; // u1[codeLength]
        int exceptionTableLength; //u2
        ExceptionTable[] exceptionTable;
        int attributeCount; //u2
        AttributeInfo[] attributes;
    
        private int attributesSize;
    
        @Override
        public int contentSize() {
            return attributesSize + 2 + 2 + 4 + codeLength + exceptionTableLength;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
            maxStack = Utils.read2Number(bytes, offset);
            offset += 2;
            maxLocals = Utils.read2Number(bytes, offset);
            offset += 2;
            codeLength = Utils.read4Number(bytes, offset);
            offset += 4;
            code = new int[codeLength];
            for (int i = 0; i < codeLength; i++) {
                code[i] = Utils.readUnsignedByte(bytes, offset);
                offset += 1;
            }
            exceptionTableLength = Utils.read2Number(bytes, offset);
            offset += 2;
            exceptionTable = new ExceptionTable[exceptionTableLength];
            for (int i = 0; i < exceptionTableLength; i++) {
                exceptionTable[i] = new ExceptionTable();
                exceptionTable[i].parse(bytes, offset);
                offset += exceptionTable[i].size();
            }
            attributeCount = Utils.read2Number(bytes, offset);
            offset += 2;
            attributes = new AttributeInfo[attributeCount];
            for (int i = 0; i < attributeCount; i++) {
                attributes[i] = new AttributeInfo();
                attributes[i].parse(bytes, offset);
                offset += attributes[i].size();
                attributesSize += attributes[i].size();
            }
        }
    
        public String toString() {
            return "CodeInfo{" +
                    "maxStack=" + maxStack +
                    ", maxLocals=" + maxLocals +
                    ", codeLength=" + codeLength +
                    ", code=" + Arrays.toString(code) +
                    ", exceptionTableLength=" + exceptionTableLength +
                    ", exceptionTable=" + Arrays.toString(exceptionTable) +
                    ", attributeCount=" + attributeCount +
                    ", attributes=" + Arrays.toString(attributes) +
                    '}';
        }
    }
    

    常量属性

    class ConstantValue extends Info {
        int constantValueIndex; //u2
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
            constantValueIndex = Utils.read2Number(bytes, offset + 2);
        }
    
        @Override
        public int contentSize() {
            return 2;
        }
    
        @Override
        public String toString() {
            return "ConstantValue{" +
                    "constantValueIndex=" + constantValueIndex +
                    '}';
        }
    }
    

    异常属性

    /**
     * <pre>
     * Exceptions_attribute {
     *     u2 attribute_name_index;
     *     u4 attribute_length;
     *     u2 number_of_exceptions;
     *     u2 exception_index_table[number_of_exceptions];
     * }
     * </pre>
     */
    class Exceptions extends Info {
        int numberOfExceptions; //u2
        int[] exceptionIndexTable; //u2[numberOfExceptions]
    
        @Override
        public int contentSize() {
            return 2;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
            numberOfExceptions = Utils.read2Number(bytes, offset);
            offset += 2;
            exceptionIndexTable = new int[numberOfExceptions];
            for (int i = 0; i < numberOfExceptions; i++) {
                exceptionIndexTable[i] = Utils.read2Number(bytes, offset);
                offset += 2;
            }
        }
    
        @Override
        public String toString() {
            return "Exceptions{" +
                    "numberOfExceptions=" + numberOfExceptions +
                    ", exceptionIndexTable=" + Arrays.toString(exceptionIndexTable) +
                    '}';
        }
    }
    

    字节码与源码行号对应属性

    /**
     * <pre>
     * LineNumberTable_attribute {
     *     u2 attribute_name_index;
     *     u4 attribute_length;
     *     u2 line_number_table_length;
     *     {   u2 start_pc;
     *         u2 line_number;
     *     } line_number_table[line_number_table_length];
     * }
     * </pre>
     */
    class LineNumberTable extends Info {
    
        class LineNumberInfo implements Parsable {
            int startPc; //u2
            int lineNumber; //u2
    
            public static final int size = 4;
    
            @Override
            public void parse(byte[] bytes, int offset) {
                startPc = Utils.read2Number(bytes, offset);
                offset += 2;
                lineNumber = Utils.read2Number(bytes, offset);
            }
    
            @Override
            public String toString() {
                return "LineNumberInfo{" +
                        "startPc=" + startPc +
                        ", lineNumber=" + lineNumber +
                        '}';
            }
        }
    
        int lineNumberTableLength; //u2
        private LineNumberInfo[] mLineNumberInfos;
    
        @Override
        protected int contentSize() {
            return mLineNumberInfos.length * LineNumberInfo.size + 2;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
            lineNumberTableLength = Utils.read2Number(bytes, offset);
            offset += 2;
            mLineNumberInfos = new LineNumberInfo[lineNumberTableLength];
            for (int i = 0; i < lineNumberTableLength; i++) {
                mLineNumberInfos[i] = new LineNumberInfo();
                mLineNumberInfos[i].parse(bytes, offset);
                offset += LineNumberInfo.size;
            }
        }
    
        @Override
        public String toString() {
            return "LineNumberTable{" +
                    "lineNumberTableLength=" + lineNumberTableLength +
                    ", mLineNumberInfos=" + Arrays.toString(mLineNumberInfos) +
                    '}';
        }
    }
    

    局部变量属性

    /**
     * <pre>
     * LocalVariableTable_attribute {
     *     u2 attribute_name_index;
     *     u4 attribute_length;
     *     u2 local_variable_table_length;
     *     {   u2 start_pc;
     *         u2 length;
     *         u2 name_index;
     *         u2 descriptor_index;
     *         u2 index;
     *     } local_variable_table[local_variable_table_length];
     * }
     * </pre>
     */
    class LocalVariableTable extends Info {
    
        class LocalVairableTableItem implements Parsable {
            int startPc;
            int length;
            int nameIndex;
            int descriptorIndex;
            int index;
    
            public static final int size = 10;
    
            @Override
            public void parse(byte[] bytes, int offset) {
                startPc = Utils.read2Number(bytes, offset);
                length = Utils.read2Number(bytes, offset + 2);
                nameIndex = Utils.read2Number(bytes, offset + 2);
                descriptorIndex = Utils.read2Number(bytes, offset + 4);
                index = Utils.read2Number(bytes, offset + 6);
            }
    
            @Override
            public String toString() {
                return "LocalVairableTableItem{" +
                        "startPc=" + startPc +
                        ", length=" + length +
                        ", nameIndex=" + nameIndex +
                        ", descriptorIndex=" + descriptorIndex +
                        ", index=" + index +
                        '}';
            }
        }
    
        int localVariableTableLength; //u2
        private LocalVairableTableItem[] items;
    
        @Override
        protected int contentSize() {
            return localVariableTableLength * LocalVairableTableItem.size + 2;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
            localVariableTableLength = Utils.read2Number(bytes, offset);
            offset += 2;
            items = new LocalVairableTableItem[localVariableTableLength];
            for (int i = 0; i < localVariableTableLength; i++) {
                items[i] = new LocalVairableTableItem();
                items[i].parse(bytes, offset);
                offset += LocalVairableTableItem.size;
            }
        }
    
        @Override
        public String toString() {
            return "LocalVariableTable{" +
                    "localVariableTableLength=" + localVariableTableLength +
                    ", items=" + Arrays.toString(items) +
                    '}';
        }
    }
    

    源代码文件属性

    /**
     * <pre>
     * SourceFile_attribute {
     *     u2 attribute_name_index;
     *     u4 attribute_length;
     *     u2 sourcefile_index;
     * }
     * </pre>
     */
    class SourceFile extends Info {
    
        int sourceFileIndex; //u2
    
        @Override
        protected int contentSize() {
            return 2;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
            sourceFileIndex = Utils.read2Number(bytes, offset);
        }
    
        @Override
        public String toString() {
            return "SourceFile{" +
                    "sourceFileIndex=" + sourceFileIndex + " -> " + ((UTF8) BytecodeParser.constantItemHashMap.get(sourceFileIndex)).value +
                    '}';
        }
    }
    

    内部类属性

    /**
     * <pre>
     * InnerClasses_attribute {
     *     u2 attribute_name_index;
     *     u4 attribute_length;
     *     u2 number_of_classes;
     *     {   u2 inner_class_info_index;
     *         u2 outer_class_info_index;
     *         u2 inner_name_index;
     *         u2 inner_class_access_flags;
     *     } classes[number_of_classes];
     * }
     * </pre>
     */
    class InnerClasses extends Info {
    
        class Classes implements Parsable {
            int innerClassInfoIndex, outerClassInfoIndex, innerNameInex, innerClassAccessFlags; //u2
    
            public static final int size = 8;
    
            @Override
            public void parse(byte[] bytes, int offset) {
                innerClassInfoIndex = Utils.read2Number(bytes, offset);
                offset += 2;
                outerClassInfoIndex = Utils.read2Number(bytes, offset);
                offset += 2;
                innerNameInex = Utils.read2Number(bytes, offset);
                offset += 2;
                innerClassAccessFlags = Utils.read2Number(bytes, offset);
            }
    
            @Override
            public String toString() {
                return "Classes{" +
                        "innerClassInfoIndex=" + innerClassInfoIndex +
                        ", outerClassInfoIndex=" + outerClassInfoIndex +
                        ", innerNameInex=" + innerNameInex + " -> " + ((UTF8) BytecodeParser.constantItemHashMap.get(innerNameInex)).value +
                        ", innerClassAccessFlags=" + innerClassAccessFlags + " -> " + AccessFlags.printAccess(innerClassAccessFlags) +
                        '}';
            }
        }
    
        int numberOfClasses; //u2
        private Classes[] mClasses;
    
        @Override
        protected int contentSize() {
            return numberOfClasses * Classes.size + 2;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
            numberOfClasses = Utils.read2Number(bytes, offset);
            offset += 2;
            mClasses = new Classes[numberOfClasses];
            for (int i = 0; i < numberOfClasses; i++) {
                mClasses[i] = new Classes();
                mClasses[i].parse(bytes, offset);
                offset += Classes.size;
            }
        }
    
        @Override
        public String toString() {
            return "InnerClasses{" +
                    "numberOfClasses=" + numberOfClasses +
                    ", mClasses=" + Arrays.toString(mClasses) +
                    '}';
        }
    }
    

    泛型签名属性

    /**
     * <pre>
     * Signature_attribute {
     *     u2 attribute_name_index;
     *     u4 attribute_length;
     *     u2 signature_index;
     * }
     * </pre>
     */
    class Signature extends Info {
    
        int signatureIndex; //u2
    
        @Override
        protected int contentSize() {
            return 2;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
            signatureIndex = Utils.read2Number(bytes, offset);
        }
    
        @Override
        public String toString() {
            ConstantItem constantItem = BytecodeParser.constantItemHashMap.get(signatureIndex);
            String signature = constantItem.toString();
            if (constantItem instanceof UTF8) {
                signature = ((UTF8) constantItem).value;
            } else if (constantItem instanceof METHOD_REF) {
                signature = constantItem.toString();
            } else if (constantItem instanceof STRING) {
                signature = ((UTF8) BytecodeParser.constantItemHashMap.get(((STRING) constantItem).index)).value;
            }
            return "Signature{" +
                    "signatureIndex=" + signatureIndex + " -> " + signature +
                    '}';
        }
    }
    

    StackMapTable 属性

    StackMapTable 用于优化类型检查效率的。https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.4

    /**
     * https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.4
     * <pre>
     * StackMapTable_attribute {
     *     u2              attribute_name_index;
     *     u4              attribute_length;
     *     u2              number_of_entries;
     *     stack_map_frame entries[number_of_entries];
     * }
     *
     * union stack_map_frame {
     *     same_frame;
     *     same_locals_1_stack_item_frame;
     *     same_locals_1_stack_item_frame_extended;
     *     chop_frame;
     *     same_frame_extended;
     *     append_frame;
     *     full_frame;
     * }
     * </pre>
     */
    class StackMapTable extends Info {
    
        class StackMapFrame {
            /**
             * <pre>
             * same_frame {
             *     u1 frame_type = SAME; // 0-63
             * }
             * </pre>
             */
            class SameFrame {
                int frame_type; //u1
            }
    
            /**
             * <pre>
             * same_locals_1_stack_item_frame {
             *     u1 frame_type = SAME_LOCALS_1_STACK_ITEM; // 64-127
             *     verification_type_info stack[1];
             * }
             * </pre>
             */
            class SameLocals1StackItemFrame {
            }
    
            class SameLocals1StackItemFrameExtended {
            }
    
            class ChopFrame {
            }
    
            class SameFrameExtended {
            }
    
            class AppendFrame {
            }
    
            class FullFrame {
            }
        }
    
        int numberOfEntries; //u2
    
        private StackMapFrame[] mStackMapFrames;
    
        @Override
        protected int contentSize() {
            return 0;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
    
        }
    }
    

    Synthetic 编译器合成属性

    /**
     * <pre>
     * Synthetic_attribute {
     *     u2 attribute_name_index;
     *     u4 attribute_length; //always zero
     * }
     * </pre>
     */
    class Synthetic extends Info {
    
        @Override
        protected int contentSize() {
            return 0;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
    
        }
    }
    

    Deprecated 属性

    /**
     * <pre>
     * Deprecated_attribute {
     *     u2 attribute_name_index;
     *     u4 attribute_length;
     * }
     * </pre>
     */
    class Deprecated extends Info {
        @Override
        protected int contentSize() {
            return 0;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
    
        }
    }
    

    LocalVariableTypeTable

    局部变量类型属性

    /**
     * <pre>
     *  LocalVariableTypeTable_attribute {
     *     u2 attribute_name_index;
     *     u4 attribute_length;
     *     u2 local_variable_type_table_length;
     *     {   u2 start_pc;
     *         u2 length;
     *         u2 name_index;
     *         u2 signature_index;
     *         u2 index;
     *     } local_variable_type_table[local_variable_type_table_length];
     * }
     * </pre>
     */
    class LocalVariableTypeTable extends Info {
    
        class Local_variable_type_table implements Parsable {
            int start_pc;
            int length;
            int name_index;
            int signature_index;
            int index;
    
            public static final int size = 10;
    
            @Override
            public void parse(byte[] bytes, int offset) {
                start_pc = Utils.read2Number(bytes, offset);
                length = Utils.read2Number(bytes, offset + 2);
                name_index = Utils.read2Number(bytes, offset + 4);
                signature_index = Utils.read2Number(bytes, offset + 6);
                index = Utils.read2Number(bytes, offset + 8);
            }
    
            @Override
            public String toString() {
                return "Local_variable_type_table{" +
                        "start_pc=" + start_pc +
                        ", length=" + length +
                        ", name_index=" + name_index +
                        ", signature_index=" + signature_index +
                        ", index=" + index +
                        '}';
            }
        }
    
        int lvtt_length; //u2
        Local_variable_type_table[] mTables;
    
        @Override
        protected int contentSize() {
            return lvtt_length * Local_variable_type_table.size + 2;
        }
    
        @Override
        public void parseInner(byte[] bytes, int offset) {
            lvtt_length = Utils.read2Number(bytes, offset);
            offset += 2;
            mTables = new Local_variable_type_table[lvtt_length];
            for (int i = 0; i < lvtt_length; i++) {
                mTables[i] = new Local_variable_type_table();
                mTables[i].parse(bytes, offset);
                offset += Local_variable_type_table.size;
            }
        }
    
        @Override
        public String toString() {
            return "LocalVariableTypeTable{" +
                    "lvtt_length=" + lvtt_length +
                    ", mTables=" + Arrays.toString(mTables) +
                    '}';
        }
    }
    
    //endregion
    

    从字节中获取数字的工具类

    由于 Java 的所有数字类型都是 signed 类型,就会导致 unsigned 的数到了 Java 中可能越界溢出。所以统一使用 Java 的 int 代表 unsigned byte

    class Utils {
        /**
         * 获取占4字节的数
         */
        static int read4Number(byte[] bytes, int offset) {
            return ((bytes[offset] & 0xFF) << 24) | ((bytes[offset + 1] & 0xFF) << 16) | ((bytes[offset + 2] & 0xFF) << 8) | ((bytes[offset + 3] & 0xFF));
        }
    
        /**
         * 获取占2字节的数, 为了避免 java 中只有 signed short 越界出现显示了负数, 所以返回 int
         */
        static int read2Number(byte[] bytes, int offset) {
            return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF);
        }
    
        static int readUnsignedByte(byte[] bytes, int offset) {
            return (bytes[offset] & 0xFF);
        }
    
        /**
         * 获得占8字节的数
         */
        static long read8Number(byte[] bytes, int offset) {
            return (
                    ((long) bytes[offset] & 0xFF) << 56) |
                    (((long) bytes[offset + 1] & 0xFF) << 48) |
                    (((long) bytes[offset + 2] & 0xFF) << 40) |
                    (((long) bytes[offset + 3] & 0xFF) << 32) |
                    (((long) bytes[offset + 3] & 0xFF) << 24) |
                    (((long) bytes[offset + 3] & 0xFF) << 16) |
                    (((long) bytes[offset + 3] & 0xFF) << 8) |
                    (((long) bytes[offset + 3] & 0xFF));
        }
    }
    

    相关文章

      网友评论

          本文标题:解析 JVM 字节码结构

          本文链接:https://www.haomeiwen.com/subject/kysnthtx.html