package minijvm.loader; import java.util.ArrayList; import java.util.List; import minijvm.attr.AttributeInfo; import minijvm.attr.CodeAttr; import minijvm.attr.LineNumberTable; import minijvm.attr.LocalVariableTable; import minijvm.clz.AccessFlag; import minijvm.clz.ClassFile; import minijvm.clz.ClassIndex; import minijvm.cmd.ByteCodeCommand; import minijvm.cmd.CommandParser; import minijvm.constant.ClassInfo; import minijvm.constant.ConstantInfo; import minijvm.constant.ConstantPool; import minijvm.constant.FieldRefInfo; import minijvm.constant.MethodRefInfo; import minijvm.constant.NameAndTypeInfo; import minijvm.constant.NullConstantInfo; import minijvm.constant.StringInfo; import minijvm.constant.UTF8Info; import minijvm.field.Field; import minijvm.method.Method; public class ClassFileParser { public ClassFile parse(byte[] codes) { ByteCodeIterator iter = new ByteCodeIterator(codes); ClassFile classFile = new ClassFile(); String magicNumber = iter.nextU4ToHexString(); if (!"cafebabe".equalsIgnoreCase(magicNumber)) { return null; } classFile.setMinorVersion(iter.nextU2ToInt()); classFile.setMajorVersion(iter.nextU2ToInt()); ConstantPool pool = parseConstantPool(iter); classFile.setConstPool(pool); classFile.setAccessFlag(parseAccessFlag(iter)); classFile.setClassIndex(parseClassIndex(iter)); // 目前没有处理接口 parseInterfaces(iter); List<Field> fieldList = parseFields(iter, pool); addFields(classFile, fieldList); List<Method> methodList = parseMethods(iter, classFile); addMethods(classFile, methodList); return classFile; } private AccessFlag parseAccessFlag(ByteCodeIterator iter) { int flag = iter.nextU2ToInt(); AccessFlag accessFlag = new AccessFlag(flag); return accessFlag; } private ClassIndex parseClassIndex(ByteCodeIterator iter) { ClassIndex classIndex = new ClassIndex(); int thisClassIndex = iter.nextU2ToInt(); int superClassIndex = iter.nextU2ToInt(); classIndex.setThisClassIndex(thisClassIndex); classIndex.setSuperClassIndex(superClassIndex); return classIndex; } private ConstantPool parseConstantPool(ByteCodeIterator iter) { int size = iter.nextU2ToInt(); System.out.println("ConstantPool size: " + size); ConstantPool pool = new ConstantPool(); pool.addConstantInfo(new NullConstantInfo()); // 添加无效的第0项 for (int i = 1; i < size; i++) { int tag = iter.nextU1ToInt(); if (tag == ConstantInfo.UTF8_INFO) { UTF8Info utf8Info = new UTF8Info(pool); int length = iter.nextU2ToInt(); String value = iter.nextLengthToString(length); utf8Info.setLength(length); utf8Info.setValue(value); pool.addConstantInfo(utf8Info); } else if (tag == ConstantInfo.CLASS_INFO) { ClassInfo classInfo = new ClassInfo(pool); int index = iter.nextU2ToInt(); classInfo.setUtf8Index(index); pool.addConstantInfo(classInfo); } else if (tag == ConstantInfo.STRING_INFO) { StringInfo stringInfo = new StringInfo(pool); int index = iter.nextU2ToInt(); stringInfo.setIndex(index); pool.addConstantInfo(stringInfo); } else if (tag == ConstantInfo.FIELD_INFO) { FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); int classInfoIndex = iter.nextU2ToInt(); int nameAndTypeIndex = iter.nextU2ToInt(); fieldRefInfo.setClassInfoIndex(classInfoIndex); fieldRefInfo.setNameAndTypeIndex(nameAndTypeIndex); pool.addConstantInfo(fieldRefInfo); } else if (tag == ClassInfo.METHOD_INFO) { MethodRefInfo methodRefInfo = new MethodRefInfo(pool); int classInfoIndex = iter.nextU2ToInt(); int nameAndTypeIndex = iter.nextU2ToInt(); methodRefInfo.setClassInfoIndex(classInfoIndex); methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex); pool.addConstantInfo(methodRefInfo); } else if (tag == ClassInfo.NAME_AND_TYPE_INFO) { NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); int index1 = iter.nextU2ToInt(); int index2 = iter.nextU2ToInt(); nameAndTypeInfo.setIndex1(index1); nameAndTypeInfo.setIndex2(index2); pool.addConstantInfo(nameAndTypeInfo); } else { throw new RuntimeException("这个类型的常量还没有实现"); } } return pool; } private void parseInterfaces(ByteCodeIterator iter) { int interfaceNum = iter.nextU2ToInt(); if (interfaceNum != 0) { throw new RuntimeException("有接口没有读取"); } } private List<Field> parseFields(ByteCodeIterator iter, ConstantPool pool) { int filedNum = iter.nextU2ToInt(); System.out.println("Field num: " + filedNum); List<Field> fieldList = new ArrayList<>(); for (int i = 0; i < filedNum; i++) { int accessFlag = iter.nextU2ToInt(); int nameIndex = iter.nextU2ToInt(); int descriptionIndex = iter.nextU2ToInt(); int attributesCount = iter.nextU2ToInt(); if (attributesCount != 0) { throw new RuntimeException("字段的属性表没有处理"); } fieldList.add(new Field(accessFlag, nameIndex, descriptionIndex, pool)); } return fieldList; } private void addFields(ClassFile classFile, List<Field> fieldList) { for (Field field : fieldList) { classFile.addField(field); } } private List<Method> parseMethods(ByteCodeIterator iter, ClassFile classFile) { int methodNum = iter.nextU2ToInt(); System.out.println("Methods num: " + methodNum); List<Method> methodList = new ArrayList<>(); for (int i = 0; i < methodNum; i++) { int accessFlag = iter.nextU2ToInt(); int nameIndex = iter.nextU2ToInt(); int descriptionIndex = iter.nextU2ToInt(); Method method = new Method(classFile, accessFlag, nameIndex, descriptionIndex); int attributesCount = iter.nextU2ToInt(); for (int j = 0; j < attributesCount; j++) { parseAttribute(iter, method, classFile); } methodList.add(method); } return methodList; } private void parseAttribute(ByteCodeIterator iter, Method method, ClassFile classFile) { int nameIndex = iter.nextU2ToInt(); int length = iter.nextU4ToInt(); if (AttributeInfo.CODE.equals(getUTF8ValueOfConstantPool(nameIndex, classFile))) { CodeAttr codeAttr = parseCodeAttribute(iter, classFile); method.setCodeAttr(codeAttr); } else { //TODO 目前没有处理除CODE外的其余属性 iter.nextUxToHexString(length); } } private CodeAttr parseCodeAttribute(ByteCodeIterator iter, ClassFile classFile) { iter.back(6); // 因为之前验证类型时前进了6个字节,在此回退 int nameIndex = iter.nextU2ToInt(); int length = iter.nextU4ToInt(); int maxStack = iter.nextU2ToInt(); int maxLocals = iter.nextU2ToInt(); int codeLength = iter.nextU4ToInt(); String code = iter.nextUxToHexString(codeLength); ByteCodeCommand[] codeCommands = CommandParser.parse(classFile, code); CodeAttr codeAttr = new CodeAttr(nameIndex, length, maxStack, maxLocals, codeLength, code, codeCommands); // TODO Code属性中的exception int exceptionLength = iter.nextU2ToInt(); if (exceptionLength != 0) { throw new RuntimeException("Code属性中有异常字段没有处理"); } // Code属性中的属性 int attributesCount = iter.nextU2ToInt(); for (int i = 0; i < attributesCount; i++) { int attrNameIndex = iter.nextU2ToInt(); int attrLength = iter.nextU4ToInt(); if (AttributeInfo.LINE_NUM_TABLE.equals(getUTF8ValueOfConstantPool(attrNameIndex, classFile))) { LineNumberTable lineNumberTable = new LineNumberTable(attrNameIndex, attrLength); codeAttr.setLineNumberTable(lineNumberTable); iter.nextUxToHexString(attrLength); } else if (AttributeInfo.LOCAL_VAR_TABLE.equals(getUTF8ValueOfConstantPool(attrNameIndex, classFile))) { LocalVariableTable localVariableTable = new LocalVariableTable(attrNameIndex, attrLength); codeAttr.setLocalVariableTable(localVariableTable); iter.nextUxToHexString(attrLength); } else { String msg = "此属性:" + getUTF8ValueOfConstantPool(attrNameIndex, classFile) + "还没有处理"; throw new RuntimeException(msg); } } return codeAttr; } private void addMethods(ClassFile classFile, List<Method> methodList) { for (Method method : methodList) { classFile.addMethod(method); } } private String getUTF8ValueOfConstantPool(int index, ClassFile classFile) { ConstantPool constantPool = classFile.getConstantPool(); return constantPool.getUTF8String(index); } }