From 675d9fd807d6571d09ac5dfa6f72d0a833dd67bf Mon Sep 17 00:00:00 2001 From: Imgaojp Date: Tue, 21 Feb 2017 19:18:15 +0800 Subject: [PATCH] ClassLoader --- src/com/gabongao/jvm/Interpreter.java | 19 +- src/com/gabongao/jvm/Jvm.java | 51 ++- src/com/gabongao/jvm/classfile/ClassFile.java | 64 +-- ...va => ConstantInterfaceMethodrefInfo.java} | 4 +- .../jvm/classfile/ConstantMemberrefInfo.java | 2 +- .../gabongao/jvm/classfile/MemberInfo.java | 10 + src/com/gabongao/jvm/classpath/ClassPath.java | 2 + .../jvm/instructions/BranchInstruction.java | 3 +- .../gabongao/jvm/instructions/Factory.java | 50 +-- .../jvm/instructions/Index16Instruction.java | 323 ++++++++++++++- .../jvm/instructions/Index8Instruction.java | 55 ++- .../jvm/instructions/OperandsInstruction.java | 23 +- src/com/gabongao/jvm/rtda/Frame.java | 14 + src/com/gabongao/jvm/rtda/LocalVars.java | 17 +- src/com/gabongao/jvm/rtda/OperandStack.java | 15 +- src/com/gabongao/jvm/rtda/Slot.java | 15 + .../gabongao/jvm/rtda/heap/AccessFlags.java | 64 +++ .../gabongao/jvm/rtda/heap/ClassLoader.java | 191 +++++++++ .../gabongao/jvm/rtda/heap/ClassMember.java | 119 ++++++ src/com/gabongao/jvm/rtda/heap/ClassRef.java | 42 ++ .../gabongao/jvm/rtda/heap/ClassStruct.java | 380 ++++++++++++++++++ src/com/gabongao/jvm/rtda/heap/Constant.java | 48 +++ .../gabongao/jvm/rtda/heap/ConstantPool.java | 55 +++ src/com/gabongao/jvm/rtda/heap/Field.java | 110 +++++ src/com/gabongao/jvm/rtda/heap/FieldRef.java | 82 ++++ .../jvm/rtda/heap/InterfaceMethodRef.java | 43 ++ src/com/gabongao/jvm/rtda/heap/MemberRef.java | 55 +++ src/com/gabongao/jvm/rtda/heap/Method.java | 138 +++++++ src/com/gabongao/jvm/rtda/heap/MethodRef.java | 47 +++ src/com/gabongao/jvm/rtda/heap/Object.java | 59 +++ .../jvm/rtda/{Object.java => heap/Slots.java} | 12 +- src/com/gabongao/jvm/rtda/heap/SymRef.java | 85 ++++ 32 files changed, 2096 insertions(+), 101 deletions(-) rename src/com/gabongao/jvm/classfile/{ConstantInterfaceMemberrefInfo.java => ConstantInterfaceMethodrefInfo.java} (93%) create mode 100644 src/com/gabongao/jvm/rtda/heap/AccessFlags.java create mode 100644 src/com/gabongao/jvm/rtda/heap/ClassLoader.java create mode 100644 src/com/gabongao/jvm/rtda/heap/ClassMember.java create mode 100644 src/com/gabongao/jvm/rtda/heap/ClassRef.java create mode 100644 src/com/gabongao/jvm/rtda/heap/ClassStruct.java create mode 100644 src/com/gabongao/jvm/rtda/heap/Constant.java create mode 100644 src/com/gabongao/jvm/rtda/heap/ConstantPool.java create mode 100644 src/com/gabongao/jvm/rtda/heap/Field.java create mode 100644 src/com/gabongao/jvm/rtda/heap/FieldRef.java create mode 100644 src/com/gabongao/jvm/rtda/heap/InterfaceMethodRef.java create mode 100644 src/com/gabongao/jvm/rtda/heap/MemberRef.java create mode 100644 src/com/gabongao/jvm/rtda/heap/Method.java create mode 100644 src/com/gabongao/jvm/rtda/heap/MethodRef.java create mode 100644 src/com/gabongao/jvm/rtda/heap/Object.java rename src/com/gabongao/jvm/rtda/{Object.java => heap/Slots.java} (88%) create mode 100644 src/com/gabongao/jvm/rtda/heap/SymRef.java diff --git a/src/com/gabongao/jvm/Interpreter.java b/src/com/gabongao/jvm/Interpreter.java index d0df345..31d5714 100644 --- a/src/com/gabongao/jvm/Interpreter.java +++ b/src/com/gabongao/jvm/Interpreter.java @@ -14,6 +14,7 @@ import com.gabongao.jvm.classfile.MemberInfo; import com.gabongao.jvm.instructions.*; import com.gabongao.jvm.rtda.Frame; import com.gabongao.jvm.rtda.Thread; +import com.gabongao.jvm.rtda.heap.Method; /** *         ┏┓   ┏┓+ + @@ -58,6 +59,20 @@ public class Interpreter { } } + public void doInterpreter(Method method) { + Thread thread = new Thread(); + Frame frame = new Frame(thread, method); + thread.pushFrame(frame); + try { + loop(thread, method.getCode()); + } catch (Exception e) { + e.printStackTrace(); + System.out.println(); + System.out.printf("LocalVars: %s\n", frame.getLocalVars()); + System.out.printf("OperandStack: %s\n", frame.getOperandStack()); + } + } + public void loop(Thread thread, byte[] byteCode) { Frame frame = thread.popFrame(); BytecodeReader bytecodeReader = new BytecodeReader(); @@ -65,13 +80,13 @@ public class Interpreter { for (; ; ) { int pc = frame.getNextPc(); thread.setPc(pc); - System.out.printf("loop: %2d\t", n); + System.out.printf("loop: %6d\t", n); bytecodeReader.reset(byteCode, pc); char opcode = (char) bytecodeReader.readInt8(); Instruction instruction = Factory.newInstruction((byte) opcode); instruction.fetchOperands(bytecodeReader); frame.setNextPc(bytecodeReader.getPc()); - System.out.printf("pc:%2d\t inst:%s\n", pc, instruction.getClass().getName()); + System.out.printf("pc:%3d\t inst:%s\n", pc, instruction.getClass().getName()); instruction.execute(frame); n++; } diff --git a/src/com/gabongao/jvm/Jvm.java b/src/com/gabongao/jvm/Jvm.java index 7255208..86a0b38 100644 --- a/src/com/gabongao/jvm/Jvm.java +++ b/src/com/gabongao/jvm/Jvm.java @@ -6,6 +6,9 @@ import com.gabongao.jvm.classpath.ClassPath; import com.gabongao.jvm.rtda.Frame; import com.gabongao.jvm.rtda.LocalVars; import com.gabongao.jvm.rtda.OperandStack; +import com.gabongao.jvm.rtda.heap.ClassLoader; +import com.gabongao.jvm.rtda.heap.ClassStruct; +import com.gabongao.jvm.rtda.heap.Method; /** *         ┏┓   ┏┓+ + @@ -52,11 +55,11 @@ public class Jvm { /* ch02 ClassPath cp = new ClassPath(); cp.parse(cmd.jreOption, cmd.cpOption); - System.out.printf("classpath: %s\tclass: %s\targs: %s\n",cmd.cpOption,cmd.className, Arrays.asList(cmd.args)); - String className = cmd.className.replace(".", "/").concat(".class"); - byte[] classData = cp.readClass(className); + System.out.printf("classpath: %s\tclass: %s\targs: %s\n",cmd.cpOption,cmd.getClassName, Arrays.asList(cmd.args)); + String getClassName = cmd.getClassName.replace(".", "/").concat(".class"); + byte[] classData = cp.readClass(getClassName); if (classData == null) { - System.out.printf("Could not load main class %s\n",className); + System.out.printf("Could not load main class %s\n",getClassName); System.exit(1); } for (byte b:classData @@ -69,10 +72,10 @@ public class Jvm { /* ch03 ClassPath cp = new ClassPath(); cp.parse(cmd.jreOption, cmd.cpOption); - String className = cmd.className.replace(".", "/").concat(".class"); - ClassFile classFile = new ClassFile(cp.readClass(className)); + String getClassName = cmd.getClassName.replace(".", "/").concat(".class"); + ClassFile classFile = new ClassFile(cp.readClass(getClassName)); classFile.read(); - System.out.println(cmd.className); + System.out.println(cmd.getClassName); printClassInfo(classFile); } @@ -95,24 +98,48 @@ public class Jvm { } */ - /* ch04 + // ch04 + /* Frame frame = new Frame(100, 100); testLocalVars(frame.getLocalVars()); testOperandStack(frame.getOperandStack()); */ + + //ch05 + +// Interpreter interpreter = new Interpreter(); +// ClassPath cp = new ClassPath(); +// cp.parse(cmd.jreOption, cmd.cpOption); +// String className = cmd.className.replace(".", "/").concat(".class"); +// ClassFile classFile = loadClass(className, cp); +// classFile.read(); +// MemberInfo mainMethod = getMainMethod(classFile); +// if (mainMethod != null) { +// interpreter.doInterpreter(mainMethod); +// } else { +// System.out.printf("Main method not found in class %s\n", className); +// } + + Interpreter interpreter = new Interpreter(); ClassPath cp = new ClassPath(); + + ClassLoader classLoader = new ClassLoader(cp); cp.parse(cmd.jreOption, cmd.cpOption); - String className = cmd.className.replace(".", "/").concat(".class"); - ClassFile classFile = loadClass(className, cp); - classFile.read(); - MemberInfo mainMethod = getMainMethod(classFile); +// String className = cmd.className.replace(".", "/").concat(".class"); + String className = cmd.className; + ClassStruct mainClass = classLoader.loadClass(className); + Method mainMethod = mainClass.getMainMethod(); +// ClassFile classFile = loadClass(className, cp); +// classFile.read(); +// MemberInfo mainMethod = getMainMethod(classFile); if (mainMethod != null) { interpreter.doInterpreter(mainMethod); } else { System.out.printf("Main method not found in class %s\n", className); } + } public static MemberInfo getMainMethod(ClassFile classFile) { diff --git a/src/com/gabongao/jvm/classfile/ClassFile.java b/src/com/gabongao/jvm/classfile/ClassFile.java index 7768782..b28bc27 100644 --- a/src/com/gabongao/jvm/classfile/ClassFile.java +++ b/src/com/gabongao/jvm/classfile/ClassFile.java @@ -33,30 +33,30 @@ package com.gabongao.jvm.classfile; * Created by Imgaojp on 2017/2/18. */ public class ClassFile { - static final int CONSTANT_Class = 7; - static final int CONSTANT_Fieldref = 9; - static final int CONSTANT_Methodref = 10; - static final int CONSTANT_InterfaceMethodref = 11; - static final int CONSTANT_String = 8; - static final int CONSTANT_Integer = 3; - static final int CONSTANT_Float = 4; - static final int CONSTANT_Long = 5; - static final int CONSTANT_Double = 6; - static final int CONSTANT_NameAndType = 12; - static final int CONSTANT_Utf8 = 1; static final int CONSTANT_MethodHandle = 15; static final int CONSTANT_MethodType = 16; static final int CONSTANT_InvokeDynamic = 18; - char majorVersion; - ConstantPool constantPool; - char accessFlags; - char thisClass; - char superClass; - char[] interfaces; - MemberInfo[] fields; - MemberInfo[] methods; - AttributeInfo[] attributes; - ClassReader classReader; + private static final int CONSTANT_Class = 7; + private static final int CONSTANT_Fieldref = 9; + private static final int CONSTANT_Methodref = 10; + private static final int CONSTANT_InterfaceMethodref = 11; + private static final int CONSTANT_String = 8; + private static final int CONSTANT_Integer = 3; + private static final int CONSTANT_Float = 4; + private static final int CONSTANT_Long = 5; + private static final int CONSTANT_Double = 6; + private static final int CONSTANT_NameAndType = 12; + private static final int CONSTANT_Utf8 = 1; + private char majorVersion; + private ConstantPool constantPool; + private char accessFlags; + private char thisClass; + private char superClass; + private char[] interfaces; + private MemberInfo[] fields; + private MemberInfo[] methods; + private AttributeInfo[] attributes; + private ClassReader classReader; private char minorVersion; public ClassFile(byte[] classData) { @@ -107,6 +107,7 @@ public class ClassFile { public void read() { readAndCheckMagic(); readAndCheckVersion(); + constantPool = new ConstantPool(); constantPool = readConstantPool(); accessFlags = classReader.readUint16(); thisClass = classReader.readUint16(); @@ -136,16 +137,17 @@ public class ClassFile { public ConstantPool readConstantPool() { int cpCount = classReader.readUint16(); +// constantPool.constantInfos = new ConstantInfo[cpCount]; ConstantInfo[] constantInfos = new ConstantInfo[cpCount]; +// ConstantPool cp = new ConstantPool(); for (int i = 1; i < cpCount; i++) { constantInfos[i] = readConstantInfo(); if (constantInfos[i] instanceof ConstantLongInfo || constantInfos[i] instanceof ConstantDoubleInfo) { i++; } } - ConstantPool cp = new ConstantPool(); - cp.setConstantInfos(constantInfos); - return cp; + constantPool.setConstantInfos(constantInfos); + return constantPool; } public ConstantInfo readConstantInfo() { @@ -176,7 +178,7 @@ public class ClassFile { case CONSTANT_Methodref: return new ConstantMethodrefInfo(constantPool); case CONSTANT_InterfaceMethodref: - return new ConstantInterfaceMemberrefInfo(constantPool); + return new ConstantInterfaceMethodrefInfo(constantPool); case CONSTANT_NameAndType: return new ConstantNameAndTypeInfo(); // case CONSTANT_MethodType: @@ -223,12 +225,16 @@ public class ClassFile { return ""; } + //todo:return null public String[] interfaceNames() { - String[] interfaceNames = new String[interfaces.length]; - for (int i = 0; i < interfaces.length; i++) { - interfaceNames[i] = constantPool.getClassName(interfaces[i]); + if ((interfaces != null)) { + String[] interfaceNames = new String[interfaces.length]; + for (int i = 0; i < interfaces.length; i++) { + interfaceNames[i] = constantPool.getClassName(interfaces[i]); + } + return interfaceNames; } - return interfaceNames; + return null; } diff --git a/src/com/gabongao/jvm/classfile/ConstantInterfaceMemberrefInfo.java b/src/com/gabongao/jvm/classfile/ConstantInterfaceMethodrefInfo.java similarity index 93% rename from src/com/gabongao/jvm/classfile/ConstantInterfaceMemberrefInfo.java rename to src/com/gabongao/jvm/classfile/ConstantInterfaceMethodrefInfo.java index 900bec9..a28661f 100644 --- a/src/com/gabongao/jvm/classfile/ConstantInterfaceMemberrefInfo.java +++ b/src/com/gabongao/jvm/classfile/ConstantInterfaceMethodrefInfo.java @@ -32,8 +32,8 @@ package com.gabongao.jvm.classfile; *           ┗┻┛ ┗┻┛+ + + + * Created by Imgaojp on 2017/2/18. */ -public class ConstantInterfaceMemberrefInfo extends ConstantMemberrefInfo { - public ConstantInterfaceMemberrefInfo(ConstantPool constantPool) { +public class ConstantInterfaceMethodrefInfo extends ConstantMemberrefInfo { + public ConstantInterfaceMethodrefInfo(ConstantPool constantPool) { super(constantPool); } } diff --git a/src/com/gabongao/jvm/classfile/ConstantMemberrefInfo.java b/src/com/gabongao/jvm/classfile/ConstantMemberrefInfo.java index 98924e9..46a3ead 100644 --- a/src/com/gabongao/jvm/classfile/ConstantMemberrefInfo.java +++ b/src/com/gabongao/jvm/classfile/ConstantMemberrefInfo.java @@ -50,7 +50,7 @@ public class ConstantMemberrefInfo extends ConstantInfo { nameAndTypeIndex = classReader.readUint16(); } - public String className() { + public String getClassName() { return constantPool.getClassName(classIndex); } diff --git a/src/com/gabongao/jvm/classfile/MemberInfo.java b/src/com/gabongao/jvm/classfile/MemberInfo.java index 8fe958c..86e8550 100644 --- a/src/com/gabongao/jvm/classfile/MemberInfo.java +++ b/src/com/gabongao/jvm/classfile/MemberInfo.java @@ -46,6 +46,16 @@ public class MemberInfo { this.attributes = ClassFile.readAttributes(classReader, cp); } + public AttrConstantValue getConstantValueAttribute() { + for (AttributeInfo attr : attributes + ) { + if (attr instanceof AttrConstantValue) { + return (AttrConstantValue) attr; + } + } + return null; + } + public AttrCode getCodeAttribure() { for (AttributeInfo attr : attributes ) { diff --git a/src/com/gabongao/jvm/classpath/ClassPath.java b/src/com/gabongao/jvm/classpath/ClassPath.java index 8b601cb..2e3b2c2 100644 --- a/src/com/gabongao/jvm/classpath/ClassPath.java +++ b/src/com/gabongao/jvm/classpath/ClassPath.java @@ -39,6 +39,8 @@ public class ClassPath { } public byte[] readClass(String className) { + + className = className.concat(".class"); byte[] bytes = bootClasspath.readClass(className); if ( bytes!= null) { return bytes; diff --git a/src/com/gabongao/jvm/instructions/BranchInstruction.java b/src/com/gabongao/jvm/instructions/BranchInstruction.java index fedb2c2..2d44fec 100644 --- a/src/com/gabongao/jvm/instructions/BranchInstruction.java +++ b/src/com/gabongao/jvm/instructions/BranchInstruction.java @@ -9,7 +9,7 @@ package com.gabongao.jvm.instructions; import com.gabongao.jvm.rtda.Frame; -import com.gabongao.jvm.rtda.Object; +import com.gabongao.jvm.rtda.heap.Object; import com.gabongao.jvm.rtda.OperandStack; /** @@ -48,7 +48,6 @@ public class BranchInstruction implements Instruction { public void execute(Frame frame) { } - ; public void branch(Frame frame, int offset) { int pc = frame.getThread().getPc(); diff --git a/src/com/gabongao/jvm/instructions/Factory.java b/src/com/gabongao/jvm/instructions/Factory.java index 0b4cee6..1b3070a 100644 --- a/src/com/gabongao/jvm/instructions/Factory.java +++ b/src/com/gabongao/jvm/instructions/Factory.java @@ -37,6 +37,7 @@ public class Factory { static OperandsInstruction operandsInstruction = new OperandsInstruction(); static BranchInstruction branchInstruction = new BranchInstruction(); static Index8Instruction index8Instruction = new Index8Instruction(); + static Index16Instruction index16Instruction = new Index16Instruction(); public static Instruction newInstruction(byte opcode) { switch (Byte.toUnsignedInt(opcode)) { @@ -76,12 +77,12 @@ public class Factory { return operandsInstruction.new Bipush(); case 0x11: return operandsInstruction.new Sipush(); - //case 0x12: - // return &LDC{} - //case 0x13: - // return &LDC_W{} - //case 0x14: - // return &LDC2_W{} + case 0x12: + return index8Instruction.new Ldc(); + case 0x13: + return index8Instruction.new Ldc().new Ldc_W(); + case 0x14: + return index8Instruction.new Ldc().new Ldc2_W(); case 0x15: return index8Instruction.new Iload(); case 0x16: @@ -403,26 +404,26 @@ public class Factory { // return areturn // case 0xb1: // return _return - //case 0xb2: - // return &GET_STATIC{} - //case 0xb3: - // return &PUT_STATIC{} - //case 0xb4: - // return &GET_FIELD{} - //case 0xb5: - // return &PUT_FIELD{} - //case 0xb6: - // return &INVOKE_VIRTUAL{} - //case 0xb7: - // return &INVOKE_SPECIAL{} + case 0xb2: + return index16Instruction.new GetStatic(); + case 0xb3: + return index16Instruction.new PutStatic(); + case 0xb4: + return index16Instruction.new GetField(); + case 0xb5: + return index16Instruction.new PutField(); + case 0xb6: + return index16Instruction.new InvokeVirtual(); + case 0xb7: + return index16Instruction.new InvokeSpecial(); //case 0xb8: // return &INVOKE_STATIC{} //case 0xb9: // return &INVOKE_INTERFACE{} //case 0xba: // return &INVOKE_DYNAMIC{} - //case 0xbb: - // return &NEW{} + case 0xbb: + return index16Instruction.new New(); //case 0xbc: // return &NEW_ARRAY{} //case 0xbd: @@ -431,10 +432,10 @@ public class Factory { // return arraylength //case 0xbf: // return athrow - //case 0xc0: - // return &CHECK_CAST{} - //case 0xc1: - // return &INSTANCE_OF{} + case 0xc0: + return index16Instruction.new CheckCast(); + case 0xc1: + return index16Instruction.new InstanceOf(); //case 0xc2: // return monitorenter //case 0xc3: @@ -461,6 +462,5 @@ public class Factory { default: throw new RuntimeException(String.format("Bad opcode: 0X%X", opcode)); } - } } diff --git a/src/com/gabongao/jvm/instructions/Index16Instruction.java b/src/com/gabongao/jvm/instructions/Index16Instruction.java index c6d4fef..640631c 100644 --- a/src/com/gabongao/jvm/instructions/Index16Instruction.java +++ b/src/com/gabongao/jvm/instructions/Index16Instruction.java @@ -8,6 +8,11 @@ package com.gabongao.jvm.instructions; +import com.gabongao.jvm.rtda.Frame; +import com.gabongao.jvm.rtda.OperandStack; +import com.gabongao.jvm.rtda.heap.*; +import com.gabongao.jvm.rtda.heap.Object; + /** *         ┏┓   ┏┓+ + *        ┏┛┻━━━┛┻┓ + + @@ -32,11 +37,323 @@ package com.gabongao.jvm.instructions; *           ┗┻┛ ┗┻┛+ + + + * Created by Imgaojp on 2017/2/18. */ -public abstract class Index16Instruction implements Instruction { - private char Index; +public class Index16Instruction implements Instruction { + protected char index; @Override public void fetchOperands(BytecodeReader bytecodeReader) { - Index = bytecodeReader.readUint16(); + index = bytecodeReader.readUint16(); + } + + @Override + public void execute(Frame frame) { + } + + public class New extends Index16Instruction { + @Override + public void execute(Frame frame) { + ConstantPool cp = frame.getMethod().getClassMember().getClassStruct().getConstantPool(); + ClassRef classRef = (ClassRef) cp.getConstant(index).getObject(); + ClassStruct classStruct = classRef.resolvedClass(); + + if (classStruct.IsInterface() || classStruct.IsAbstract()) { + throw new RuntimeException("InstantiationError"); + } + Object ref = classStruct.newObject(); + frame.getOperandStack().pushRef(ref); + } + + //todo: index传值失败,父类的index为private,子类不能访问父类的值,因此默认初始值0. + @Override + public void fetchOperands(BytecodeReader bytecodeReader) { + super.fetchOperands(bytecodeReader); + } + } + + public class PutStatic extends Index16Instruction { + @Override + public void execute(Frame frame) { + Method currentMethod = frame.getMethod(); + ClassStruct currentClass = currentMethod.getClassMember().getClassStruct(); + ConstantPool cp = currentClass.getConstantPool(); + FieldRef fieldRef = (FieldRef) cp.getConstant(index).getObject(); + Field field = fieldRef.resolvedField(); + ClassStruct classStruct = field.getClassStruct(); + if (!field.IsStatic()) { + throw new RuntimeException("IncompatibleClassChangeError"); + } + if (field.IsFinal()) { + if (currentClass != classStruct || !currentMethod.getClassMember().getName().equals("")) { + throw new RuntimeException("IllegalAccessError"); + } + } + String descriptor = field.getDescriptor(); + int slotId = field.getSlotId(); + Slots slots = classStruct.getStaticVars(); + OperandStack operandStack = frame.getOperandStack(); + char[] des = descriptor.toCharArray(); + switch (des[0]) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'I': + slots.setInt(slotId, operandStack.popInt()); + break; + case 'F': + slots.setFloat(slotId, operandStack.popFloat()); + break; + case 'J': + slots.setLong(slotId, operandStack.popLong()); + break; + case 'D': + slots.setDouble(slotId, operandStack.popDouble()); + break; + case 'L': + case '[': + slots.setRef(slotId, operandStack.popRef()); + break; + } + } + } + + public class GetStatic extends Index16Instruction { + @Override + public void execute(Frame frame) { + ConstantPool cp = frame.getMethod().getClassMember().getClassStruct().getConstantPool(); + FieldRef fieldRef = (FieldRef) cp.getConstant(index).getObject(); + Field field = fieldRef.resolvedField(); + ClassStruct classStruct = field.getClassStruct(); + if (!field.IsStatic()) { + throw new RuntimeException("IncompatibleClassChangeError"); + } + String descriptor = field.getDescriptor(); + int slotId = field.getSlotId(); + Slots slots = classStruct.getStaticVars(); + OperandStack operandStack = frame.getOperandStack(); + char[] des = descriptor.toCharArray(); + switch (des[0]) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'I': + operandStack.pushInt(slots.getInt(slotId)); + break; + case 'F': + operandStack.pushFloat(slots.getFloat(slotId)); + break; + case 'J': + operandStack.pushLong(slots.getLong(slotId)); + break; + case 'D': + operandStack.pushDouble(slots.getDouble(slotId)); + break; + case 'L': + case '[': + operandStack.pushRef(slots.getRef(slotId)); + break; + } + } + } + + public class PutField extends Index16Instruction { + @Override + public void execute(Frame frame) { + Method currentMethod = frame.getMethod(); + ClassStruct currentClass = currentMethod.getClassMember().getClassStruct(); + ConstantPool cp = currentClass.getConstantPool(); + FieldRef fieldRef = (FieldRef) cp.getConstant(index).getObject(); + Field field = fieldRef.resolvedField(); + if (field.IsStatic()) { + throw new RuntimeException("IncompatibleClassChangeError"); + } + if (field.IsFinal()) { + if (currentClass != field.getClassStruct() || !currentMethod.getClassMember().getName().equals("")) { + throw new RuntimeException("IllegalAccessError"); + } + } + String descriptor = field.getDescriptor(); + int slotId = field.getSlotId(); + OperandStack operandStack = frame.getOperandStack(); + char[] des = descriptor.toCharArray(); + switch (des[0]) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'I': + int vali = operandStack.popInt(); + Object refi = operandStack.popRef(); + if (refi == null) { + throw new RuntimeException("NullPointerException"); + } + refi.getFields().setInt(slotId, vali); + break; + case 'F': + float valf = operandStack.popFloat(); + Object reff = operandStack.popRef(); + if (reff == null) { + throw new RuntimeException("NullPointerException"); + } + reff.getFields().setFloat(slotId, valf); + break; + case 'J': + long vall = operandStack.popLong(); + Object refl = operandStack.popRef(); + if (refl == null) { + throw new RuntimeException("NullPointerException"); + } + refl.getFields().setLong(slotId, vall); + break; + case 'D': + double vald = operandStack.popDouble(); + Object refd = operandStack.popRef(); + if (refd == null) { + throw new RuntimeException("NullPointerException"); + } + refd.getFields().setDouble(slotId, vald); + break; + case 'L': + case '[': + Object valr = operandStack.popRef(); + Object ref = operandStack.popRef(); + if (ref == null) { + throw new RuntimeException("NullPointerException"); + } + ref.getFields().setRef(slotId, valr); + break; + } + } + } + + public class GetField extends Index16Instruction { + + @Override + public void execute(Frame frame) { + ConstantPool cp = frame.getMethod().getClassMember().getClassStruct().getConstantPool(); + FieldRef fieldRef = (FieldRef) cp.getConstant(index).getObject(); + Field field = fieldRef.resolvedField(); + if (field.IsStatic()) { + throw new RuntimeException("IncompatibleClassChangeError"); + } + + OperandStack operandStack = frame.getOperandStack(); + Object ref = operandStack.popRef(); + if (ref == null) { + throw new RuntimeException("NullPointerException"); + } + String descriptor = field.getDescriptor(); + int slotId = field.getSlotId(); + Slots slots = ref.getFields(); + char[] des = descriptor.toCharArray(); + + switch (des[0]) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'I': + operandStack.pushInt(slots.getInt(slotId)); + break; + case 'F': + operandStack.pushFloat(slots.getFloat(slotId)); + break; + case 'J': + operandStack.pushLong(slots.getLong(slotId)); + break; + case 'D': + operandStack.pushDouble(slots.getDouble(slotId)); + break; + case 'L': + case '[': + operandStack.pushRef(slots.getRef(slotId)); + break; + } + } + } + + public class InstanceOf extends Index16Instruction { + @Override + public void execute(Frame frame) { + OperandStack operandStack = frame.getOperandStack(); + Object ref = operandStack.popRef(); + if (ref == null) { + operandStack.pushInt(0); + } + ConstantPool cp = frame.getMethod().getClassMember().getClassStruct().getConstantPool(); + ClassRef classRef = (ClassRef) cp.getConstant(index).getObject(); + ClassStruct classStruct = classRef.resolvedClass(); + if (ref.isInstanceOf(classStruct)) { + operandStack.pushInt(1); + } else { + operandStack.pushInt(0); + } + } + } + + public class CheckCast extends Index16Instruction { + @Override + public void execute(Frame frame) { + OperandStack operandStack = frame.getOperandStack(); + Object ref = operandStack.popRef(); + operandStack.pushRef(ref); + if (ref == null) { + return; + } + ConstantPool cp = frame.getMethod().getClassMember().getClassStruct().getConstantPool(); + ClassRef classRef = (ClassRef) cp.getConstant(index).getObject(); + ClassStruct classStruct = classRef.resolvedClass(); + if (!ref.isInstanceOf(classStruct)) { + throw new RuntimeException("ClassCastException"); + } + } + } + + public class InvokeSpecial extends Index16Instruction { + @Override + public void execute(Frame frame) { + frame.getOperandStack().popRef(); + } + } + + public class InvokeVirtual extends Index16Instruction { + @Override + public void execute(Frame frame) { + ConstantPool cp = frame.getMethod().getClassMember().getClassStruct().getConstantPool(); + MethodRef methodRef = (MethodRef) cp.getConstant(index).getObject(); + if (methodRef.getName().equals("println")) { + OperandStack operandStack = frame.getOperandStack(); + switch (methodRef.getDescriptor()) { + case "(Z)V": + System.out.println(operandStack.popInt() != 0); + break; + case "(C)V": + System.out.printf("%c\n", operandStack.popInt()); + break; + case "(B)V": + System.out.println(operandStack.popInt()); + break; + case "(S)V": + System.out.println(operandStack.popInt()); + break; + case "(I)V": + System.out.println(operandStack.popInt()); + break; + case "(J)V": + System.out.println(operandStack.popLong()); + break; + case "(F)V": + System.out.println(operandStack.popFloat()); + break; + case "(D)V": + System.out.println(operandStack.popDouble()); + break; + default: + throw new RuntimeException("println:" + methodRef.getDescriptor()); + } + operandStack.popRef(); + } + } } } diff --git a/src/com/gabongao/jvm/instructions/Index8Instruction.java b/src/com/gabongao/jvm/instructions/Index8Instruction.java index 37a9f93..23ed88e 100644 --- a/src/com/gabongao/jvm/instructions/Index8Instruction.java +++ b/src/com/gabongao/jvm/instructions/Index8Instruction.java @@ -10,7 +10,9 @@ package com.gabongao.jvm.instructions; import com.gabongao.jvm.rtda.Frame; import com.gabongao.jvm.rtda.LocalVars; -import com.gabongao.jvm.rtda.Object; +import com.gabongao.jvm.rtda.OperandStack; +import com.gabongao.jvm.rtda.heap.ConstantPool; +import com.gabongao.jvm.rtda.heap.Object; /** *         ┏┓   ┏┓+ + @@ -685,4 +687,55 @@ public class Index8Instruction implements Instruction { localVars.setInt(super.getIndex(), localVars.getInt(super.getIndex()) + constVal); } } + + public class Ldc extends Index8Instruction { + @Override + public void execute(Frame frame) { + _ldc(frame, super.getIndex()); + } + + public void _ldc(Frame frame, int index) { + OperandStack operandStack = frame.getOperandStack(); + ConstantPool cp = frame.getMethod().getClassMember().getClassStruct().getConstantPool(); + java.lang.Object c = cp.getConstant(index).getObject(); + if (c instanceof Integer) { + operandStack.pushInt((int) c); + } else if (c instanceof Float) { + operandStack.pushFloat((float) c); + } else { + throw new RuntimeException("todo : ldc"); + } //todo + } + } + + public class Ldc_W extends Ldc { + @Override + public void execute(Frame frame) { + super.execute(frame); + } + + @Override + public void fetchOperands(BytecodeReader bytecodeReader) { + Index = bytecodeReader.readUint16(); + } + } + + public class Ldc2_W extends Ldc_W { + @Override + public void execute(Frame frame) { + OperandStack operandStack = frame.getOperandStack(); + ConstantPool cp = frame.getMethod().getClassMember().getClassStruct().getConstantPool(); + java.lang.Object c = cp.getConstant(Index).getObject(); + if (c instanceof Long) { + operandStack.pushLong((long) c); + } else if (c instanceof Double) { + operandStack.pushDouble((double) c); + } else { + throw new RuntimeException("ClassFormatError"); + } + } + } + + + } \ No newline at end of file diff --git a/src/com/gabongao/jvm/instructions/OperandsInstruction.java b/src/com/gabongao/jvm/instructions/OperandsInstruction.java index 36d55c7..7386a0c 100644 --- a/src/com/gabongao/jvm/instructions/OperandsInstruction.java +++ b/src/com/gabongao/jvm/instructions/OperandsInstruction.java @@ -42,7 +42,6 @@ import sun.awt.OSInfo; public class OperandsInstruction implements Instruction { @Override public void fetchOperands(BytecodeReader bytecodeReader) { - //TODO } public void execute(Frame frame) { @@ -294,9 +293,15 @@ public class OperandsInstruction implements Instruction { public void execute(Frame frame) { OperandStack operandStack = frame.getOperandStack(); Slot slot = operandStack.popSlot(); + Slot slot1 = slot.copySlot(); operandStack.pushSlot(slot); - operandStack.pushSlot(slot); + operandStack.pushSlot(slot1); } + + //todo:dup 指令传入两个相同的引用,要先拷贝一份。 +// Slot slot = operandStack.popSlot(); +// operandStack.pushSlot(slot); +// operandStack.pushSlot(slot); } public class Dup_X1 extends OperandsInstruction { @@ -307,7 +312,7 @@ public class OperandsInstruction implements Instruction { Slot slot2 = operandStack.popSlot(); operandStack.pushSlot(slot1); operandStack.pushSlot(slot2); - operandStack.pushSlot(slot1); + operandStack.pushSlot(slot1.copySlot()); } } @@ -321,7 +326,7 @@ public class OperandsInstruction implements Instruction { operandStack.pushSlot(slot1); operandStack.pushSlot(slot3); operandStack.pushSlot(slot2); - operandStack.pushSlot(slot1); + operandStack.pushSlot(slot1.copySlot()); } } @@ -334,7 +339,7 @@ public class OperandsInstruction implements Instruction { operandStack.pushSlot(slot2); operandStack.pushSlot(slot1); operandStack.pushSlot(slot2); - operandStack.pushSlot(slot1); + operandStack.pushSlot(slot1.copySlot()); } } @@ -348,8 +353,8 @@ public class OperandsInstruction implements Instruction { operandStack.pushSlot(slot2); operandStack.pushSlot(slot1); operandStack.pushSlot(slot3); - operandStack.pushSlot(slot2); - operandStack.pushSlot(slot1); + operandStack.pushSlot(slot2.copySlot()); + operandStack.pushSlot(slot1.copySlot()); } } @@ -365,8 +370,8 @@ public class OperandsInstruction implements Instruction { operandStack.pushSlot(slot1); operandStack.pushSlot(slot4); operandStack.pushSlot(slot3); - operandStack.pushSlot(slot2); - operandStack.pushSlot(slot1); + operandStack.pushSlot(slot2.copySlot()); + operandStack.pushSlot(slot1.copySlot()); } } diff --git a/src/com/gabongao/jvm/rtda/Frame.java b/src/com/gabongao/jvm/rtda/Frame.java index 69f267d..8355a0a 100644 --- a/src/com/gabongao/jvm/rtda/Frame.java +++ b/src/com/gabongao/jvm/rtda/Frame.java @@ -8,6 +8,8 @@ package com.gabongao.jvm.rtda; +import com.gabongao.jvm.rtda.heap.Method; + /** *         ┏┓   ┏┓+ + *        ┏┛┻━━━┛┻┓ + + @@ -37,6 +39,7 @@ public class Frame { private LocalVars localVars; private OperandStack operandStack; private Thread thread; + private Method method; private int nextPc; public Frame(Thread thread, int maxLocals, int maxStack) { @@ -45,6 +48,17 @@ public class Frame { operandStack = new OperandStack(maxStack); } + public Frame(Thread thread, Method method) { + this.thread = thread; + this.method = method; + this.localVars = new LocalVars(method.getMaxLocals()); + this.operandStack = new OperandStack(method.getMaxStack()); + } + + public Method getMethod() { + return method; + } + public LocalVars getLocalVars() { return localVars; } diff --git a/src/com/gabongao/jvm/rtda/LocalVars.java b/src/com/gabongao/jvm/rtda/LocalVars.java index 98b71fc..53f9597 100644 --- a/src/com/gabongao/jvm/rtda/LocalVars.java +++ b/src/com/gabongao/jvm/rtda/LocalVars.java @@ -8,6 +8,8 @@ package com.gabongao.jvm.rtda; +import com.gabongao.jvm.rtda.heap.Object; + import java.util.Arrays; /** @@ -37,16 +39,19 @@ import java.util.Arrays; public class LocalVars { private Slot[] slots; - LocalVars(int maxLocals) { - if (maxLocals > 0) { + public LocalVars(int maxLocals) { + if (maxLocals >= 0) { slots = new Slot[maxLocals]; + for (int i = 0; i < maxLocals; i++) { + slots[i] = new Slot(); + } } else { throw new RuntimeException("LocalVars Count Error"); } } public void setInt(int index, int val) { - slots[index] = new Slot(); +// slots[index] = new Slot(); slots[index].setNum(val); } @@ -55,7 +60,7 @@ public class LocalVars { } public void setFloat(int index, float val) { - slots[index] = new Slot(); +// slots[index] = new Slot(); slots[index].setNum(Float.floatToRawIntBits(val)); } @@ -64,7 +69,7 @@ public class LocalVars { } public void setLong(int index, long val) { - slots[index] = new Slot(); +// slots[index] = new Slot(); slots[index].setNum((int) val); slots[index + 1] = new Slot(); slots[index + 1].setNum((int) (val >> 32)); @@ -77,7 +82,7 @@ public class LocalVars { } public void setRef(int index, Object ref) { - slots[index] = new Slot(); +// slots[index] = new Slot(); slots[index].setRef(ref); } diff --git a/src/com/gabongao/jvm/rtda/OperandStack.java b/src/com/gabongao/jvm/rtda/OperandStack.java index 9cc3d94..11d182f 100644 --- a/src/com/gabongao/jvm/rtda/OperandStack.java +++ b/src/com/gabongao/jvm/rtda/OperandStack.java @@ -8,6 +8,8 @@ package com.gabongao.jvm.rtda; +import com.gabongao.jvm.rtda.heap.Object; + import java.util.Arrays; /** @@ -41,6 +43,9 @@ public class OperandStack { public OperandStack(int maxStacks) { if (maxStacks > 0) { slots = new Slot[maxStacks]; + for (int i = 0; i < maxStacks; i++) { + slots[i] = new Slot(); + } } else { throw new RuntimeException("Operands Count Error"); } @@ -55,7 +60,7 @@ public class OperandStack { } public void pushInt(int val) { - slots[size] = new Slot(); +// slots[size] = new Slot(); slots[size].setNum(val); size++; } @@ -66,7 +71,7 @@ public class OperandStack { } public void pushFloat(float val) { - slots[size] = new Slot(); +// slots[size] = new Slot(); slots[size].setNum(Float.floatToRawIntBits(val)); size++; } @@ -77,9 +82,9 @@ public class OperandStack { } public void pushLong(long val) { - slots[size] = new Slot(); +// slots[size] = new Slot(); slots[size].setNum((int) val); - slots[size + 1] = new Slot(); +// slots[size + 1] = new Slot(); slots[size + 1].setNum((int) (val >> 32)); size += 2; } @@ -92,7 +97,7 @@ public class OperandStack { } public void pushRef(Object ref) { - slots[size] = new Slot(); +// slots[size] = new Slot(); slots[size].setRef(ref); size++; } diff --git a/src/com/gabongao/jvm/rtda/Slot.java b/src/com/gabongao/jvm/rtda/Slot.java index b902612..2202364 100644 --- a/src/com/gabongao/jvm/rtda/Slot.java +++ b/src/com/gabongao/jvm/rtda/Slot.java @@ -8,6 +8,8 @@ package com.gabongao.jvm.rtda; +import com.gabongao.jvm.rtda.heap.Object; + /** *         ┏┓   ┏┓+ + *        ┏┛┻━━━┛┻┓ + + @@ -36,6 +38,11 @@ public class Slot { private int num; private Object ref; + public Slot() { + this.num = 0; + this.ref = new Object(); + } + @Override public String toString() { return "Slot{" + @@ -59,4 +66,12 @@ public class Slot { public void setRef(Object ref) { this.ref = ref; } + + public Slot copySlot() { + Slot s = new Slot(); + s.setNum(this.getNum()); + s.setRef(this.getRef()); + return s; + } + } diff --git a/src/com/gabongao/jvm/rtda/heap/AccessFlags.java b/src/com/gabongao/jvm/rtda/heap/AccessFlags.java new file mode 100644 index 0000000..388874a --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/AccessFlags.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public enum AccessFlags { + ACCESS_PUBLIC(0X0001), //class field method + ACCESS_PRIVATE(0X0002), // field method + ACCESS_PROTECTED(0X0004), // field method + ACCESS_STATIC(0X0008), // field method + ACCESS_FINAL(0X0010), //class field method + ACCESS_SUPER(0X0020), //class + ACCESS_SYNCHRONIZED(0X0020), // method + ACCESS_VOLATILE(0X0040), // field + ACCESS_BRIDGE(0X0040), // method + ACCESS_TRANSIENT(0X0080), // field + ACCESS_VARARGS(0X0080), // method + ACCESS_NATIVE(0X0100), // method + ACCESS_INTERFACE(0X0200), //class + ACCESS_ABSTRACT(0X0400), //class method + ACCESS_STRICT(0X0800), // method + ACCESS_SYNTHETIC(0X1000), //class field method + ACCESS_ANNOTATION(0X2000), //class + ACCESS_ENUM(0X4000), //class field + ; + private int value; + + AccessFlags(int value) { + this.value = value; + } + + public int getValue() { + return value; + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/ClassLoader.java b/src/com/gabongao/jvm/rtda/heap/ClassLoader.java new file mode 100644 index 0000000..fac7595 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/ClassLoader.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.ClassFile; +import com.gabongao.jvm.classpath.ClassPath; + +import java.util.HashMap; +import java.util.LinkedHashMap; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class ClassLoader { + private ClassPath classPath; + private HashMap classStructHashMap; + + public ClassLoader(ClassPath classPath) { + this.classPath = classPath; + classStructHashMap = new LinkedHashMap<>(); + } + + public ClassStruct loadClass(String name) { + ClassStruct classStruct = classStructHashMap.get(name); + if (classStruct == null) { + return loadNonArrayClass(name); + } + return classStruct; + } + + private ClassStruct loadNonArrayClass(String name) { + byte[] classData = classPath.readClass(name); + ClassStruct classStruct = defineClass(classData); + link(classStruct); + System.out.printf("Loaded class %s \n", name); + return classStruct; + } + + private ClassStruct defineClass(byte[] classData) { + ClassStruct classStruct = parseClass(classData); + classStruct.setClassLoader(this); + resolveSuperClass(classStruct); + resolveInterfaces(classStruct); + classStructHashMap.put(classStruct.getClassName(), classStruct); + return classStruct; + } + + private ClassStruct parseClass(byte[] classData) { + ClassFile classFile = new ClassFile(classData); + classFile.read(); + return new ClassStruct(classFile); + } + + private void resolveSuperClass(ClassStruct classStruct) { + if (!classStruct.getClassName().equals("java/lang/Object")) { + classStruct.setSuperClass(classStruct.getClassLoader().loadClass(classStruct.getSuperClassName())); + } + } + + private void resolveInterfaces(ClassStruct classStruct) { + int interfaceCount = classStruct.getInterfaceNames() == null ? 0 : classStruct.getInterfaceNames().length; + if (interfaceCount > 0) { + classStruct.setInterfaces(new ClassStruct[interfaceCount]); + for (int i = 0; i < interfaceCount; i++) { + classStruct.getInterfaces()[i] = classStruct.getClassLoader().loadClass(classStruct.getInterfaceNames()[i]); + } + } + } + + private void link(ClassStruct classStruct) { + verify(classStruct); + prepare(classStruct); + } + + private void verify(ClassStruct classStruct) { + //todo:verify class + } + + private void prepare(ClassStruct classStruct) { + calcInstanceFieldSlotIds(classStruct); + calcStaticFieldSlotIds(classStruct); + allocAndInitStaticVars(classStruct); + } + + private void calcInstanceFieldSlotIds(ClassStruct classStruct) { + int slotId = 0; + if (classStruct.getSuperClassName() != null) { + slotId = classStruct.getSuperClass() == null ? 0 : classStruct.getSuperClass().getInstanceSlotCount(); + } + Field[] fields = classStruct.getFields(); + int len = fields.length; + for (int i = 0; i < len; i++) { + if (!fields[i].IsStatic()) { + fields[i].setSlotId(slotId); + slotId++; + if (fields[i].isLongOrDouble()) { + slotId++; + } + } + } + classStruct.setInstanceSlotCount(slotId); + } + + private void calcStaticFieldSlotIds(ClassStruct classStruct) { + int slotId = 0; + Field[] fields = classStruct.getFields(); + int len = fields.length; + for (int i = 0; i < len; i++) { + if (fields[i].IsStatic()) { + fields[i].setSlotId(slotId); + slotId++; + if (fields[i].isLongOrDouble()) { + slotId++; + } + } + } + classStruct.setStaticSlotCount(slotId); + } + + private void allocAndInitStaticVars(ClassStruct classStruct) { + classStruct.setStaticVars(new Slots(classStruct.getStaticSlotCount())); + Field[] fields = classStruct.getFields(); + int len = fields.length; + for (int i = 0; i < len; i++) { + if (fields[i].IsStatic() && fields[i].IsFinal()) { + initStaticFinalVar(classStruct, fields[i]); + } + } + } + + private void initStaticFinalVar(ClassStruct classStruct, Field field) { + Slots slots = classStruct.getStaticVars(); + ConstantPool cp = classStruct.getConstantPool(); + int cpIndex = field.getConstValueIndex(); + int slotId = field.getSlotId(); + if (cpIndex > 0) { + switch (field.getDescriptor()) { + case "Z": + case "B": + case "C": + case "S": + case "I": + int vali = (int) cp.getConstant(cpIndex).getObject(); + slots.setInt(slotId, vali); + break; + case "J": + long vall = (Long) cp.getConstant(cpIndex).getObject(); + slots.setLong(slotId, vall); + break; + case "F": + float valf = (Float) cp.getConstant(cpIndex).getObject(); + slots.setFloat(slotId, valf); + break; + case "D": + double vald = (Double) cp.getConstant(cpIndex).getObject(); + slots.setDouble(cpIndex, vald); + break; + case "Ljava/lang/String;": + throw new RuntimeException("todo"); + //todo + } + } + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/ClassMember.java b/src/com/gabongao/jvm/rtda/heap/ClassMember.java new file mode 100644 index 0000000..df4eb11 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/ClassMember.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.AttrConstantValue; +import com.gabongao.jvm.classfile.MemberInfo; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class ClassMember { + protected char accessFlags; + protected String name, descriptor; + private ClassStruct classStruct; + + public ClassMember(MemberInfo memberInfo) { + this.accessFlags = memberInfo.getAccessFlags(); + this.name = memberInfo.getName(); + this.descriptor = memberInfo.getDescriptor(); + } + + public boolean isAccessibleTo(ClassStruct d) { + if (IsPublic()) { + return true; + } + ClassStruct c = classStruct; + if (IsProtected()) { + return d.equals(c) || d.isSubClassOf(c) || c.getPackageName().equals(d.getPackageName()); + } + if (!IsPrivate()) { + return c.getPackageName().equals(d.getPackageName()); + } + return d.equals(c); + } + + public String getName() { + return name; + } + + public String getDescriptor() { + return descriptor; + } + + public ClassStruct getClassStruct() { + return classStruct; + } + + public void setClassStruct(ClassStruct classStruct) { + this.classStruct = classStruct; + } + + public char getAccessFlags() { + return accessFlags; + } + + public boolean IsFinal() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_FINAL.getValue()); + } + + public boolean IsSynthetic() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_SYNTHETIC.getValue()); + } + + public boolean IsEnum() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_ENUM.getValue()); + } + + public boolean IsPublic() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_PUBLIC.getValue()); + } + + public boolean IsPrivate() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_PRIVATE.getValue()); + } + + public boolean IsProtected() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_PROTECTED.getValue()); + } + + public boolean IsStatic() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_STATIC.getValue()); + } + + public boolean IsVolatile() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_VOLATILE.getValue()); + } + + public boolean IsTransient() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_TRANSIENT.getValue()); + } + +} diff --git a/src/com/gabongao/jvm/rtda/heap/ClassRef.java b/src/com/gabongao/jvm/rtda/heap/ClassRef.java new file mode 100644 index 0000000..8670e9d --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/ClassRef.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.ConstantClassInfo; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class ClassRef extends SymRef { + public ClassRef(ConstantPool constantPool, ConstantClassInfo classInfo) { + super(constantPool); + setClassName(classInfo.getName()); + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/ClassStruct.java b/src/com/gabongao/jvm/rtda/heap/ClassStruct.java new file mode 100644 index 0000000..2dbb0d4 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/ClassStruct.java @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.*; + +import java.lang.*; +import java.lang.Object; +import java.util.Arrays; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class ClassStruct { + private char accessFlags; + private String className, superClassName; + private String[] interfaceNames; + private ConstantPool constantPool; + private Field[] fields; + private Method[] methods; + private ClassLoader classLoader; + private ClassStruct superClass; + private ClassStruct[] interfaces; + private int instanceSlotCount, staticSlotCount; + private Slots staticVars; + + public ClassStruct(ClassFile classFile) { + this.accessFlags = classFile.getAccessFlags(); + this.className = classFile.thisClassName(); + this.superClassName = classFile.superClassName(); + this.interfaceNames = classFile.interfaceNames(); + this.constantPool = newConstantPool(classFile.getConstantPool()); + this.fields = newFields(classFile.getFields()); + this.methods = newMethods(classFile.getMethods()); + } + + public com.gabongao.jvm.rtda.heap.Object newObject() { + return new com.gabongao.jvm.rtda.heap.Object(this); + } + + private ConstantPool newConstantPool(com.gabongao.jvm.classfile.ConstantPool cfCp) { + int cpCount = cfCp.getConstantInfos().length; + Constant[] constants = new Constant[cpCount]; + ConstantPool rtCp = new ConstantPool(this, constants); + for (int i = 1; i < cpCount; i++) { + ConstantInfo cpInfo = cfCp.getConstantInfos()[i]; + switch (cpInfo.getClass().getName()) { + case "com.gabongao.jvm.classfile.ConstantIntegerInfo": + ConstantIntegerInfo constantIntegerInfo = (ConstantIntegerInfo) cpInfo; + constants[i] = new Constant(constantIntegerInfo.getVal()); + break; + case "com.gabongao.jvm.classfile.ConstantLongInfo": + ConstantLongInfo constantLongInfo = (ConstantLongInfo) cpInfo; + constants[i] = new Constant(constantLongInfo.getVal()); + i++; + break; + case "com.gabongao.jvm.classfile.ConstantDoubleInfo": + ConstantDoubleInfo constantDoubleInfo = (ConstantDoubleInfo) cpInfo; + constants[i] = new Constant(constantDoubleInfo.getVal()); + break; + case "com.gabongao.jvm.classfile.ConstantStringInfo": + ConstantStringInfo constantStringInfo = (ConstantStringInfo) cpInfo; + constants[i] = new Constant(constantStringInfo.getString()); + break; + case "com.gabongao.jvm.classfile.ConstantClassInfo": + ConstantClassInfo classInfo = (ConstantClassInfo) cpInfo; + ClassRef classRef = new ClassRef(rtCp, classInfo); +// classRef.setClassStruct(this); + constants[i] = new Constant(classRef); + break; + case "com.gabongao.jvm.classfile.ConstantFieldrefInfo": + ConstantFieldrefInfo fieldrefInfo = (ConstantFieldrefInfo) cpInfo; + FieldRef ref = new FieldRef(rtCp, fieldrefInfo); +// ref.setClassStruct(this); + constants[i] = new Constant(ref); + break; + case "com.gabongao.jvm.classfile.ConstantMethodrefInfo": + ConstantMethodrefInfo methodrefInfo = (ConstantMethodrefInfo) cpInfo; + MethodRef methodRef = new MethodRef(rtCp, methodrefInfo); +// methodRef.setClassStruct(this); + constants[i] = new Constant(methodRef); + break; + case "com.gabongao.jvm.classfile.ConstantInterfaceMethodrefInfo": + ConstantInterfaceMethodrefInfo interfaceMethodrefInfo = (ConstantInterfaceMethodrefInfo) cpInfo; + InterfaceMethodRef interfaceMethodRef = new InterfaceMethodRef(rtCp, interfaceMethodrefInfo); +// interfaceMethodRef.setClassStruct(this); + constants[i] = new Constant(interfaceMethodRef); + break; + } + } + return rtCp; + } + + private Method[] newMethods(MemberInfo[] cfMethods) { + Method[] methods = new Method[cfMethods.length]; + for (int i = 0; i < cfMethods.length; i++) { + methods[i] = new Method(cfMethods[i]); + methods[i].getClassMember().setClassStruct(this); + } + return methods; + } + + private Field[] newFields(MemberInfo[] cfFields) { + Field[] fields = new Field[cfFields.length]; + for (int i = 0; i < cfFields.length; i++) { + fields[i] = new Field(cfFields[i]); + fields[i].setClassStruct(this); + } + return fields; + } + + public boolean isAccessibleTo(ClassStruct other) { + return this.IsPublic() || this.getPackageName().equals(other.getPackageName()); + } + + public boolean isSubClassOf(ClassStruct other) { + for (ClassStruct c = superClass; c != null; c = c.superClass) { + if (c == other) { + return true; + } + } + return false; + } + + public String getPackageName() { + int i = className.lastIndexOf("/"); + if (i >= 0) { + return className.substring(0, i); + } + return ""; + } + + public boolean IsPublic() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_PUBLIC.getValue()); + } + + public boolean IsFinal() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_FINAL.getValue()); + } + + public boolean IsSuper() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_SUPER.getValue()); + } + + public boolean IsInterface() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_INTERFACE.getValue()); + } + + public boolean IsAbstract() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_ABSTRACT.getValue()); + } + + public boolean IsSynthetic() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_SYNTHETIC.getValue()); + } + + public boolean IsAnnotation() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_ANNOTATION.getValue()); + } + + public boolean IsEnum() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_ENUM.getValue()); + } + + public char getAccessFlags() { + return accessFlags; + } + + public void setAccessFlags(char accessFlags) { + this.accessFlags = accessFlags; + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public String getSuperClassName() { + return superClassName; + } + + public void setSuperClassName(String superClassName) { + this.superClassName = superClassName; + } + + public String[] getInterfaceNames() { + return interfaceNames; + } + + public void setInterfaceNames(String[] interfaceNames) { + this.interfaceNames = interfaceNames; + } + + public ConstantPool getConstantPool() { + return constantPool; + } + + public void setConstantPool(ConstantPool constantPool) { + this.constantPool = constantPool; + } + + public Field[] getFields() { + return fields; + } + + public void setFields(Field[] fields) { + this.fields = fields; + } + + public Method[] getMethods() { + return methods; + } + + public void setMethods(Method[] methods) { + this.methods = methods; + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public ClassStruct getSuperClass() { + return superClass; + } + + public void setSuperClass(ClassStruct superClass) { + this.superClass = superClass; + } + + public ClassStruct[] getInterfaces() { + return interfaces; + } + + public void setInterfaces(ClassStruct[] interfaces) { + this.interfaces = interfaces; + } + + public int getInstanceSlotCount() { + return instanceSlotCount; + } + + public void setInstanceSlotCount(int instanceSlotCount) { + this.instanceSlotCount = instanceSlotCount; + } + + public int getStaticSlotCount() { + return staticSlotCount; + } + + public void setStaticSlotCount(int staticSlotCount) { + this.staticSlotCount = staticSlotCount; + } + + public Slots getStaticVars() { + return staticVars; + } + + public void setStaticVars(Slots staticVars) { + this.staticVars = staticVars; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ClassStruct)) return false; + + ClassStruct that = (ClassStruct) o; + + if (getAccessFlags() != that.getAccessFlags()) return false; + if (getInstanceSlotCount() != that.getInstanceSlotCount()) return false; + if (getStaticSlotCount() != that.getStaticSlotCount()) return false; + if (!getClassName().equals(that.getClassName())) return false; + if (!getSuperClassName().equals(that.getSuperClassName())) return false; + if (!getConstantPool().equals(that.getConstantPool())) return false; + if (!getClassLoader().equals(that.getClassLoader())) return false; + if (!getSuperClass().equals(that.getSuperClass())) return false; + return getStaticVars().equals(that.getStaticVars()); + } + + @Override + public int hashCode() { + int result = (int) getAccessFlags(); + result = 31 * result + (getClassName() != null ? getClassName().hashCode() : 0); + result = 31 * result + (getSuperClassName() != null ? getSuperClassName().hashCode() : 0); + result = 31 * result + Arrays.hashCode(getInterfaceNames()); + result = 31 * result + (getConstantPool() != null ? getConstantPool().hashCode() : 0); + result = 31 * result + Arrays.hashCode(getFields()); + result = 31 * result + Arrays.hashCode(getMethods()); + result = 31 * result + (getClassLoader() != null ? getClassLoader().hashCode() : 0); + result = 31 * result + (getSuperClass() != null ? getSuperClass().hashCode() : 0); + result = 31 * result + Arrays.hashCode(getInterfaces()); + result = 31 * result + getInstanceSlotCount(); + result = 31 * result + getStaticSlotCount(); + result = 31 * result + (getStaticVars() != null ? getStaticVars().hashCode() : 0); + return result; + } + + public boolean isAssignableFrom(ClassStruct other) { + ClassStruct s = other; + ClassStruct t = this; + if (s.equals(t)) { + return true; + } + if (!t.IsInterface()) { + return s.isSubClassOf(t); + } else { + return s.isImplements(t); + } + } + + public boolean isImplements(ClassStruct iface) { + for (ClassStruct c = this.superClass; c != null; c = c.getSuperClass()) { + for (ClassStruct cs : c.interfaces + ) { + if (cs.equals(iface) || cs.isSubInterfaceOf(iface)) { + return true; + } + } + } + return false; + } + + public boolean isSubInterfaceOf(ClassStruct iface) { + for (ClassStruct superInterface : this.interfaces + ) { + if (superInterface.equals(iface) || superInterface.isSubInterfaceOf(iface)) { + return true; + } + } + return false; + } + + public Method getMainMethod() { + return this.getStaticMethod("main", "([Ljava/lang/String;)V"); + } + + public Method getStaticMethod(String name, String descriptor) { + for (Method method : methods + ) { + if (method.IsStatic() && method.getClassMember().getName().equals(name) && method.getClassMember().getDescriptor().equals(descriptor)) { + return method; + } + } + return null; + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/Constant.java b/src/com/gabongao/jvm/rtda/heap/Constant.java new file mode 100644 index 0000000..441bb63 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/Constant.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import java.lang.*; +import java.lang.Object; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class Constant { + private java.lang.Object object; + + public Constant(Object object) { + this.object = object; + } + + public Object getObject() { + return object; + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/ConstantPool.java b/src/com/gabongao/jvm/rtda/heap/ConstantPool.java new file mode 100644 index 0000000..3e0e533 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/ConstantPool.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class ConstantPool { + private ClassStruct classStruct; + private Constant[] constants; + + ConstantPool(ClassStruct classStruct, Constant[] constants) { + this.constants = constants; + this.classStruct = classStruct; + } + + + public Constant getConstant(int index) { + if (index >= constants.length) { + throw new RuntimeException("getConstant Array out of bound"); + } + return constants[index] == null ? null : constants[index]; + } + + public ClassStruct getClassStruct() { + return classStruct; + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/Field.java b/src/com/gabongao/jvm/rtda/heap/Field.java new file mode 100644 index 0000000..0d8ffd7 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/Field.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.AttrConstantValue; +import com.gabongao.jvm.classfile.MemberInfo; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class Field extends ClassMember { + private int slotId; + private int constValueIndex; + + public Field(MemberInfo memberInfo) { + super(memberInfo); + AttrConstantValue attr = memberInfo.getConstantValueAttribute(); + if (attr != null) { + constValueIndex = attr.getConstantValueIndex(); + } + } + + public int getConstValueIndex() { + return constValueIndex; + } + + public boolean IsFinal() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_FINAL.getValue()); + } + + public boolean IsSynthetic() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_SYNTHETIC.getValue()); + } + + public boolean IsEnum() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_ENUM.getValue()); + } + + public boolean IsPublic() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_PUBLIC.getValue()); + } + + public boolean IsPrivate() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_PRIVATE.getValue()); + } + + public boolean IsProtected() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_PROTECTED.getValue()); + } + + public boolean IsStatic() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_STATIC.getValue()); + } + + public boolean IsVolatile() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_VOLATILE.getValue()); + } + + public boolean IsTransient() { + return 0 != (((int) accessFlags) & AccessFlags.ACCESS_TRANSIENT.getValue()); + } + + + public char getAccessFlags() { + return accessFlags; + } + + public void setAccessFlags(char accessFlags) { + this.accessFlags = accessFlags; + } + + public int getSlotId() { + return slotId; + } + + public void setSlotId(int slotId) { + this.slotId = slotId; + } + + public boolean isLongOrDouble() { + return descriptor.equals("J") || descriptor.equals("D"); + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/FieldRef.java b/src/com/gabongao/jvm/rtda/heap/FieldRef.java new file mode 100644 index 0000000..e0f9cca --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/FieldRef.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.*; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class FieldRef extends MemberRef { + private Field field; + + public FieldRef(ConstantPool constantPool, ConstantMemberrefInfo memberrefInfo) { + super(constantPool, memberrefInfo); + } + + public Field resolvedField() { + if (field == null) { + resolveFieldRef(); + } + return field; + } + + public void resolveFieldRef() { + ClassStruct d = constantPool.getClassStruct(); + ClassStruct c = resolvedClass(); + field = lookupField(c, name, descriptor); + if (field == null) { + throw new RuntimeException("NoSuchFieldError"); + } + if (!field.isAccessibleTo(d)) { + throw new RuntimeException("IllegalAccessError"); + } + } + + public Field lookupField(ClassStruct c, String name, String descriptor) { + for (Field f : c.getFields() + ) { + if (f.getName().equals(name) && f.descriptor.equals(descriptor)) { + return f; + } + } + for (ClassStruct cs : c.getInterfaces() + ) { + Field field = lookupField(cs, name, descriptor); + if (field != null) { + return field; + } + } + if (c.getSuperClass() != null) { + return lookupField(c.getSuperClass(), name, descriptor); + } + return null; + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/InterfaceMethodRef.java b/src/com/gabongao/jvm/rtda/heap/InterfaceMethodRef.java new file mode 100644 index 0000000..ad47da1 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/InterfaceMethodRef.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.ConstantMemberrefInfo; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class InterfaceMethodRef extends MemberRef { + private Method method; + + public InterfaceMethodRef(ConstantPool constantPool, ConstantMemberrefInfo memberrefInfo) { + super(constantPool, memberrefInfo); + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/MemberRef.java b/src/com/gabongao/jvm/rtda/heap/MemberRef.java new file mode 100644 index 0000000..1576e95 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/MemberRef.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.ConstantClassInfo; +import com.gabongao.jvm.classfile.ConstantMemberrefInfo; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class MemberRef extends SymRef { + protected String name, descriptor; + + public MemberRef(ConstantPool constantPool, ConstantMemberrefInfo memberrefInfo) { + super(constantPool); + super.setClassName(memberrefInfo.getClassName()); + name = memberrefInfo.nameAndDescriptor()[0]; + descriptor = memberrefInfo.nameAndDescriptor()[1]; + } + + public String getDescriptor() { + return descriptor; + } + + public String getName() { + return name; + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/Method.java b/src/com/gabongao/jvm/rtda/heap/Method.java new file mode 100644 index 0000000..a5b04ef --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/Method.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.MemberInfo; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class Method { + ClassMember classMember; + int maxStack, maxLocals; + byte[] code; + + Method(MemberInfo memberInfo) { + classMember = new ClassMember(memberInfo); + maxLocals = memberInfo.getCodeAttribure() == null ? 0 : memberInfo.getCodeAttribure().getMaxLocals(); + maxStack = memberInfo.getCodeAttribure() == null ? 0 : memberInfo.getCodeAttribure().getMaxStack(); + code = memberInfo.getCodeAttribure() == null ? null : memberInfo.getCodeAttribure().getCode(); + } + + public ClassMember getClassMember() { + return classMember; + } + + public void setClassMember(ClassMember classMember) { + this.classMember = classMember; + } + + public int getMaxStack() { + return maxStack; + } + + public void setMaxStack(int maxStack) { + this.maxStack = maxStack; + } + + public int getMaxLocals() { + return maxLocals; + } + + public void setMaxLocals(int maxLocals) { + this.maxLocals = maxLocals; + } + + public byte[] getCode() { + return code; + } + + public void setCode(byte[] code) { + this.code = code; + } + + public boolean IsFinal() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_FINAL.getValue()); + } + + public boolean IsAbstract() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_ABSTRACT.getValue()); + } + + public boolean IsSynthetic() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_SYNTHETIC.getValue()); + } + + public boolean IsPublic() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_PUBLIC.getValue()); + } + + public boolean IsPrivate() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_PRIVATE.getValue()); + } + + public boolean IsProtected() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_PROTECTED.getValue()); + } + + public boolean IsStatic() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_STATIC.getValue()); + } + + public boolean IsSynchronized() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_SYNCHRONIZED.getValue()); + } + + public boolean IsBridge() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_BRIDGE.getValue()); + } + + public boolean IsVarargs() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_VARARGS.getValue()); + } + + public boolean IsNative() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_NATIVE.getValue()); + } + + public boolean IsStrict() { + return 0 != (((int) classMember.accessFlags) & AccessFlags.ACCESS_STRICT.getValue()); + } + + public char getAccessFlags() { + return classMember.accessFlags; + } + + public void setAccessFlags(char accessFlags) { + this.classMember.accessFlags = accessFlags; + } + + +} diff --git a/src/com/gabongao/jvm/rtda/heap/MethodRef.java b/src/com/gabongao/jvm/rtda/heap/MethodRef.java new file mode 100644 index 0000000..2a5e548 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/MethodRef.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.ConstantMemberrefInfo; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class MethodRef extends MemberRef { + private Method method; + + public MethodRef(ConstantPool constantPool, ConstantMemberrefInfo memberrefInfo) { + super(constantPool, memberrefInfo); + } + + public Method getMethod() { + return method; + } +} diff --git a/src/com/gabongao/jvm/rtda/heap/Object.java b/src/com/gabongao/jvm/rtda/heap/Object.java new file mode 100644 index 0000000..1c251d8 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/Object.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *            ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/18. + */ +public class Object { + private ClassStruct classStruct; + private Slots fields; + //TODO + + public Object() { + } + + public Object(ClassStruct classStruct) { + this.classStruct = classStruct; + this.fields = new Slots(classStruct.getInstanceSlotCount()); + } + + public ClassStruct getClassStruct() { + return classStruct; + } + + public Slots getFields() { + return fields; + } + + public boolean isInstanceOf(ClassStruct classStruct) { + return classStruct.isAssignableFrom(this.classStruct); + } +} diff --git a/src/com/gabongao/jvm/rtda/Object.java b/src/com/gabongao/jvm/rtda/heap/Slots.java similarity index 88% rename from src/com/gabongao/jvm/rtda/Object.java rename to src/com/gabongao/jvm/rtda/heap/Slots.java index 0dd1b0c..7ca21e2 100644 --- a/src/com/gabongao/jvm/rtda/Object.java +++ b/src/com/gabongao/jvm/rtda/heap/Slots.java @@ -6,7 +6,9 @@ * Vestibulum commodo. Ut rhoncus gravida arcu. */ -package com.gabongao.jvm.rtda; +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.rtda.LocalVars; /** *         ┏┓   ┏┓+ + @@ -30,8 +32,10 @@ package com.gabongao.jvm.rtda; *          ┗┓┓┏━┳┓┏┛ + + + + *           ┃┫┫ ┃┫┫ *           ┗┻┛ ┗┻┛+ + + + - * Created by Imgaojp on 2017/2/18. + * Created by Imgaojp on 2017/2/20. */ -public class Object { - //TODO +public class Slots extends LocalVars { + public Slots(int slotCount) { + super(slotCount); + } } diff --git a/src/com/gabongao/jvm/rtda/heap/SymRef.java b/src/com/gabongao/jvm/rtda/heap/SymRef.java new file mode 100644 index 0000000..7fb9439 --- /dev/null +++ b/src/com/gabongao/jvm/rtda/heap/SymRef.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gabongao.jvm.rtda.heap; + +import com.gabongao.jvm.classfile.ConstantClassInfo; + +/** + *         ┏┓   ┏┓+ + + *        ┏┛┻━━━┛┻┓ + + + *        ┃       ┃ + *        ┃   ━   ┃ ++ + + + + *        ████━████ ┃+ + *        ┃       ┃ + + *        ┃   ┻   ┃ + *        ┃       ┃ + + + *        ┗━┓   ┏━┛ + *          ┃   ┃ + *          ┃   ┃ + + + + + *          ┃   ┃    Code is far away from bug with the animal protecting + *          ┃   ┃ +     神兽保佑,代码无bug + *          ┃   ┃ + *          ┃   ┃  + + *          ┃    ┗━━━┓ + + + *          ┃        ┣┓ + *          ┃        ┏┛ + *          ┗┓┓┏━┳┓┏┛ + + + + + *           ┃┫┫ ┃┫┫ + *           ┗┻┛ ┗┻┛+ + + + + * Created by Imgaojp on 2017/2/20. + */ +public class SymRef { + ConstantPool constantPool; + String className; + private ClassStruct classStruct; + + public SymRef(ConstantPool constantPool) { + this.constantPool = constantPool; + } + + public ConstantPool getConstantPool() { + return constantPool; + } + + public void setConstantPool(ConstantPool constantPool) { + this.constantPool = constantPool; + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public ClassStruct getClassStruct() { + return classStruct; + } + + public void setClassStruct(ClassStruct classStruct) { + this.classStruct = classStruct; + } + + public ClassStruct resolvedClass() { + if (this.classStruct == null) { + resolvedClassRef(); + } + return classStruct; + } + + public void resolvedClassRef() { + ClassStruct d = constantPool.getClassStruct(); + ClassStruct c = d.getClassLoader().loadClass(className); + if (!c.isAccessibleTo(d)) { + throw new RuntimeException("java.lang.IllegalAccessError"); + } + classStruct = c; + } +}