package jvm.classfile; import jvm.classfile.attribute.item.AttributeInfo; import jvm.classfile.attribute.parser.AttributeParser; import jvm.classfile.constant.item.IReference; import jvm.classfile.constant.item.impl.ClassInfo; import jvm.classfile.constant.item.impl.CountConstant; import jvm.classfile.constant.parser.ConstantParser; import jvm.classfile.constant.parser.ConstantParserFactory; import jvm.classfile.field.Field; import jvm.classfile.method.Method; import jvm.util.ByteCodeIterator; import jvm.util.TypeUtils; /** * Created by Haochen on 2017/4/9. * TODO: */ public class ClassParser { public static ClassFile parse(byte[] bytes) { ClassFile classFile = new ClassFile(); ByteCodeIterator iterator = new ByteCodeIterator(bytes); iterator.skip(4); // skip magic number classFile.minorVersion = parseMinorVersion(iterator); classFile.majorVersion = parseMajorVersion(iterator); classFile.constantPool = parseConstantPool(iterator); classFile.accessFlag = parseAccessFlag(iterator); classFile.classIndex = parseClassIndex(iterator); linkConstantReferences(classFile); parseInterfaces(classFile, iterator); parseFields(classFile, iterator); parseMethods(classFile, iterator); parseAttributes(classFile, iterator); return classFile; } private static void parseAttributes(ClassFile classFile, ByteCodeIterator iterator) { int count = iterator.nextU2ToInt(); for (int i = 0; i < count; ++i) { AttributeInfo attribute = AttributeParser.parse(iterator, classFile.constantPool); classFile.attributes.add(attribute); } } private static int parseMinorVersion(ByteCodeIterator iterator) { return iterator.nextU2ToInt(); } private static int parseMajorVersion(ByteCodeIterator iterator) { return iterator.nextU2ToInt(); } private static ConstantPool parseConstantPool(ByteCodeIterator iterator) { ConstantPool constantPool = new ConstantPool(); int count = iterator.nextU2ToInt(); constantPool.addConstantInfo(new CountConstant(count)); for (int i = 1; i < count; ++i) { int tag = iterator.nextU1ToInt(); ConstantParser parser = ConstantParserFactory.get(tag); constantPool.addConstantInfo(parser.parse(iterator)); } return constantPool; } private static AccessFlag parseAccessFlag(ByteCodeIterator iterator) { AccessFlag accessFlag = new AccessFlag(); accessFlag.flagValue = iterator.nextU2ToInt(); return accessFlag; } private static ClassIndex parseClassIndex(ByteCodeIterator iterator) { ClassIndex classIndex = new ClassIndex(); classIndex.thisClass = iterator.nextU2ToInt(); classIndex.superClass = iterator.nextU2ToInt(); return classIndex; } private static void parseInterfaces(ClassFile classFile, ByteCodeIterator iterator) { int count = iterator.nextU2ToInt(); ConstantPool constantPool = classFile.constantPool; for (int i = 0; i < count; ++i) { int index = iterator.nextU2ToInt(); ClassInfo info = (ClassInfo) constantPool.getConstantInfo(index); classFile.interfaces.add(info); } } private static void parseFields(ClassFile classFile, ByteCodeIterator iterator) { int count = iterator.nextU2ToInt(); for (int i = 0; i < count; ++i) { Field field = Field.parse(iterator, classFile.constantPool); classFile.fields.add(field); if (field.getAccessFlag().isStatic()) { classFile.putStaticFieldValue(field.getName(), TypeUtils.getDefaultValue(field)); } } } private static void parseMethods(ClassFile classFile, ByteCodeIterator iterator) { int count = iterator.nextU2ToInt(); for (int i = 0; i < count; ++i) { classFile.methods.add(Method.parse(iterator, classFile)); } } private static void linkConstantReferences(ClassFile classFile) { ConstantPool constantPool = classFile.constantPool; for (int i = 0; i < constantPool.getSize(); ++i) { constantPool.forEach(c -> { if (c instanceof IReference) { ((IReference) c).linkReference(constantPool); } }); } } }