package com.coderising.jvm.loader; import java.io.UnsupportedEncodingException; import java.util.Objects; import com.coderising.jvm.clz.AccessFlag; import com.coderising.jvm.clz.ClassFile; import com.coderising.jvm.clz.ClassIndex; import com.coderising.jvm.constant.ClassInfo; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.constant.FieldRefInfo; import com.coderising.jvm.constant.MethodRefInfo; import com.coderising.jvm.constant.NameAndTypeInfo; import com.coderising.jvm.constant.NullConstantInfo; import com.coderising.jvm.constant.StringInfo; import com.coderising.jvm.constant.UTF8Info; import com.coderising.jvm.util.Util; public class ClassFileParser { private final int CONSTANT_CLASS = 7; private final int CONSTANT_FIELD_REF = 9; private final int CONSTANT_METHOD_REF = 10; // 0A private final int CONSTANT_INTERFACE_METHOD_REF = 11; private final int CONSTANT_STRING = 8; private final int CONSTANT_INTEGER = 3; private final int CONSTANT_FLOAT = 4; private final int CONSTANT_LONG = 5; private final int CONSTANT_DOUBLE = 6; private final int CONSTANT_NAME_AND_TYPE = 12; // 0C private final int CONSTANT_UTF8 = 1; private final int CONSTANT_METHOD_HANDLE = 15; private final int CONSTANT_METHOD_TYPE = 16; private final int CONSTANT_INVOKE_DYNAMIC = 18; public ClassFile parse(byte[] codes) { // 读 Magic Number ByteCodeIterator it = new ByteCodeIterator(codes); String magicNumber = it.nextU4ToHexString(); if (!Objects.equals("cafebabe", magicNumber)) { throw new RuntimeException("这不是一个Java字节码文件"); } ClassFile classFile = new ClassFile(); // 读 次版本号 int minorVersion = it.nextU2ToInt(); classFile.setMinorVersion(minorVersion); // 读 主版本号 int majorVersion = it.nextU2ToInt(); classFile.setMajorVersion(majorVersion); classFile.setConstPool(parseConstantPool(it)); classFile.setAccessFlag(parseAccessFlag(it)); classFile.setClassIndex(parseClassInfex(it)); return classFile; } private AccessFlag parseAccessFlag(ByteCodeIterator iter) { return new AccessFlag(iter.nextU2ToInt()); } private ClassIndex parseClassInfex(ByteCodeIterator iter) { ClassIndex classIndex = new ClassIndex(); classIndex.setThisClassIndex(iter.nextU2ToInt()); classIndex.setSuperClassIndex(iter.nextU2ToInt()); return classIndex; } private ConstantPool parseConstantPool(ByteCodeIterator it) { // 读 常量池个数 int count = it.nextU2ToInt(); ConstantPool constantPool = new ConstantPool(); constantPool.addConstantInfo(new NullConstantInfo()); for (int i = 0; i < count; i++) { int tag = it.nextU1ToInt(); switch (tag) { case CONSTANT_CLASS: ClassInfo classInfo = new ClassInfo(constantPool); classInfo.setUtf8Index(it.nextU2ToInt()); constantPool.addConstantInfo(classInfo); System.out.println("classInfo "+classInfo.getUtf8Index()); break; case CONSTANT_UTF8: UTF8Info utf8Info = new UTF8Info(constantPool); utf8Info.setLength(it.nextU2ToInt()); utf8Info.setValue(it.nextToString(utf8Info.getLength())); constantPool.addConstantInfo(utf8Info); System.out.println("utf-8 "+utf8Info.getValue()); break; case CONSTANT_METHOD_REF: MethodRefInfo methodRefInfo = new MethodRefInfo(constantPool); methodRefInfo.setClassInfoIndex(it.nextU2ToInt()); methodRefInfo.setNameAndTypeIndex(it.nextU2ToInt()); constantPool.addConstantInfo(methodRefInfo); System.out.println("method ref "+methodRefInfo.getClassInfoIndex()+" "+methodRefInfo.getNameAndTypeIndex()); break; case CONSTANT_NAME_AND_TYPE: NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(constantPool); nameAndTypeInfo.setIndex1(it.nextU2ToInt()); nameAndTypeInfo.setIndex2(it.nextU2ToInt()); constantPool.addConstantInfo(nameAndTypeInfo); System.out.println("name and type "+nameAndTypeInfo.getIndex1()+" "+nameAndTypeInfo.getIndex2()); break; case CONSTANT_FIELD_REF: FieldRefInfo fieldRefInfo = new FieldRefInfo(constantPool); fieldRefInfo.setClassInfoIndex(it.nextU2ToInt()); fieldRefInfo.setNameAndTypeIndex(it.nextU2ToInt()); constantPool.addConstantInfo(fieldRefInfo); System.out.println("field ref "+fieldRefInfo.getClassInfoIndex()+" "+fieldRefInfo.getNameAndTypeIndex()); break; case CONSTANT_STRING: StringInfo stringInfo = new StringInfo(constantPool); stringInfo.setIndex(it.nextU2ToInt()); constantPool.addConstantInfo(stringInfo); System.out.println("string "+stringInfo.getIndex()); break; default: // throw new RuntimeException("还不支持的tag " + tag); } } return constantPool; } public static void main(String[] args) { String path1 = "D:\\src\\java\\study\\coding2017\\group13\\2931408816\\lesson5\\build\\classes\\main"; ClassFileLoader loader = new ClassFileLoader(); loader.addClassPath(path1); String className = "com.coderising.jvm.test.Main"; ClassFile clzFile = null; clzFile = loader.loadClass(className); clzFile.print(); } } /* Classfile /D:/src/java/study/coding2017/group13/2931408816/lesson5/build/classes/main/com/coderising/jvm/test/Main.class Last modified 2017-4-9; size 285 bytes MD5 checksum a159f82f5c9fecafdde2333579a3db3b Compiled from "Main.java" public class com.coderising.jvm.test.Main minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #3.#13 // java/lang/Object."<init>":()V #2 = Class #14 // com/coderising/jvm/test/Main #3 = Class #15 // java/lang/Object #4 = Utf8 <init> #5 = Utf8 ()V #6 = Utf8 Code #7 = Utf8 LineNumberTable #8 = Utf8 LocalVariableTable #9 = Utf8 this #10 = Utf8 Lcom/coderising/jvm/test/Main; #11 = Utf8 SourceFile #12 = Utf8 Main.java #13 = NameAndType #4:#5 // "<init>":()V #14 = Utf8 com/coderising/jvm/test/Main #15 = Utf8 java/lang/Object { public com.coderising.jvm.test.Main(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 6: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/coderising/jvm/test/Main; } SourceFile: "Main.java" */