Repository: zachaxy/JVM Branch: master Commit: 0e3b830c12d5 Files: 299 Total size: 315.3 KB Directory structure: gitextract_uyxsbubc/ ├── .gitignore ├── Java/ │ └── src/ │ ├── Main.java │ ├── Utils/ │ │ ├── ByteUtils.java │ │ └── Cmd.java │ ├── classfile/ │ │ ├── ClassFile.java │ │ ├── ClassReader.java │ │ ├── ConstantPool.java │ │ ├── MemberInfo.java │ │ ├── attribute/ │ │ │ ├── AttributeInfo.java │ │ │ ├── CodeAttribute.java │ │ │ ├── ConstantValueAttribute.java │ │ │ ├── DeprecatedAttribute.java │ │ │ ├── ExceptionsAttribute.java │ │ │ ├── LineNumberTableAttribute.java │ │ │ ├── LocalVariableTableAttribute.java │ │ │ ├── SourceFileAttribute.java │ │ │ ├── SyntheticAttribute.java │ │ │ └── UnparsedAttribute.java │ │ └── classconstant/ │ │ ├── ConstantClassInfo.java │ │ ├── ConstantDoubleInfo.java │ │ ├── ConstantFieldRefInfo.java │ │ ├── ConstantFloatInfo.java │ │ ├── ConstantInfo.java │ │ ├── ConstantIntegerInfo.java │ │ ├── ConstantInterfaceMethodRefInfo.java │ │ ├── ConstantInvokeDynamicInfo.java │ │ ├── ConstantLongInfo.java │ │ ├── ConstantMemberRefInfo.java │ │ ├── ConstantMethodHandleInfo.java │ │ ├── ConstantMethodRefInfo.java │ │ ├── ConstantMethodTypeInfo.java │ │ ├── ConstantNameAndTypeInfo.java │ │ ├── ConstantStringInfo.java │ │ └── ConstantUtf8Info.java │ ├── classpath/ │ │ ├── ClassPath.java │ │ ├── CompositeEntry.java │ │ ├── DirEntry.java │ │ ├── Entry.java │ │ ├── WildcardEntry.java │ │ └── ZipJarEntry.java │ ├── instructions/ │ │ ├── InstructionFactory.java │ │ ├── base/ │ │ │ ├── BranchInstruction.java │ │ │ ├── BranchLogic.java │ │ │ ├── BytecodeReader.java │ │ │ ├── ClassInitLogic.java │ │ │ ├── Index16Instruction.java │ │ │ ├── Index8Instruction.java │ │ │ ├── Instruction.java │ │ │ ├── MethodInvokeLogic.java │ │ │ └── NoOperandsInstruction.java │ │ ├── comparisons/ │ │ │ ├── dcmp/ │ │ │ │ ├── DCMP.java │ │ │ │ ├── DCMPG.java │ │ │ │ └── DCMPL.java │ │ │ ├── fcmp/ │ │ │ │ ├── FCMP.java │ │ │ │ ├── FCMPG.java │ │ │ │ └── FCMPL.java │ │ │ ├── ifacmp/ │ │ │ │ ├── IF_ACMPEQ.java │ │ │ │ ├── IF_ACMPNE.java │ │ │ │ └── IfAcmp.java │ │ │ ├── ifcond/ │ │ │ │ ├── IFEQ.java │ │ │ │ ├── IFGE.java │ │ │ │ ├── IFGT.java │ │ │ │ ├── IFLE.java │ │ │ │ ├── IFLT.java │ │ │ │ └── IFNE.java │ │ │ ├── ificmp/ │ │ │ │ ├── IF_ICMPEQ.java │ │ │ │ ├── IF_ICMPGE.java │ │ │ │ ├── IF_ICMPGT.java │ │ │ │ ├── IF_ICMPLE.java │ │ │ │ ├── IF_ICMPLT.java │ │ │ │ ├── IF_ICMPNE.java │ │ │ │ └── IfIcmp.java │ │ │ └── lcmp/ │ │ │ └── LCMP.java │ │ ├── constants/ │ │ │ ├── ACONST_NULL.java │ │ │ ├── BIPUSH.java │ │ │ ├── DCONST_0.java │ │ │ ├── DCONST_1.java │ │ │ ├── FCONST_0.java │ │ │ ├── FCONST_1.java │ │ │ ├── FCONST_2.java │ │ │ ├── ICONST_0.java │ │ │ ├── ICONST_1.java │ │ │ ├── ICONST_2.java │ │ │ ├── ICONST_3.java │ │ │ ├── ICONST_4.java │ │ │ ├── ICONST_5.java │ │ │ ├── ICONST_M1.java │ │ │ ├── LCONST_0.java │ │ │ ├── LCONST_1.java │ │ │ ├── LDC.java │ │ │ ├── LDC2_W.java │ │ │ ├── LDC_W.java │ │ │ ├── NOP.java │ │ │ └── SIPUSH.java │ │ ├── control/ │ │ │ ├── ARETURN.java │ │ │ ├── DRETURN.java │ │ │ ├── FRETURN.java │ │ │ ├── GOTO.java │ │ │ ├── IRETURN.java │ │ │ ├── LOOKUP_SWITCH.java │ │ │ ├── LRETURN.java │ │ │ ├── RETURN.java │ │ │ └── TABLE_SWITCH.java │ │ ├── conversions/ │ │ │ ├── d2x/ │ │ │ │ ├── D2F.java │ │ │ │ ├── D2I.java │ │ │ │ └── D2L.java │ │ │ ├── f2x/ │ │ │ │ ├── F2D.java │ │ │ │ ├── F2I.java │ │ │ │ └── F2L.java │ │ │ ├── i2x/ │ │ │ │ ├── I2B.java │ │ │ │ ├── I2C.java │ │ │ │ ├── I2D.java │ │ │ │ ├── I2F.java │ │ │ │ ├── I2L.java │ │ │ │ └── I2S.java │ │ │ └── l2x/ │ │ │ ├── L2D.java │ │ │ ├── L2F.java │ │ │ └── L2I.java │ │ ├── extended/ │ │ │ ├── GOTO_W.java │ │ │ ├── IFNONNULL.java │ │ │ ├── IFNULL.java │ │ │ └── WIDE.java │ │ ├── loads/ │ │ │ ├── Load.java │ │ │ ├── loaddouble/ │ │ │ │ ├── DLOAD.java │ │ │ │ ├── DLOAD_0.java │ │ │ │ ├── DLOAD_1.java │ │ │ │ ├── DLOAD_2.java │ │ │ │ └── DLOAD_3.java │ │ │ ├── loadfloat/ │ │ │ │ ├── FLOAD.java │ │ │ │ ├── FLOAD_0.java │ │ │ │ ├── FLOAD_1.java │ │ │ │ ├── FLOAD_2.java │ │ │ │ └── FLOAD_3.java │ │ │ ├── loadint/ │ │ │ │ ├── ILOAD.java │ │ │ │ ├── ILOAD_0.java │ │ │ │ ├── ILOAD_1.java │ │ │ │ ├── ILOAD_2.java │ │ │ │ └── ILOAD_3.java │ │ │ ├── loadlong/ │ │ │ │ ├── LLOAD.java │ │ │ │ ├── LLOAD_0.java │ │ │ │ ├── LLOAD_1.java │ │ │ │ ├── LLOAD_2.java │ │ │ │ └── LLOAD_3.java │ │ │ ├── loadref/ │ │ │ │ ├── ALOAD.java │ │ │ │ ├── ALOAD_0.java │ │ │ │ ├── ALOAD_1.java │ │ │ │ ├── ALOAD_2.java │ │ │ │ └── ALOAD_3.java │ │ │ └── loadxarr/ │ │ │ ├── AALOAD.java │ │ │ ├── BALOAD.java │ │ │ ├── CALOAD.java │ │ │ ├── DALOAD.java │ │ │ ├── FALOAD.java │ │ │ ├── IALOAD.java │ │ │ ├── LALOAD.java │ │ │ └── SALOAD.java │ │ ├── math/ │ │ │ ├── add/ │ │ │ │ ├── DADD.java │ │ │ │ ├── FADD.java │ │ │ │ ├── IADD.java │ │ │ │ └── LADD.java │ │ │ ├── and/ │ │ │ │ ├── IAND.java │ │ │ │ └── LAND.java │ │ │ ├── div/ │ │ │ │ ├── DDIV.java │ │ │ │ ├── FDIV.java │ │ │ │ ├── IDIV.java │ │ │ │ └── LDIV.java │ │ │ ├── iinc/ │ │ │ │ └── IINC.java │ │ │ ├── mul/ │ │ │ │ ├── DMUL.java │ │ │ │ ├── FMUL.java │ │ │ │ ├── IMUL.java │ │ │ │ └── LMUL.java │ │ │ ├── neg/ │ │ │ │ ├── DNEG.java │ │ │ │ ├── FNEG.java │ │ │ │ ├── INEG.java │ │ │ │ └── LNEG.java │ │ │ ├── or/ │ │ │ │ ├── IOR.java │ │ │ │ └── LOR.java │ │ │ ├── rem/ │ │ │ │ ├── DREM.java │ │ │ │ ├── FREM.java │ │ │ │ ├── IREM.java │ │ │ │ └── LREM.java │ │ │ ├── sh/ │ │ │ │ ├── ISHL.java │ │ │ │ ├── ISHR.java │ │ │ │ ├── IUSHR.java │ │ │ │ ├── LSHL.java │ │ │ │ ├── LSHR.java │ │ │ │ └── LUSHR.java │ │ │ ├── sub/ │ │ │ │ ├── DSUB.java │ │ │ │ ├── FSUB.java │ │ │ │ ├── ISUB.java │ │ │ │ └── LSUB.java │ │ │ └── xor/ │ │ │ ├── IXOR.java │ │ │ └── LXOR.java │ │ ├── references/ │ │ │ ├── ANEW_ARRAY.java │ │ │ ├── ARRAY_LENGTH.java │ │ │ ├── ATHROW.java │ │ │ ├── CHECK_CAST.java │ │ │ ├── GET_FIELD.java │ │ │ ├── GET_STATIC.java │ │ │ ├── INSTANCE_OF.java │ │ │ ├── INVOKE_INTERFACE.java │ │ │ ├── INVOKE_NATIVE.java │ │ │ ├── INVOKE_SPECIAL.java │ │ │ ├── INVOKE_STATIC.java │ │ │ ├── INVOKE_VIRTUAL.java │ │ │ ├── MULTI_ANEW_ARRAY.java │ │ │ ├── NEW.java │ │ │ ├── NEW_ARRAY.java │ │ │ ├── PUT_FIELD.java │ │ │ └── PUT_STATIC.java │ │ ├── stack/ │ │ │ ├── dup/ │ │ │ │ ├── DUP.java │ │ │ │ ├── DUP2.java │ │ │ │ ├── DUP2_X1.java │ │ │ │ ├── DUP2_X2.java │ │ │ │ ├── DUP_X1.java │ │ │ │ └── DUP_X2.java │ │ │ ├── pop/ │ │ │ │ ├── POP.java │ │ │ │ └── POP2.java │ │ │ └── swap/ │ │ │ └── SWAP.java │ │ └── stores/ │ │ ├── Store.java │ │ ├── storedouble/ │ │ │ ├── DSTORE.java │ │ │ ├── DSTORE_0.java │ │ │ ├── DSTORE_1.java │ │ │ ├── DSTORE_2.java │ │ │ └── DSTORE_3.java │ │ ├── storefloat/ │ │ │ ├── FSTORE.java │ │ │ ├── FSTORE_0.java │ │ │ ├── FSTORE_1.java │ │ │ ├── FSTORE_2.java │ │ │ └── FSTORE_3.java │ │ ├── storeint/ │ │ │ ├── ISTORE.java │ │ │ ├── ISTORE_0.java │ │ │ ├── ISTORE_1.java │ │ │ ├── ISTORE_2.java │ │ │ └── ISTORE_3.java │ │ ├── storelong/ │ │ │ ├── LSTORE.java │ │ │ ├── LSTORE_0.java │ │ │ ├── LSTORE_1.java │ │ │ ├── LSTORE_2.java │ │ │ └── LSTORE_3.java │ │ ├── storeref/ │ │ │ ├── ASTORE.java │ │ │ ├── ASTORE_0.java │ │ │ ├── ASTORE_1.java │ │ │ ├── ASTORE_2.java │ │ │ └── ASTORE_3.java │ │ └── storexarr/ │ │ ├── AASTORE.java │ │ ├── BASTORE.java │ │ ├── CASTORE.java │ │ ├── DASTORE.java │ │ ├── FASTORE.java │ │ ├── IASTORE.java │ │ ├── LASTORE.java │ │ └── SASTORE.java │ ├── runtimedata/ │ │ ├── LocalVars.java │ │ ├── OperandStack.java │ │ ├── Slot.java │ │ ├── Slots.java │ │ ├── Zframe.java │ │ ├── Zstack.java │ │ ├── Zthread.java │ │ └── heap/ │ │ ├── AccessFlag.java │ │ ├── ClassMember.java │ │ ├── ClassNameHelper.java │ │ ├── ClassRef.java │ │ ├── ExceptionTable.java │ │ ├── FieldRef.java │ │ ├── InterfaceMethodRef.java │ │ ├── MemberRef.java │ │ ├── MethodDescriptor.java │ │ ├── MethodLookup.java │ │ ├── MethodRef.java │ │ ├── RuntimeConstantInfo.java │ │ ├── RuntimeConstantPool.java │ │ ├── StringPool.java │ │ ├── SymRef.java │ │ ├── Zclass.java │ │ ├── ZclassLoader.java │ │ ├── Zfield.java │ │ ├── Zmethod.java │ │ └── Zobject.java │ ├── test/ │ │ ├── TestClassFile03.java │ │ ├── TestClassLoader07.java │ │ ├── TestClassPath02.java │ │ ├── TestCmd01.java │ │ ├── TestException12.java │ │ ├── TestGetClass11.java │ │ ├── TestInterpreter06.java │ │ ├── TestInvokeMethod08.java │ │ ├── TestLocalVars04.java │ │ ├── TestNewArray09.java │ │ ├── TestOperandStack05.java │ │ └── TestStringPool10.java │ └── znative/ │ ├── NativeMethod.java │ ├── RegisterCenter.java │ └── java/ │ └── lang/ │ ├── NStackTraceElement.java │ ├── Nclass.java │ ├── Nobject.java │ └── Nthrowable.java └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml /local.properties /.idea/ /out .DS_Store /captures /Java/src/help.java /tmp ================================================ FILE: Java/src/Main.java ================================================ /** * Author: zhangxin * Time: 2017/4/30 0030. * Desc: */ public class Main { public static void main(String[] args) { System.out.println("please refer to the test package to make your own code. enjoy!"); } } ================================================ FILE: Java/src/Utils/ByteUtils.java ================================================ package Utils; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: */ public class ByteUtils { public static String bytesToHexString(byte[] src) { return bytesToHexString(src, src.length); } /** * @param src 待转换的字节数组 * @param len 只转换字节数组中的前len个字节 * @return 转换成的字符串, 考虑到这是对底层数据的操作, */ public static String bytesToHexString(byte[] src, int len) { StringBuilder stringBuilder = new StringBuilder(""); if (src == null || len <= 0) { return null; } for (int i = 0; i < len; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v).toUpperCase(); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } //Java中并没有u16,所以这里使用int来表示; public static int bytesToU16(byte[] data) { assert data.length == 2; return (data[0] + 256) % 256 * 256 + (data[1] + 256) % 256; } //这个方法和下个方法区别在哪里,返回值不同啊... /*public static long bytesToU32(byte[] data) { assert data.length == 4; long res = 0; for (int i = 0; i < 4; i++) { res += res * 256 + (data[i] + 256) % 256; } return res; }*/ public static int byteToInt32(byte[] data) { assert data.length == 4; int res = 0; for (int i = 0; i < data.length; i++) { res = res << 8 | (data[i] + 256) % 256; } return res; } public static long byteToLong64(byte[] data) { assert data.length == 8; long res = 0; for (int i = 0; i < data.length; i++) { res = res << 8 | (data[i] + 256) % 256; } return res; } public static float byte2Float32(byte[] b) { int i = byteToInt32(b); return Float.intBitsToFloat(i); } public static double byte2Double64(byte[] b) { long l = byteToLong64(b); return Double.longBitsToDouble(l); } } ================================================ FILE: Java/src/Utils/Cmd.java ================================================ package Utils; /** * Author: zhangxin * Time: 2017/4/30 0030. * Desc:Cmd解析程序 */ public class Cmd { private boolean isRightFmt = true; //是否是正确的格式; private boolean isRightOpt = true; //是否是正确的格式; private boolean helpFlag; //是否是help 查看帮助 private boolean versionFlag; //是否是查看版本 private String cpOption; //classPath 的路径; java -cp(-classpath) xxx /*使用 -Xjre 的选项:这是一个非标准的选项,java命令中是没有的,使用这个选项目的是用来指定启动类路径来寻找和加载Java标准库中的类 即JAVA_HOME/jre的路径; 这里要注意的是,如果真的要指定XjreOption,那么其路径值必须要用双引号包含起来 */ private String xJreOption; private String clazz; //包含main方法的class文件; private String[] args; //执行clazz文件需要的参数 public Cmd(String cmdLine) { parseCmd(cmdLine); } public Cmd(String[] strs) { parseCmd(strs); } public void parseCmd(String[] args) { int classNameIndex = 1; //参数必须大于等于2,否则不合法。最简短的java命令:java -version if (args.length < 2) { isRightFmt = false; return; } //首先判断开头是不是 java ,如果连这个都不是,直接退出吧,提示正确的使用方法; if (!"java".equals(args[0])) { isRightFmt = false; } else { if ("-help".equals(args[1]) || "-?".equals(args[1])) { helpFlag = true; } else if ("-version".equals(args[1])) { versionFlag = true; } else if ("-cp".equals(args[1]) || "classpath".equals(args[1])) { if (args.length < 4) { //如果走到这一步,那么命令行必定是java -cp aa/bb test 11 22 33 的形式,所以应该至少有4项; isRightFmt = false; } classNameIndex = 3; this.cpOption = args[2]; } else if ("-Xjre".equals(args[1])) { if (args.length < 4) { //如果走到这一步,那么命令行必定是java -Xjre "C:\Program Files\Java\jdk1.8.0_20\jre" java.lang.Object 的形式,所以应该至少有4项; isRightFmt = false; } classNameIndex = 3; this.xJreOption = args[2]; } else if (args[1].startsWith("-")) { isRightOpt = false; } this.clazz = args[classNameIndex]; this.args = new String[args.length - classNameIndex - 1]; int argsIndex = classNameIndex + 1; for (int i = argsIndex; i < args.length; i++) { this.args[i - argsIndex] = args[i]; } } } private void parseCmd(String cmdLine) { //NOTE:解析命令行参数,以单个或者多个空格分开,这种方式目前不支持,因为如果输入的 路径名 中间有空格会导致下面解析失败 String[] args = cmdLine.trim().split("\\s+"); parseCmd(args); } public void printUsage() { System.out.println("Usage: java [-options] class [args...]"); System.out.println("Specially,we don't support the path that contains space!"); } public boolean isRightFmt() { return isRightFmt; } public boolean isRightOpt() { return isRightOpt; } public boolean isHelpFlag() { return helpFlag; } public boolean isVersionFlag() { return versionFlag; } public String getCpOption() { return cpOption; } public String getXJreOption() { return xJreOption; } public String getClazz() { return clazz; } public String[] getArgs() { return args; } } ================================================ FILE: Java/src/classfile/ClassFile.java ================================================ package classfile; import Utils.ByteUtils; import classfile.attribute.AttributeInfo; import classfile.attribute.SourceFileAttribute; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: 由javac编译生成的class文件的bean对象 */ public class ClassFile { private int minorVersion; private int majorVersion; public ConstantPool constantPool; private int accessFlags; /* 该索引值指向常量池中一个类型为 CONSTANT_Class_info的类描述符常量, 再通过 CONSTANT_Class_info类型的常量中的索引值,可以找到定义在CONSTANT_Utf8_info类型的常量中的全限定名字符串。 */ private int thisClass; private int superClass; //同 thisClass 的索引值。 private int[] interfaces; //存放所实现的接口在常量池中的索引。同 thisClass 的索引值。 private MemberInfo[] fields; //存放类中所有的字段,包括静态的非静态的;不同的属性通过字段的访问修饰符来读取; private MemberInfo[] methods; //存放类中所有的方法,包括静态的非静态的;不同的属性通过方法的访问修饰符来读取; private AttributeInfo[] attributes; //属性表,存放类的属性; public ClassFile(byte[] classData) { ClassReader reader = new ClassReader(classData); read(reader); } /** * 读取class文件,解析各个字段 * * @param reader */ private void read(ClassReader reader) { readAndCheckMagic(reader); readAndCheckVersion(reader); constantPool = new ConstantPool(reader); accessFlags = reader.readUint16(); thisClass = reader.readUint16(); superClass = reader.readUint16(); interfaces = reader.readUint16s(); fields = MemberInfo.readMembers(reader, constantPool); methods = MemberInfo.readMembers(reader, constantPool); attributes = AttributeInfo.readAttributes(reader, constantPool); } //文件开头前四个字节,是魔数,因为是64的无符号的,所以不能简单的使用long来表示,目前的解决方法是将4个字节的byte数组转换为字符串,对比class文件的魔数 private void readAndCheckMagic(ClassReader reader) { String magic = ByteUtils.bytesToHexString(reader.readUint32()); if (!magic.equals("CAFEBABE")) { throw new RuntimeException("java.lang.ClassFormatError: magic!"); } } //版本号,16字节,分别代表主版本号和次版本号,并向前兼容 private void readAndCheckVersion(ClassReader reader) { minorVersion = reader.readUint16(); majorVersion = reader.readUint16(); if (majorVersion == 45) { return; } if (minorVersion == 0 && majorVersion >= 46 && majorVersion <= 52) { return; } throw new RuntimeException("java.lang.UnsupportedClassVersionError!"); } public int getMinorVersion() { return minorVersion; } public int getMajorVersion() { return majorVersion; } public ConstantPool getConstantPool() { return constantPool; } public int getAccessFlags() { return accessFlags; } public int getThisClass() { return thisClass; } public int getSuperClass() { return superClass; } public int[] getInterfaces() { return interfaces; } public MemberInfo[] getFields() { return fields; } public MemberInfo[] getMethods() { return methods; } public AttributeInfo[] getAttributes() { return attributes; } public String getClassName() { return constantPool.getClassName(thisClass); } public String getSuperClassName() { if (superClass > 0) { return constantPool.getClassName(superClass); } else { return ""; } } public String[] getInterfaceNames() { String[] interfaceNames = new String[interfaces.length]; for (int i = 0; i < interfaceNames.length; i++) { interfaceNames[i] = constantPool.getClassName(interfaces[i]); } return interfaceNames; } public String getSourceFile() { for (AttributeInfo info : attributes) { if (info instanceof SourceFileAttribute) { return ((SourceFileAttribute) info).getFileName(); } } return "unknow"; } } ================================================ FILE: Java/src/classfile/ClassReader.java ================================================ package classfile; import Utils.ByteUtils; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: 封装的读取 class 字节码文件的 reader,里面包含一个index值,表明当前要读的字节数组的索引. */ public class ClassReader { private byte[] data; private int index = 0; public ClassReader(byte[] data) { this.data = data; } // u1 public byte readUint8() { byte res = data[index++]; return res; } // u2 这里是读取一个无符号的16位整,java中没有,只能用int来代替吧; public int readUint16() { byte[] res = new byte[2]; res[0] = data[index++]; res[1] = data[index++]; return ByteUtils.bytesToU16(res); } // u4 public byte[] readUint32() { byte[] res = new byte[4]; res[0] = data[index++]; res[1] = data[index++]; res[2] = data[index++]; res[3] = data[index++]; // return ByteUtils.bytesToU32(res); //如果需要转换的话,自行调用ByteUtils中的方法; return res; } public byte[] readUint64() { byte[] res = new byte[8]; res[0] = data[index++]; res[1] = data[index++]; res[2] = data[index++]; res[3] = data[index++]; res[4] = data[index++]; res[5] = data[index++]; res[6] = data[index++]; res[7] = data[index++]; return res; } /** * 读取连续的16bit长的数组,首先读出16bit,用来表示接下来要去读的多少个16bit * @return */ public int[] readUint16s() { int n = readUint16(); int[] data = new int[n]; for (int i = 0; i < n; i++) { data[i] = readUint16(); } return data; } public byte[] readBytes(int n) { byte[] res = new byte[n]; for (int i = 0; i < n; i++) { res[i] = data[index++]; } return res; } } ================================================ FILE: Java/src/classfile/ConstantPool.java ================================================ package classfile; import classfile.classconstant.*; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: 常量池实际上也是一个表,这里用数组来实现,所以常量池这个类中持有一个常量数据 * 至于这个数组的每一项的初始化,则根据读到的字节的tag不同而创建不同的常量子类 * 常量池有多中项目类型,这个根据读取到的tag的不同创建不同的常量类, */ public class ConstantPool { //保存类文件常量池中的所有常量,常量分为多种类型,基本类型都有对应的常量,以及字符串等;(简言之,这就是常量池的抽象) ConstantInfo[] infos; public ConstantInfo[] getInfos() { return infos; } //class文件中常量池中的常量数量,注意返回的这个数量是包含0的,但是0是空的; private int constantPoolCount; private int realConstantPoolCount; public ConstantPool(ClassReader reader) { /*读出常量池的大小;接下来根据这个大小,生成常量信息数组; 注意: 1. 表头给出的常量池大小比实际大1,所以这样的话,虽然可能生成了这么大的,但是0不使用,直接从1开始; 2. 有效的常量池索引是1~n–1。0是无效索引,表示不指向任何常量 3. CONSTANT_Long_info和 CONSTANT_Double_info各占两个位置。 也就是说,如果常量池中存在这两种常量,实际的常量数量比n–1还要少,而且1~n–1的某些数也会变成无效索引。 */ constantPoolCount = reader.readUint16(); infos = new ConstantInfo[constantPoolCount]; for (int i = 1; i < constantPoolCount; i++) { infos[i] = ConstantInfo.readConstantInfo(reader, this); realConstantPoolCount++; // System.out.println(i+":"+infos[i].getClass()); if ((infos[i] instanceof ConstantLongInfo) || (infos[i] instanceof ConstantDoubleInfo)) { i++; } } } //按索引查找常量,如果没有的话,直接抛异常; private ConstantInfo getConstantInfo(int index) { if (0 < index && index < constantPoolCount) { ConstantInfo info = infos[index]; if (info != null) { return info; } } throw new NullPointerException("Invalid constant pool index!"); } //常量池查找字段或方法的名字和描述符 public String getName(int index) { ConstantNameAndTypeInfo info = (ConstantNameAndTypeInfo) getConstantInfo(index); return getUtf8(info.nameIndex); } //常量池查找字段或方法的描述符,描述符其实就是由其对应的类型名字对应而成; public String getType(int index) { ConstantNameAndTypeInfo info = (ConstantNameAndTypeInfo) getConstantInfo(index); return getUtf8(info.descriptorIndex); } public String[] getNameAndType(int index) { String[] str = new String[2]; ConstantNameAndTypeInfo info = (ConstantNameAndTypeInfo) getConstantInfo(index); str[0] = getUtf8(info.nameIndex); str[1] = getUtf8(info.descriptorIndex); return str; } public String getClassName(int index) { ConstantClassInfo info = (ConstantClassInfo) getConstantInfo(index); return getUtf8(info.nameIndex); } //只要调用这个方法,一定是想去读字符串常量了,所以拿到index所对应的常量后,直接强转为ConstantUtf8Info,然后获取其val值; public String getUtf8(int index) { return ((ConstantUtf8Info) getConstantInfo(index)).val; } //测试方法,正式版本祛除 public int getConstantPoolCount() { return realConstantPoolCount; } } ================================================ FILE: Java/src/classfile/MemberInfo.java ================================================ package classfile; import classfile.attribute.AttributeInfo; import classfile.attribute.CodeAttribute; import classfile.attribute.ConstantValueAttribute; import classfile.attribute.ExceptionsAttribute; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: 字段表和方法表,共用该类,因为二者在虚拟机规范中的定义是相同的 * 里面包含的是类中的所定义的成员变量/方法 * 字段/方法中可能还包含属性 * 静态的和非静态的都包含 */ /* field_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; } */ public class MemberInfo { ConstantPool constantPool; int accessFlags; int nameIndex; int descriptorIndex; AttributeInfo[] attributes; public MemberInfo(ClassReader reader, ConstantPool constantPool) { this.constantPool = constantPool; accessFlags = reader.readUint16(); nameIndex = reader.readUint16(); descriptorIndex = reader.readUint16(); attributes = AttributeInfo.readAttributes(reader, constantPool); } public static MemberInfo[] readMembers(ClassReader reader, ConstantPool constantPool) { int memberCount = reader.readUint16(); MemberInfo[] members = new MemberInfo[memberCount]; for (int i = 0; i < memberCount; i++) { members[i] = new MemberInfo(reader, constantPool); } return members; } public int getAccessFlags() { return accessFlags; } public String getName() { return constantPool.getUtf8(nameIndex); } public String getDescriptor() { return constantPool.getUtf8(descriptorIndex); } public CodeAttribute getCodeAttribute() { for (AttributeInfo info : attributes) { if (info instanceof CodeAttribute) { return (CodeAttribute) info; } } return null; } //并非每个成员变量都有ConstantValueAttribute属性,该属性只针对于static final 基础类型变量或者String类型变量; public ConstantValueAttribute getConstantValueAttribute() { for (AttributeInfo info : attributes) { if (info instanceof ConstantValueAttribute) { return (ConstantValueAttribute) info; } } return null; } public ExceptionsAttribute getExceptionsAttribute() { for (int i = 0; i < attributes.length; i++) { if (attributes[i] instanceof ExceptionsAttribute) { return (ExceptionsAttribute) attributes[i]; } } return null; } } ================================================ FILE: Java/src/classfile/attribute/AttributeInfo.java ================================================ package classfile.attribute; import Utils.ByteUtils; import classfile.ClassReader; import classfile.ConstantPool; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc: */ /* 属性表在JVM中的定义; 虚拟机规范中,每个属性都定义了name_index,用来从常量池中拿到属性名; attr_len,用来定义属性的的长度,便于接下来的解读 其实很多属性的长度都是已知的, 不确定长度的有:code属性,其长度需要根据len来读取; attribute_info { u2 attribute_name_index; u4 attribute_length; u1 info[attribute_length]; } */ public abstract class AttributeInfo { //抽象方法,由各属性自己读取对应的属性信息 abstract void readInfo(ClassReader reader); //读取单个属性 private static AttributeInfo readAttribute(ClassReader reader, ConstantPool constantPool) { int attrNameIndex = reader.readUint16(); String attrName = constantPool.getUtf8(attrNameIndex); int attrLen = ByteUtils.byteToInt32(reader.readUint32()); AttributeInfo attrInfo = create(attrName, attrLen, constantPool); attrInfo.readInfo(reader); return attrInfo; } /** * 读取属性表; * 和ConstantPool中的方法类似,一般都是一下子全部读取出来,不会只读一个 * 整个 JVM 中有三个地方用到了读取属性表 * 1. 由 class 文件转为 ClassFile 对象时,读取 Class 的属性 * 2. 为 class 中定义的 Field 和 Method 读取属性 * 3. 为 Method 中的字节码读取属性(本地变量表大小,操作数大小,字节码,异常表) */ public static AttributeInfo[] readAttributes(ClassReader reader, ConstantPool constantPool) { int attributesCount = reader.readUint16(); AttributeInfo[] attributes = new AttributeInfo[attributesCount]; for (int i = 0; i < attributesCount; i++) { attributes[i] = readAttribute(reader, constantPool); } return attributes; } //Java虚拟机规范预定义了23种属性,先解析其中的8种 /*23种预定义属性可以分为三组。 第一组属性是实现Java虚拟机所必需的,共有5种; 第二组属性是Java类库所必需的,共有12种; 第三组属性主要提供给工具使用,共有6种。第三组属性是可选的,也就是说可以不出现在class文件中。 (如果class文件中存在第三组属性,Java虚拟机实现或者Java类库也是可以利用它们的,比如使用LineNumberTable属性在异常堆栈中显示行号。) */ private static AttributeInfo create(String attrName, int attrLen, ConstantPool constantPool) { if ("Code".equals(attrName)) { return new CodeAttribute(constantPool); } else if ("ConstantValue".equals(attrName)) { return new ConstantValueAttribute(); } else if ("Deprecated".equals(attrName)) { return new DeprecatedAttribute(); } else if ("Exceptions".equals(attrName)) { return new ExceptionsAttribute(); } else if ("LineNumberTable".equals(attrName)) { return new LineNumberTableAttribute(); } else if ("LocalVariableTable".equals(attrName)) { return new LocalVariableTableAttribute(); } else if ("SourceFile".equals(attrName)) { return new SourceFileAttribute(constantPool); } else if ("Synthetic".equals(attrName)) { return new SyntheticAttribute(); } else { return new UnparsedAttribute(attrName, attrLen); } } } ================================================ FILE: Java/src/classfile/attribute/CodeAttribute.java ================================================ package classfile.attribute; import Utils.ByteUtils; import classfile.ClassReader; import classfile.ConstantPool; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc:Code是变长属性,只存在于method_info结构中 */ /* JVM 中 Code 属性的定义; Code_attribute { u2 attribute_name_index; u4 attribute_length; u2 max_stack; u2 max_locals; u4 code_length; u1 code[code_length]; u2 exception_table_length; { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type; } exception_table[exception_table_length]; u2 attributes_count; attribute_info attributes[attributes_count]; } */ public class CodeAttribute extends AttributeInfo { ConstantPool constantPool; int maxStack; //操作数栈的最大深度 int maxLocals; //局部变量表大小 byte[] code; //字节码 ExceptionTableEntry[] exceptionTable; // AttributeInfo[] attributes; public CodeAttribute(ConstantPool constantPool) { this.constantPool = constantPool; } @Override void readInfo(ClassReader reader) { maxStack = reader.readUint16(); maxLocals = reader.readUint16(); int codeLength = ByteUtils.byteToInt32(reader.readUint32()); code = reader.readBytes(codeLength); exceptionTable = readExceptionTable(reader); attributes = readAttributes(reader, constantPool); } private ExceptionTableEntry[] readExceptionTable(ClassReader reader) { int exceptionTableLength = reader.readUint16(); ExceptionTableEntry[] exceptionTable = new ExceptionTableEntry[exceptionTableLength]; for (int i = 0; i < exceptionTableLength; i++) { exceptionTable[i] = new ExceptionTableEntry(reader); } return exceptionTable; } public LineNumberTableAttribute lineNumberTableAttribute() { for (int i = 0; i < attributes.length; i++) { if (attributes[i] instanceof LineNumberTableAttribute) { return (LineNumberTableAttribute) attributes[i]; } } return null; } //异常表,包含四个指针,分别为 public static class ExceptionTableEntry { int startPc; //可能排除异常的代码块的起始字节码(包括) int endPc; //可能排除异常的代码块的终止字节码(不包括) int handlerPc; //负责处理异常的 catch 块的其实位置 int catchType; //指向运行时常量池的一个索引,解析后可以得到一个异常类 //改为传入一个reader的方法,比上面的构造方法更优雅一些; public ExceptionTableEntry(ClassReader reader) { this.startPc = reader.readUint16(); this.endPc = reader.readUint16(); this.handlerPc = reader.readUint16(); this.catchType = reader.readUint16(); } public int getStartPc() { return startPc; } public int getEndPc() { return endPc; } public int getHandlerPc() { return handlerPc; } public int getCatchType() { return catchType; } } public int getMaxStack() { return maxStack; } public int getMaxLocals() { return maxLocals; } public byte[] getCode() { return code; } public ExceptionTableEntry[] getExceptionTable() { return exceptionTable; } } ================================================ FILE: Java/src/classfile/attribute/ConstantValueAttribute.java ================================================ package classfile.attribute; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc:ConstantValue是定长属性,只会出现在field_info结构中。 * 其作用是通知JVM自动为静态变量赋值。只有被static关键字修饰的变量才有这个属性。 * 对于以下三种情况: * int a1 = 123; * static int a2 = 123; * final static int a3 = 123; * * a1是实例变量,其赋值是在实例构造器方法中完成的。 * 而对于a2和a3,他们都是类变量,那么其赋值有两种情况,一种是在,一种是使用ConstantValue属性; * 目前Sun Javac 的选择是:a3 使用生成 ConstantValue 属性的方法来赋值 * a2则将会在中进行赋值。 * * 表示常量表达式的值,其在JVM中定义如下: * ConstantValue_attribute { * u2 attribute_name_index; * u4 attribute_length; * u2 constantvalue_index; * } * 其中attribute_length的值必须是2。constantvalue_index是常量池索引,代表了常量池中一个字面量常量的引用。 */ public class ConstantValueAttribute extends AttributeInfo { int constantValueIndex; @Override void readInfo(ClassReader reader) { constantValueIndex = reader.readUint16(); } public int getConstantValueIndex() { return constantValueIndex; } } ================================================ FILE: Java/src/classfile/attribute/DeprecatedAttribute.java ================================================ package classfile.attribute; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc:仅起标记作用,不包含任何数据。是JDK1.1引入的,可以出现在 ClassFile、field_info和method_info结构中 * 属于布尔属性,只有存在和不存在的区别。 */ public class DeprecatedAttribute extends AttributeInfo { int attribute_name_index; int attribute_length; @Override void readInfo(ClassReader reader) { //由于没有数据,所以是空的. } } ================================================ FILE: Java/src/classfile/attribute/ExceptionsAttribute.java ================================================ package classfile.attribute; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc: Exceptions是变长属性,记录方法抛出的异常表 */ /* Exceptions_attribute { u2 attribute_name_index; u4 attribute_length; u2 number_of_exceptions; u2 exception_index_table[number_of_exceptions]; } */ public class ExceptionsAttribute extends AttributeInfo { int[] exceptionIndexTable; @Override void readInfo(ClassReader reader) { exceptionIndexTable = reader.readUint16s(); } public int[] getExceptionIndexTable() { return exceptionIndexTable; } } ================================================ FILE: Java/src/classfile/attribute/LineNumberTableAttribute.java ================================================ package classfile.attribute; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc: LineNumberTable属性表存放方法的行号信息,和前面介绍的SourceFile属性都属于调试信息,都不是运行时必需 * 在使用javac编译器编译Java程序时,默认会在class文件中生成这些信息。可以使用javac提供的-g:none选项来关闭这些信息的生成 * 描述Java源码行号与字节码行号之间的对应关系。 */ public class LineNumberTableAttribute extends AttributeInfo { LineNumberTableEntry[] lineNumberTable; @Override void readInfo(ClassReader reader) { int lineNumberTableLength = reader.readUint16(); this.lineNumberTable = new LineNumberTableEntry[lineNumberTableLength]; for (int i = 0; i < lineNumberTableLength; i++) { lineNumberTable[i] = new LineNumberTableEntry(reader.readUint16(), reader.readUint16()); } } /* 根据字节码中的行号,寻找其在源代码中的行号;一般情况下;多个字节码的行号可能会对应一个源文件中的一行 0 - 15 8 - 17 14 - 21 17 - 18 18 - 20 22 - 24 可以确保的是字节码中的行号递增的,而对应的源码中的行号并不是 */ public int getLineNumber(int pc) { for (int i = lineNumberTable.length - 1; i >= 0; i--) { LineNumberTableEntry entry = lineNumberTable[i]; if (pc >= entry.startPc) { return entry.lineNumber; } } return -1; } static class LineNumberTableEntry { int startPc; //字节码行号 int lineNumber; //Java源码行号,二者执行的关联 public LineNumberTableEntry(int startPc, int lineNumber) { this.startPc = startPc; this.lineNumber = lineNumber; } } } ================================================ FILE: Java/src/classfile/attribute/LocalVariableTableAttribute.java ================================================ package classfile.attribute; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc: 用于描述栈帧中局部变量表中的变量和Java源码中定义的变量之间的关系。 * 这并不是运行时必须的属性,但默认会生成到Class文件中,可以在Javac 中使用 -g:none 来取消这项信息; * 如果不生成这项,产生的影响是:当其他人引用这个方法时,IDE将会使用诸如arg0,arg1之类的占位符代替原来的参数名,但对运行毫无影响。 * 只是在调试期间无法根据参数名从上下文中获得参数值。 */ public class LocalVariableTableAttribute extends AttributeInfo { LocalVariableTableEntry[] localVariableTable; @Override void readInfo(ClassReader reader) { int localVariableTableLength = reader.readUint16(); this.localVariableTable = new LocalVariableTableEntry[localVariableTableLength]; for (int i = 0; i < localVariableTableLength; i++) { localVariableTable[i] = new LocalVariableTableEntry( reader.readUint16(), reader.readUint16(), reader.readUint16(), reader.readUint16(), reader.readUint16() ); } } static class LocalVariableTableEntry { int startPc; //代表该局部变量的生命周期开始的字节码偏移量 int length; //代表该局部变量的作用范围所覆盖的长度 int nameIndex; //指向常量池中个CONSTANT_Utf8_info型常量的索引,代表局部变量名称 int descriptorIndex; //指向常量池中个CONSTANT_Utf8_info型常量的索引,变量描述符 int index; //该局部变量在栈帧局部变量包中slot的位置 public LocalVariableTableEntry(int startPc, int length, int nameIndex, int descriptorIndex, int index) { this.startPc = startPc; this.length = length; this.nameIndex = nameIndex; this.descriptorIndex = descriptorIndex; this.index = index; } } } ================================================ FILE: Java/src/classfile/attribute/SourceFileAttribute.java ================================================ package classfile.attribute; import classfile.ClassReader; import classfile.ConstantPool; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc:SourceFile是可选定长属性,只会出现在ClassFile结构中,用于指出源文件名 name * 这个属性也是可选的,使用 Javac -g:none 选项关闭该项信息。 * 对于大多数情况,类名和文件名是一致的,但是只有在内部类中,如果抛出异常,并且没有生成该项,堆栈中将不会显示出错代码所属的文件名。 */ public class SourceFileAttribute extends AttributeInfo { //sourcefile_index是常量池索引,指向CONSTANT_Utf8_info常量,其常量值是源码文件的文件名 int sourceFileIndex; ConstantPool constantPool; public SourceFileAttribute(ConstantPool constantPool) { this.constantPool = constantPool; } @Override void readInfo(ClassReader reader) { sourceFileIndex = reader.readUint16(); } public String getFileName() { return constantPool.getUtf8(sourceFileIndex); } } ================================================ FILE: Java/src/classfile/attribute/SyntheticAttribute.java ================================================ package classfile.attribute; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc:仅起标记作用,不包含任何数据。是JDK1.1引入的,可以出现在 ClassFile、field_info和method_info结构中 * 代表词字段或方法并不是由Java源码生成的,而是由编译器自行添加的。 */ public class SyntheticAttribute extends AttributeInfo { int attribute_name_index; int attribute_length; @Override void readInfo(ClassReader reader) { //由于没有数据,所以是空的. } } ================================================ FILE: Java/src/classfile/attribute/UnparsedAttribute.java ================================================ package classfile.attribute; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc: 由于精力有限,这里不可能将所有的属性都实现,只是挑重要的几个实现,其它的都直接跳过所对应的字节数即可。 */ public class UnparsedAttribute extends AttributeInfo { private String attrName; private int attrLen; private byte[] info; public UnparsedAttribute(String attrName, int attrLen) { this.attrName = attrName; this.attrLen = attrLen; } @Override void readInfo(ClassReader reader) { info = reader.readBytes(attrLen); } } ================================================ FILE: Java/src/classfile/classconstant/ConstantClassInfo.java ================================================ package classfile.classconstant; import classfile.ClassReader; import classfile.ConstantPool; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc:表示类或者接口的符号引用 * 类和超类索引,以及接口表中的接口索引指向的都是CONSTANT_Class_info常量 *

* ClassFileTest的this_class索引是5,其 name_index=50,super_class(Object)的索引是6,其name_index=51, 这里其实存的还是名字 * 5代表的是this_class,本类类名的引用,其值在50处,可以看到常量池50的地方保存的就是jvmgo/book/ch03/ClassFileTest的字符串 * 51处保存的就是java/lang/Object的字符串 */ public class ConstantClassInfo extends ConstantInfo { ConstantPool constantPool; public int nameIndex; public ConstantClassInfo(ConstantPool constantPool, int i) { this.constantPool = constantPool; type = i; } @Override void readInfo(ClassReader reader) { nameIndex = reader.readUint16(); } public String getName() { return constantPool.getUtf8(nameIndex); } } ================================================ FILE: Java/src/classfile/classconstant/ConstantDoubleInfo.java ================================================ package classfile.classconstant; import Utils.ByteUtils; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: */ public class ConstantDoubleInfo extends ConstantInfo { double val; public ConstantDoubleInfo(int i) { type = i; } @Override void readInfo(ClassReader reader) { byte[] data = reader.readUint64(); val = ByteUtils.byte2Double64(data); } public double getVal() { return val; } } ================================================ FILE: Java/src/classfile/classconstant/ConstantFieldRefInfo.java ================================================ package classfile.classconstant; import classfile.ConstantPool; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc: 字段符号引用 */ public class ConstantFieldRefInfo extends ConstantMemberRefInfo { public ConstantFieldRefInfo(ConstantPool constantPool,int type) { super(constantPool,type); } } ================================================ FILE: Java/src/classfile/classconstant/ConstantFloatInfo.java ================================================ package classfile.classconstant; import Utils.ByteUtils; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: */ public class ConstantFloatInfo extends ConstantInfo { float val; public ConstantFloatInfo(int i) { type = i; } @Override void readInfo(ClassReader reader) { byte[] data = reader.readUint32(); val = ByteUtils.byte2Float32(data); } public float getVal() { return val; } } ================================================ FILE: Java/src/classfile/classconstant/ConstantInfo.java ================================================ package classfile.classconstant; import classfile.ClassReader; import classfile.ConstantPool; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: 常量的抽象类,这里实现了常量池中所有常量的类型。 * 由于常量池中存放的信息各不相同,所以每种常量的格式也不同。常量数据的第一字节是tag,用来区分常量类型。 * 根据在常量池的字节码的每个tag字节,可以判断下一个常量类型是什么,每个常量占用多少个字节都是可以确定的,接着再读取下一个tag,确定下一个常量类型; */ public abstract class ConstantInfo { public static final int CONSTANT_Utf8 = 1; public static final int CONSTANT_Integer = 3; public static final int CONSTANT_Float = 4; public static final int CONSTANT_Long = 5; public static final int CONSTANT_Double = 6; public static final int CONSTANT_Class = 7; public static final int CONSTANT_String = 8; public static final int CONSTANT_Fieldref = 9; public static final int CONSTANT_Methodref = 10; public static final int CONSTANT_InterfaceMethodref = 11; public static final int CONSTANT_NameAndType = 12; public static final int CONSTANT_MethodHandle = 15; public static final int CONSTANT_MethodType = 16; public static final int CONSTANT_InvokeDynamic = 18; //抽象方法来读取信息,需要各自具体类去实现;因为每种常量所占的字节数并不相同。 abstract void readInfo(ClassReader reader); //表明当前常量的类型是上述常量的哪一种; protected int type; public int getType() { return type; } public static ConstantInfo readConstantInfo(ClassReader reader, ConstantPool constantPool) { int type = (reader.readUint8() + 256) % 256; ConstantInfo info = create(type, constantPool); info.readInfo(reader); return info; } private static ConstantInfo create(int type, ConstantPool constantPool) { switch (type) { case CONSTANT_Utf8: return new ConstantUtf8Info(1); case CONSTANT_Integer: return new ConstantIntegerInfo(3); case CONSTANT_Float: return new ConstantFloatInfo(4); case CONSTANT_Long: return new ConstantLongInfo(5); case CONSTANT_Double: return new ConstantDoubleInfo(6); case CONSTANT_String: return new ConstantStringInfo(constantPool, 8); case CONSTANT_Class: return new ConstantClassInfo(constantPool, 7); case CONSTANT_Fieldref: return new ConstantFieldRefInfo(constantPool, 9); case CONSTANT_Methodref: return new ConstantMethodRefInfo(constantPool, 10); case CONSTANT_InterfaceMethodref: return new ConstantInterfaceMethodRefInfo(constantPool, 11); case CONSTANT_NameAndType: return new ConstantNameAndTypeInfo(12); case CONSTANT_MethodType: return new ConstantMethodTypeInfo(16); case CONSTANT_MethodHandle: return new ConstantMethodHandleInfo(15); case CONSTANT_InvokeDynamic: return new ConstantInvokeDynamicInfo(18); default: throw new RuntimeException("java.lang.ClassFormatError: constant pool tag!"); } } } ================================================ FILE: Java/src/classfile/classconstant/ConstantIntegerInfo.java ================================================ package classfile.classconstant; import Utils.ByteUtils; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: 使用4字节存储整数常量 * 实际上比int更小的boolean、byte、short和char类型的常量也放在 CONSTANT_Integer_info 中,也是存的四字节,这是为了4k对齐,可是也造成了字节的浪费; */ public class ConstantIntegerInfo extends ConstantInfo { int val; public ConstantIntegerInfo(int i) { type = i; } @Override void readInfo(ClassReader reader) { byte[] data = reader.readUint32(); val = ByteUtils.byteToInt32(data); } public int getVal() { return val; } } ================================================ FILE: Java/src/classfile/classconstant/ConstantInterfaceMethodRefInfo.java ================================================ package classfile.classconstant; import classfile.ConstantPool; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc: 接口方法引用消息 */ public class ConstantInterfaceMethodRefInfo extends ConstantMemberRefInfo { public ConstantInterfaceMethodRefInfo(ConstantPool constantPool, int type) { super(constantPool, type); } } ================================================ FILE: Java/src/classfile/classconstant/ConstantInvokeDynamicInfo.java ================================================ package classfile.classconstant; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: */ public class ConstantInvokeDynamicInfo extends ConstantInfo { int bootstrapMethodAttrIndex; int nameAndTypeIndex; public ConstantInvokeDynamicInfo(int i) { type = i; } @Override void readInfo(ClassReader reader) { bootstrapMethodAttrIndex = reader.readUint16(); nameAndTypeIndex = reader.readUint16(); } } ================================================ FILE: Java/src/classfile/classconstant/ConstantLongInfo.java ================================================ package classfile.classconstant; import Utils.ByteUtils; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: */ public class ConstantLongInfo extends ConstantInfo { long val; public ConstantLongInfo(int i) { type = i; } @Override void readInfo(ClassReader reader) { byte[] data = reader.readUint64(); /* String hexData = ByteUtils.bytesToHexString(data); val = Long.parseLong(hexData, 16);*/ val = ByteUtils.byteToLong64(data); } public long getVal() { return val; } } ================================================ FILE: Java/src/classfile/classconstant/ConstantMemberRefInfo.java ================================================ package classfile.classconstant; import classfile.ClassReader; import classfile.ConstantPool; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: * CONSTANT_Fieldref_info表示字段符号引用 * CONSTANT_Methodref_info表示普通(非接口)方法符号引用 * CONSTANT_InterfaceMethodref_info表示接口方法符号引用 * 这三种类型结构一样,所以给出统一的类结构; * 然后定义三个类继承这个超类; * class_index和name_and_type_index都是常量池索引,分别指向CONSTANT_Class_info和CONSTANT_NameAndType_info常量。 */ /* CONSTANT_Fieldref_info { u1 tag; u2 class_index; u2 name_and_type_index; } */ public class ConstantMemberRefInfo extends ConstantInfo { ConstantPool constantPool; int classIndex; int nameAndTypeIndex; // 该构造方法是供子类调用的,虽然有三个子类,但是并没有使用过该子类,因为当前类(父类)已经满足需求了; // public ConstantMemberRefInfo(ConstantPool constantPool) { // this.constantPool = constantPool; // } // 该构造方法是供外部调用的; public ConstantMemberRefInfo(ConstantPool constantPool, int type) { this.constantPool = constantPool; this.type = type; //因为接口,方法,字段通用这一个类,所以在构造方法中传入 i 来区分不同的类型; } @Override void readInfo(ClassReader reader) { classIndex = reader.readUint16(); nameAndTypeIndex = reader.readUint16(); } public String getClassName() { return constantPool.getClassName(classIndex); } public String[] getNameAndDescriptor() { return constantPool.getNameAndType(nameAndTypeIndex); } //下面两个方法是将上面的单独分开拿出来的, public String getName() { return constantPool.getName(nameAndTypeIndex); } public String getDescriptor() { return constantPool.getType(nameAndTypeIndex); } } ================================================ FILE: Java/src/classfile/classconstant/ConstantMethodHandleInfo.java ================================================ package classfile.classconstant; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: ava7 中的属性,在本 JVM 中未实现 */ public class ConstantMethodHandleInfo extends ConstantInfo { //关于byte上界,自行处理; private byte referenceKind; private int referenceIndex; public ConstantMethodHandleInfo(int i) { type = i; } @Override void readInfo(ClassReader reader) { referenceKind = reader.readUint8(); referenceIndex = reader.readUint16(); } public int getReferenceKind() { return (referenceKind + 256) % 256; } public int getReferenceIndex() { return referenceIndex; } } ================================================ FILE: Java/src/classfile/classconstant/ConstantMethodRefInfo.java ================================================ package classfile.classconstant; import classfile.ConstantPool; /** * Author: zhangxin * Time: 2017/5/3 0003. * Desc: 方法引用消息 */ public class ConstantMethodRefInfo extends ConstantMemberRefInfo { public ConstantMethodRefInfo(ConstantPool constantPool, int type) { super(constantPool, type); } } ================================================ FILE: Java/src/classfile/classconstant/ConstantMethodTypeInfo.java ================================================ package classfile.classconstant; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: Java7 中的属性,在本 JVM 中未实现 */ public class ConstantMethodTypeInfo extends ConstantInfo { //关于byte上界,自行处理; private int descriptorIndex; public ConstantMethodTypeInfo(int i) { type = i; } @Override void readInfo(ClassReader reader) { descriptorIndex = reader.readUint16(); } public int getDescriptorIndex() { return descriptorIndex; } } ================================================ FILE: Java/src/classfile/classconstant/ConstantNameAndTypeInfo.java ================================================ package classfile.classconstant; import classfile.ClassReader; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc: * name_index和descriptor_index都是常量池索引,指向CONSTANT_Utf8_info常量。 * 字段(成员变量)和方法名就是代码中出现的(或者编译器生成的)字段或方法的名字。 * 字段或方法名由name_index给出,对应的就是代码中真实的成员变量名或者方法名 * 字段或方法的描述符由descriptor_index给出 * 描述符:描述字段的类型,描述方法的参数类型; *

* (1) * a:基本类型byte、short、char、int、long、float和double的描述符是单个字母,分别对应B、S、C、I、J、F和D。注意,long的描述符是J而不是L。 * b:引用类型的描述符是 L + 类的完全限定名 + 分号 eg: Ljava.lang.String; * c:数组类型的描述符是[+数组元素类型描述符。eg: [I 代表int[] *

* (2)字段描述符就是字段类型的描述符。 * (3)方法描述符是(分号分隔的参数类型描述符)+返回值类型描述符,其中void返回值由单个字母V表示。eg:(Ljava.lang.String;I)Ljava.lang.String * 代表的就是 String (String int),方法名由name_index给出; */ /* CONSTANT_NameAndType_info { u1 tag; u2 name_index; u2 descriptor_index; } */ public class ConstantNameAndTypeInfo extends ConstantInfo { public int nameIndex; public int descriptorIndex; public ConstantNameAndTypeInfo(int i) { type = i; } @Override void readInfo(ClassReader reader) { nameIndex = reader.readUint16(); descriptorIndex = reader.readUint16(); } } ================================================ FILE: Java/src/classfile/classconstant/ConstantStringInfo.java ================================================ package classfile.classconstant; import classfile.ClassReader; import classfile.ConstantPool; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc:本身并不存放字符串数据,只存了常量池索引,这个索引指向一个CONSTANT_Utf8_info常量 * 所以在readInfo中首先读出索引,然后在去对应的CONSTANT_Utf8_info常量中读取具体的字符串 */ public class ConstantStringInfo extends ConstantInfo { ConstantPool constantPool; int stringIndex; public ConstantStringInfo(ConstantPool constantPool,int i) { this.constantPool = constantPool; type = i; } //读取常量池索引 @Override void readInfo(ClassReader reader) { stringIndex = reader.readUint16(); } public String getString() { return constantPool.getUtf8(stringIndex); } } ================================================ FILE: Java/src/classfile/classconstant/ConstantUtf8Info.java ================================================ package classfile.classconstant; import classfile.ClassReader; import java.io.IOException; import java.io.UTFDataFormatException; /** * Author: zhangxin * Time: 2017/5/2 0002. * Desc:放的是MUTF-8编码的字符串, * 注意,字符串在class文件中是以MUTF-8(Modified UTF-8)方式编码的。 *

* MUTF-8编码方式和UTF-8大致相同,但并不兼容。 * 差别有两点: * 一是null字符(代码点U+0000)会被编码成2字节:0xC0、0x80; * 二是补充字符(Supplementary Characters,代码点大于U+FFFF的Unicode字符)是按UTF-16拆分为代理对(Surrogate Pair)分别编码的 *

* 字段名(变量名)、字段描述符等就是以字符串的形式存储在class文件中的 */ public class ConstantUtf8Info extends ConstantInfo { public String val; public ConstantUtf8Info(int i) { type = i; } @Override void readInfo(ClassReader reader) { int len = reader.readUint16(); byte[] data = reader.readBytes(len); try { val = decodeMUTF8(data); } catch (IOException e) { e.printStackTrace(); } } //将MUTF8转为UTF8编码, 根据java.io.DataInputStream.readUTF()方法改写。 private static String decodeMUTF8(byte[] bytearr) throws IOException { int utflen = bytearr.length; char[] chararr = new char[utflen]; int c, char2, char3; int count = 0; int chararr_count = 0; while (count < utflen) { c = (int) bytearr[count] & 0xff; if (c > 127) { break; } count++; chararr[chararr_count++] = (char) c; } while (count < utflen) { c = (int) bytearr[count] & 0xff; switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* 0xxxxxxx*/ count++; chararr[chararr_count++] = (char) c; break; case 12: case 13: /* 110x xxxx 10xx xxxx*/ count += 2; if (count > utflen) { throw new UTFDataFormatException("malformed input: partial character at end"); } char2 = (int) bytearr[count - 1]; if ((char2 & 0xC0) != 0x80) { throw new UTFDataFormatException("malformed input around byte " + count); } chararr[chararr_count++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); break; case 14: /* 1110 xxxx 10xx xxxx 10xx xxxx */ count += 3; if (count > utflen) { throw new UTFDataFormatException( "malformed input: partial character at end"); } char2 = (int) bytearr[count - 2]; char3 = (int) bytearr[count - 1]; if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { throw new UTFDataFormatException( "malformed input around byte " + (count - 1)); } chararr[chararr_count++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); break; default: /* 10xx xxxx, 1111 xxxx */ throw new UTFDataFormatException( "malformed input around byte " + count); } } // The number of chars produced may be less than utflen return new String(chararr, 0, chararr_count); } /*private static String decodeMUTF8(byte[] bytearr) { int utfLen = bytearr.length; char[] chararr = new char[utfLen]; char c, char2, char3; int count = 0; int chararr_count = 0; while (count < utfLen) { c = (char) ((bytearr[count] + 256) % 256); if (c > 127) { break; } count++; chararr[chararr_count] = c; chararr_count++; } while (count < utfLen) { c = (char) ((bytearr[count] + 256) % 256); switch (c >> 4) { *//* 0xxxxxxx*//* case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: count++; chararr[chararr_count] = c; chararr_count++; break; case 12: case 13: *//* 110x xxxx 10xx xxxx*//* count += 2; if (count > utfLen) { throw new RuntimeException("malformed input: partial character at end"); } char2 = (char) ((bytearr[count - 1] + 256) % 256); if ((char2 & 0xC0) != 0x80) { throw new RuntimeException("malformed input around byte " + count); } chararr[chararr_count] = (char) (c & 0x1F << 6 | char2 & 0x3F); chararr_count++; break; case 14: *//* 1110 xxxx 10xx xxxx 10xx xxxx*//* count += 3; if (count > utfLen) { throw new RuntimeException("malformed input: partial character at end"); } char2 = (char) ((bytearr[count - 2] + 256) % 256); char3 = (char) ((bytearr[count - 1] + 256) % 256); if ((char2 & 0xC0) != 0x80 || (char3 & 0xC0) != 0x80) { throw new RuntimeException("malformed input around byte " + (count - 1)); } chararr[chararr_count] = (char) (c & 0x0F << 12 | char2 & 0x3F << 6 | char3 & 0x3F << 0); chararr_count++; break; default: *//* 10xx xxxx, 1111 xxxx *//* throw new RuntimeException("malformed input around byte " + count); } } char[] res = new char[chararr_count]; for (int i = 0; i < chararr_count; i++) { res[i] = chararr[i]; } return new String(res); }*/ public String getVal() { return val; } } ================================================ FILE: Java/src/classpath/ClassPath.java ================================================ package classpath; import java.io.File; import java.io.IOException; import static classpath.Entry.createEntry; /** * Author: zhangxin * Time: 2017/5/1 0001. * Desc: */ public class ClassPath { // jre路径 private String jreDir; //分别存放三种类路径 private Entry bootClasspath; private Entry extClasspath; private Entry userClasspath; //parse()函数使用 -Xjre 选项解析启动类路径和扩展类路径 // 使用-classpath/-cp选项解析用户类路径 //以此来初始化成员变量的三种路径 public ClassPath(String jreOption, String cpOption) { jreDir = getJreDir(jreOption); bootClasspath = parseBootClasspath(); extClasspath = parseExtClasspath(); userClasspath = parseUserClasspath(cpOption); } private Entry parseBootClasspath() { //可能出现的情况是: jre/lib/* String jreLibPath = jreDir + File.separator + "lib" + File.separator + "*"; return new WildcardEntry(jreLibPath); } private Entry parseExtClasspath() { //可能出现的情况是: jre/lib/ext/* String jreExtPath = jreDir + File.separator + "lib" + File.separator + "ext" + File.separator + "*"; return new WildcardEntry(jreExtPath); } //确定传进来的jre的路径是否有效; private String getJreDir(String jreOption) { File jreFile; if (jreOption != null && !"".equals(jreOption)) { jreFile = new File(jreOption); if (jreFile.exists()) { return jreOption; } } //jreOption选项为空,那么在当前路径找 jreFile = new File("jre"); if (jreFile.exists()) { return jreFile.getAbsolutePath(); } //在JAVA_HOME中找 String java_home = System.getenv("JAVA_HOME"); if (java_home != null) { return java_home + File.separator + "jre"; } throw new RuntimeException("Can not find jre folder!"); } private Entry parseUserClasspath(String cpOption) { return Entry.createEntry(cpOption); } /*** * ClassPath 对外的统一接口,实例化ClassPath时传入 userPath 路径和类名就可以读取字节码文件 * 读取className 对应的字节码,注意顺序,我们的查找次序是: * bootClasspath => extClasspath => userClasspath; * @param className * @return */ public byte[] readClass(String className) { //注意,用命令行加载java文件时,只写文件名,所有这里统一为文件名后补上“.class”的后缀; if (className.endsWith(".class")) { throw new RuntimeException("can't find or can't load the class: " + className); } className = className.replace(".", "/"); className = className + ".class"; byte[] data; try { data = bootClasspath.readClass(className); if (data != null) { return data; } data = extClasspath.readClass(className); if (data != null) { return data; } data = userClasspath.readClass(className); if (data != null) { return data; } } catch (IOException e) { e.printStackTrace(); } throw new RuntimeException("can't find class!"); } @Override public String toString() { return userClasspath.printClassName(); } } ================================================ FILE: Java/src/classpath/CompositeEntry.java ================================================ package classpath; import java.io.IOException; import java.util.ArrayList; /** * Author: zhangxin * Time: 2017/4/30 0030. * Desc: CompositeEntry由众多的Entry组成,正好可以表示成 Entry list; * 构造函数把参数(路径列表)按分隔符分成小路径,然后把每个小路径都转换成具体的 Entry实例 */ public class CompositeEntry extends Entry { //不用担心,list中的entry是按照父类来转入的,在真正执行的时候,是按照各自的实际类型执行readClass()方法 ArrayList compositeEntries; private String pathList; public CompositeEntry() { } public CompositeEntry(String pathList, String pathListSeparator) { this.pathList = pathList; String[] paths = pathList.split(pathListSeparator); compositeEntries = new ArrayList(paths.length); for (int i = 0; i < paths.length; i++) { compositeEntries.add(new DirEntry(paths[i])); } } @Override byte[] readClass(String className) { byte[] data; for (int i = 0; i < compositeEntries.size(); i++) { try { data = compositeEntries.get(i).readClass(className); if (data != null) { return data; } } catch (IOException e) { e.printStackTrace(); } } return null; } @Override String printClassName() { return pathList; } } ================================================ FILE: Java/src/classpath/DirEntry.java ================================================ package classpath; import java.io.*; /** * Author: zhangxin * Time: 2017/4/30 0030. * Desc: 表示目录形式的类路径,这是相对来说最简单的一种了,拿到的直接就是指定的路径 */ public class DirEntry extends Entry { private String absDir; public DirEntry(String path) { File dir = new File(path); if (dir.exists()) { absDir = dir.getAbsolutePath(); } } /* @Override byte[] readClass(String className) { File file = new File(absDir, className); byte[] temp = new byte[1024]; BufferedInputStream in = null; ByteArrayOutputStream out = null; try { in = new BufferedInputStream(new FileInputStream(file)); out = new ByteArrayOutputStream(1024); int size = 0; while ((size = in.read(temp)) != -1) { out.write(temp, 0, size); } return out.toByteArray(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); if (out != null) { out.close(); } } catch (IOException e) { e.printStackTrace(); } } } return null; }*/ @Override byte[] readClass(String className) throws IOException { File file = new File(absDir, className); if (!file.exists()) { return null; } byte[] temp = new byte[1024]; BufferedInputStream in = null; ByteArrayOutputStream out = null; in = new BufferedInputStream(new FileInputStream(file)); out = new ByteArrayOutputStream(1024); int size = 0; while ((size = in.read(temp)) != -1) { out.write(temp, 0, size); } if (in != null) { in.close(); } if (out != null) { out.close(); } return out.toByteArray(); } @Override String printClassName() { return absDir; } } ================================================ FILE: Java/src/classpath/Entry.java ================================================ package classpath; import java.io.File; import java.io.IOException; /** * Author: zhangxin * Time: 2017/4/30 0030. * Desc: */ public abstract class Entry { //路径分隔符,在window下,使用 ; 分割开的 在Unix/Linux下使用: 分割开的 public static final String pathListSeparator = System.getProperty("os.name").contains("Windows") ? ";" : ":"; /** * 负责寻找和加载class文件 * * @param className class文件的相对路径,路径之间用斜线 / 分隔,文件名有.class后缀 */ abstract byte[] readClass(String className) throws IOException; /** * @return 返回className的字符串表示形式; */ abstract String printClassName(); /** * 工厂方法,根据传入的path的形式不同, * * @param path 命令行得到的路径字符串 * @return 创建具体的Entry */ static Entry createEntry(String path) { if (path != null) { if (path.contains(pathListSeparator)) { return new CompositeEntry(path, pathListSeparator); } else if (path.contains("*")) { return new WildcardEntry(""); } else if (path.contains(".jar") || path.contains(".JAR") || path.contains(".zip") || path.contains("" + ".ZIP")) { return new ZipJarEntry(path); } return new DirEntry(path); } else { //如果命令行中没有显式的指定-cp选项,那么默认要找的class就在当前路径下 File file = new File(""); try { path = file.getCanonicalPath(); return new DirEntry(path); } catch (IOException e) { e.printStackTrace(); } } throw new RuntimeException("illegal classpath format,or you should point out the classpath explicitly"); } } ================================================ FILE: Java/src/classpath/WildcardEntry.java ================================================ package classpath; import java.io.File; import java.util.ArrayList; /** * Author: zhangxin * Time: 2017/4/30 0030. * Desc:处理的是路径匹配的 xxx.* 的情况 * 首先把路径末尾的星号去掉,得到baseDir,然后遍历该baseDir路径下的文件,只取以 .jar 结尾的文件; * * 这个类其实是CompositeEntry的一个包装类; */ public class WildcardEntry extends Entry { public CompositeEntry compositeEntry; public WildcardEntry(String jreLibPath) { String baseDir = jreLibPath.substring(0, jreLibPath.length() - 1); //去掉最后的一个字符 * File dir = new File(baseDir); File[] files = dir.listFiles(); compositeEntry = new CompositeEntry(); compositeEntry.compositeEntries = new ArrayList(); for (File file : files) { if (file.isFile() && file.getName().endsWith(".jar")) { compositeEntry.compositeEntries.add(new ZipJarEntry(baseDir,file.getName())); } } // System.out.println(compositeEntry.compositeEntries.size()); } @Override byte[] readClass(String className) { return compositeEntry.readClass(className); } @Override String printClassName() { return null; } } ================================================ FILE: Java/src/classpath/ZipJarEntry.java ================================================ package classpath; import java.io.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; /** * Author: zhangxin * Time: 2017/4/30 0030. * Desc: ZipJarEntry表示ZIP或JAR文件形式的类路径,避免和Java中的ZipEntry冲突,起名为ZipJarEntry; */ public class ZipJarEntry extends Entry { String absPath; // E:\JavaSrc\JVMByHand\tmp\test.zip 全路径 String zipName; // test 压缩包名,不带 .zip 或者 jar public ZipJarEntry(String path) { File dir = new File(path); if (dir.exists()) { absPath = dir.getParentFile().getAbsolutePath(); zipName = dir.getName(); //去掉结尾的.zip或者.jar 千万别碰上其它情况,要不直接异常了; zipName = zipName.substring(0, zipName.length() - 4); } } public ZipJarEntry(String path, String zipName) { File dir = new File(path, zipName); if (dir.exists()) { absPath = dir.getAbsolutePath(); //去掉结尾的.zip或者.jar 千万别碰上其它情况,要不直接异常了; this.zipName = zipName.substring(0, zipName.length() - 4); } } /** * 从zip或者jar文件中提取class文件; * * @param className class文件的相对路径,路径之间用斜线 / 分隔,文件名有.class后缀 */ @Override byte[] readClass(String className) throws IOException { File file = new File(absPath); ZipInputStream zin = null; BufferedInputStream in = null; ByteArrayOutputStream out = null; ZipFile zf = new ZipFile(file); // ZipEntry ze = zf.getEntry(zipName + "/" + className); //如果是zip文件,获取ZipEntry的时候,直接用zipName+"/"+className ZipEntry ze = zf.getEntry(className); //如果是jar包,获取ZipEntry的时候,直接用className, if (ze == null) { return null; } in = new BufferedInputStream(zf.getInputStream(ze)); out = new ByteArrayOutputStream(1024); int size = 0; byte[] temp = new byte[1024]; while ((size = in.read(temp)) != -1) { out.write(temp, 0, size); } if (zin != null) { zin.closeEntry(); } if (in != null) { in.close(); } if (out != null) { out.close(); } return out.toByteArray(); } @Override String printClassName() { return absPath; } } ================================================ FILE: Java/src/instructions/InstructionFactory.java ================================================ package instructions; import instructions.base.Instruction; import instructions.comparisons.dcmp.DCMPG; import instructions.comparisons.dcmp.DCMPL; import instructions.comparisons.fcmp.FCMPG; import instructions.comparisons.fcmp.FCMPL; import instructions.comparisons.ifacmp.IF_ACMPEQ; import instructions.comparisons.ifacmp.IF_ACMPNE; import instructions.comparisons.ifcond.*; import instructions.comparisons.ificmp.*; import instructions.comparisons.lcmp.LCMP; import instructions.constants.*; import instructions.control.*; import instructions.conversions.d2x.D2F; import instructions.conversions.d2x.D2I; import instructions.conversions.d2x.D2L; import instructions.conversions.f2x.F2D; import instructions.conversions.f2x.F2I; import instructions.conversions.f2x.F2L; import instructions.conversions.i2x.*; import instructions.conversions.l2x.L2D; import instructions.conversions.l2x.L2F; import instructions.conversions.l2x.L2I; import instructions.extended.GOTO_W; import instructions.extended.IFNONNULL; import instructions.extended.IFNULL; import instructions.extended.WIDE; import instructions.loads.loaddouble.*; import instructions.loads.loadfloat.*; import instructions.loads.loadint.*; import instructions.loads.loadlong.*; import instructions.loads.loadref.*; import instructions.loads.loadxarr.*; import instructions.math.add.DADD; import instructions.math.add.FADD; import instructions.math.add.IADD; import instructions.math.add.LADD; import instructions.math.and.IAND; import instructions.math.and.LAND; import instructions.math.div.DDIV; import instructions.math.div.FDIV; import instructions.math.div.IDIV; import instructions.math.div.LDIV; import instructions.math.iinc.IINC; import instructions.math.mul.DMUL; import instructions.math.mul.FMUL; import instructions.math.mul.IMUL; import instructions.math.mul.LMUL; import instructions.math.neg.DNEG; import instructions.math.neg.FNEG; import instructions.math.neg.INEG; import instructions.math.neg.LNEG; import instructions.math.or.IOR; import instructions.math.or.LOR; import instructions.math.rem.DREM; import instructions.math.rem.FREM; import instructions.math.rem.IREM; import instructions.math.rem.LREM; import instructions.math.sh.*; import instructions.math.sub.DSUB; import instructions.math.sub.FSUB; import instructions.math.sub.ISUB; import instructions.math.sub.LSUB; import instructions.math.xor.IXOR; import instructions.math.xor.LXOR; import instructions.references.*; import instructions.stack.dup.*; import instructions.stack.pop.POP; import instructions.stack.pop.POP2; import instructions.stack.swap.SWAP; import instructions.stores.storedouble.*; import instructions.stores.storefloat.*; import instructions.stores.storeint.*; import instructions.stores.storelong.*; import instructions.stores.storeref.*; import instructions.stores.storexarr.*; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class InstructionFactory { static NOP nop = new NOP(); static ACONST_NULL aconst_null = new ACONST_NULL(); static ICONST_M1 iconst_m1 = new ICONST_M1(); static ICONST_0 iconst_0 = new ICONST_0(); static ICONST_1 iconst_1 = new ICONST_1(); static ICONST_2 iconst_2 = new ICONST_2(); static ICONST_3 iconst_3 = new ICONST_3(); static ICONST_4 iconst_4 = new ICONST_4(); static ICONST_5 iconst_5 = new ICONST_5(); static LCONST_0 lconst_0 = new LCONST_0(); static LCONST_1 lconst_1 = new LCONST_1(); static FCONST_0 fconst_0 = new FCONST_0(); static FCONST_1 fconst_1 = new FCONST_1(); static FCONST_2 fconst_2 = new FCONST_2(); static DCONST_0 dconst_0 = new DCONST_0(); static DCONST_1 dconst_1 = new DCONST_1(); static ILOAD_0 iload_0 = new ILOAD_0(); static ILOAD_1 iload_1 = new ILOAD_1(); static ILOAD_2 iload_2 = new ILOAD_2(); static ILOAD_3 iload_3 = new ILOAD_3(); static LLOAD_0 lload_0 = new LLOAD_0(); static LLOAD_1 lload_1 = new LLOAD_1(); static LLOAD_2 lload_2 = new LLOAD_2(); static LLOAD_3 lload_3 = new LLOAD_3(); static FLOAD_0 fload_0 = new FLOAD_0(); static FLOAD_1 fload_1 = new FLOAD_1(); static FLOAD_2 fload_2 = new FLOAD_2(); static FLOAD_3 fload_3 = new FLOAD_3(); static DLOAD_0 dload_0 = new DLOAD_0(); static DLOAD_1 dload_1 = new DLOAD_1(); static DLOAD_2 dload_2 = new DLOAD_2(); static DLOAD_3 dload_3 = new DLOAD_3(); static ALOAD_0 aload_0 = new ALOAD_0(); static ALOAD_1 aload_1 = new ALOAD_1(); static ALOAD_2 aload_2 = new ALOAD_2(); static ALOAD_3 aload_3 = new ALOAD_3(); static IALOAD iaload = new IALOAD(); static LALOAD laload = new LALOAD(); static FALOAD faload = new FALOAD(); static DALOAD daload = new DALOAD(); static AALOAD aaload = new AALOAD(); static BALOAD baload = new BALOAD(); static CALOAD caload = new CALOAD(); static SALOAD saload = new SALOAD(); static ISTORE_0 istore_0 = new ISTORE_0(); static ISTORE_1 istore_1 = new ISTORE_1(); static ISTORE_2 istore_2 = new ISTORE_2(); static ISTORE_3 istore_3 = new ISTORE_3(); static LSTORE_0 lstore_0 = new LSTORE_0(); static LSTORE_1 lstore_1 = new LSTORE_1(); static LSTORE_2 lstore_2 = new LSTORE_2(); static LSTORE_3 lstore_3 = new LSTORE_3(); static FSTORE_0 fstore_0 = new FSTORE_0(); static FSTORE_1 fstore_1 = new FSTORE_1(); static FSTORE_2 fstore_2 = new FSTORE_2(); static FSTORE_3 fstore_3 = new FSTORE_3(); static DSTORE_0 dstore_0 = new DSTORE_0(); static DSTORE_1 dstore_1 = new DSTORE_1(); static DSTORE_2 dstore_2 = new DSTORE_2(); static DSTORE_3 dstore_3 = new DSTORE_3(); static ASTORE_0 astore_0 = new ASTORE_0(); static ASTORE_1 astore_1 = new ASTORE_1(); static ASTORE_2 astore_2 = new ASTORE_2(); static ASTORE_3 astore_3 = new ASTORE_3(); static IASTORE iastore = new IASTORE(); static LASTORE lastore = new LASTORE(); static FASTORE fastore = new FASTORE(); static DASTORE dastore = new DASTORE(); static AASTORE aastore = new AASTORE(); static BASTORE bastore = new BASTORE(); static CASTORE castore = new CASTORE(); static SASTORE sastore = new SASTORE(); static POP pop = new POP(); static POP2 pop2 = new POP2(); static DUP dup = new DUP(); static DUP_X1 dup_x1 = new DUP_X1(); static DUP_X2 dup_x2 = new DUP_X2(); static DUP2 dup2 = new DUP2(); static DUP2_X1 dup2_x1 = new DUP2_X1(); static DUP2_X2 dup2_x2 = new DUP2_X2(); static SWAP swap = new SWAP(); static IADD iadd = new IADD(); static LADD ladd = new LADD(); static FADD fadd = new FADD(); static DADD dadd = new DADD(); static ISUB isub = new ISUB(); static LSUB lsub = new LSUB(); static FSUB fsub = new FSUB(); static DSUB dsub = new DSUB(); static IMUL imul = new IMUL(); static LMUL lmul = new LMUL(); static FMUL fmul = new FMUL(); static DMUL dmul = new DMUL(); static IDIV idiv = new IDIV(); static LDIV ldiv = new LDIV(); static FDIV fdiv = new FDIV(); static DDIV ddiv = new DDIV(); static IREM irem = new IREM(); static LREM lrem = new LREM(); static FREM frem = new FREM(); static DREM drem = new DREM(); static INEG ineg = new INEG(); static LNEG lneg = new LNEG(); static FNEG fneg = new FNEG(); static DNEG dneg = new DNEG(); static ISHL ishl = new ISHL(); static LSHL lshl = new LSHL(); static ISHR ishr = new ISHR(); static LSHR lshr = new LSHR(); static IUSHR iushr = new IUSHR(); static LUSHR lushr = new LUSHR(); static IAND iand = new IAND(); static LAND land = new LAND(); static IOR ior = new IOR(); static LOR lor = new LOR(); static IXOR ixor = new IXOR(); static LXOR lxor = new LXOR(); static I2L i2l = new I2L(); static I2F i2f = new I2F(); static I2D i2d = new I2D(); static L2I l2i = new L2I(); static L2F l2f = new L2F(); static L2D l2d = new L2D(); static F2I f2i = new F2I(); static F2L f2l = new F2L(); static F2D f2d = new F2D(); static D2I d2i = new D2I(); static D2L d2l = new D2L(); static D2F d2f = new D2F(); static I2B i2b = new I2B(); static I2C i2c = new I2C(); static I2S i2s = new I2S(); static LCMP lcmp = new LCMP(); static FCMPL fcmpl = new FCMPL(); static FCMPG fcmpg = new FCMPG(); static DCMPL dcmpl = new DCMPL(); static DCMPG dcmpg = new DCMPG(); static IRETURN ireturn = new IRETURN(); static LRETURN lreturn = new LRETURN(); static FRETURN freturn = new FRETURN(); static DRETURN dreturn = new DRETURN(); static ARETURN areturn = new ARETURN(); static RETURN _return = new RETURN(); static ARRAY_LENGTH arraylength = new ARRAY_LENGTH(); static ATHROW athrow = new ATHROW(); /* static MONITOR_ENTER monitorenter = new MONITOR_ENTER(); static MONITOR_EXIT monitorexit = new MONITOR_EXIT(); */ static INVOKE_NATIVE invoke_native = new INVOKE_NATIVE(); public static Instruction createInstruction(int opCode) { switch (opCode) { case 0x00: return nop; case 0x01: return aconst_null; case 0x02: return iconst_m1; case 0x03: return iconst_0; case 0x04: return iconst_1; case 0x05: return iconst_2; case 0x06: return iconst_3; case 0x07: return iconst_4; case 0x08: return iconst_5; case 0x09: return lconst_0; case 0x0a: return lconst_1; case 0x0b: return fconst_0; case 0x0c: return fconst_1; case 0x0d: return fconst_2; case 0x0e: return dconst_0; case 0x0f: return dconst_1; case 0x10: return new BIPUSH(); case 0x11: return new SIPUSH(); case 0x12: return new LDC(); case 0x13: return new LDC_W(); case 0x14: return new LDC2_W(); case 0x15: return new ILOAD(); case 0x16: return new LLOAD(); case 0x17: return new FLOAD(); case 0x18: return new DLOAD(); case 0x19: return new ALOAD(); case 0x1a: return iload_0; case 0x1b: return iload_1; case 0x1c: return iload_2; case 0x1d: return iload_3; case 0x1e: return lload_0; case 0x1f: return lload_1; case 0x20: return lload_2; case 0x21: return lload_3; case 0x22: return fload_0; case 0x23: return fload_1; case 0x24: return fload_2; case 0x25: return fload_3; case 0x26: return dload_0; case 0x27: return dload_1; case 0x28: return dload_2; case 0x29: return dload_3; case 0x2a: return aload_0; case 0x2b: return aload_1; case 0x2c: return aload_2; case 0x2d: return aload_3; case 0x2e: return iaload; case 0x2f: return laload; case 0x30: return faload; case 0x31: return daload; case 0x32: return aaload; case 0x33: return baload; case 0x34: return caload; case 0x35: return saload; case 0x36: return new ISTORE(); case 0x37: return new LSTORE(); case 0x38: return new FSTORE(); case 0x39: return new DSTORE(); case 0x3a: return new ASTORE(); case 0x3b: return istore_0; case 0x3c: return istore_1; case 0x3d: return istore_2; case 0x3e: return istore_3; case 0x3f: return lstore_0; case 0x40: return lstore_1; case 0x41: return lstore_2; case 0x42: return lstore_3; case 0x43: return fstore_0; case 0x44: return fstore_1; case 0x45: return fstore_2; case 0x46: return fstore_3; case 0x47: return dstore_0; case 0x48: return dstore_1; case 0x49: return dstore_2; case 0x4a: return dstore_3; case 0x4b: return astore_0; case 0x4c: return astore_1; case 0x4d: return astore_2; case 0x4e: return astore_3; case 0x4f: return iastore; case 0x50: return lastore; case 0x51: return fastore; case 0x52: return dastore; case 0x53: return aastore; case 0x54: return bastore; case 0x55: return castore; case 0x56: return sastore; case 0x57: return pop; case 0x58: return pop2; case 0x59: return dup; case 0x5a: return dup_x1; case 0x5b: return dup_x2; case 0x5c: return dup2; case 0x5d: return dup2_x1; case 0x5e: return dup2_x2; case 0x5f: return swap; case 0x60: return iadd; case 0x61: return ladd; case 0x62: return fadd; case 0x63: return dadd; case 0x64: return isub; case 0x65: return lsub; case 0x66: return fsub; case 0x67: return dsub; case 0x68: return imul; case 0x69: return lmul; case 0x6a: return fmul; case 0x6b: return dmul; case 0x6c: return idiv; case 0x6d: return ldiv; case 0x6e: return fdiv; case 0x6f: return ddiv; case 0x70: return irem; case 0x71: return lrem; case 0x72: return frem; case 0x73: return drem; case 0x74: return ineg; case 0x75: return lneg; case 0x76: return fneg; case 0x77: return dneg; case 0x78: return ishl; case 0x79: return lshl; case 0x7a: return ishr; case 0x7b: return lshr; case 0x7c: return iushr; case 0x7d: return lushr; case 0x7e: return iand; case 0x7f: return land; case 0x80: return ior; case 0x81: return lor; case 0x82: return ixor; case 0x83: return lxor; case 0x84: return new IINC(); case 0x85: return i2l; case 0x86: return i2f; case 0x87: return i2d; case 0x88: return l2i; case 0x89: return l2f; case 0x8a: return l2d; case 0x8b: return f2i; case 0x8c: return f2l; case 0x8d: return f2d; case 0x8e: return d2i; case 0x8f: return d2l; case 0x90: return d2f; case 0x91: return i2b; case 0x92: return i2c; case 0x93: return i2s; case 0x94: return lcmp; case 0x95: return fcmpl; case 0x96: return fcmpg; case 0x97: return dcmpl; case 0x98: return dcmpg; case 0x99: return new IFEQ(); case 0x9a: return new IFNE(); case 0x9b: return new IFLT(); case 0x9c: return new IFGE(); case 0x9d: return new IFGT(); case 0x9e: return new IFLE(); case 0x9f: return new IF_ICMPEQ(); case 0xa0: return new IF_ICMPNE(); case 0xa1: return new IF_ICMPLT(); case 0xa2: return new IF_ICMPGE(); case 0xa3: return new IF_ICMPGT(); case 0xa4: return new IF_ICMPLE(); case 0xa5: return new IF_ACMPEQ(); case 0xa6: return new IF_ACMPNE(); case 0xa7: return new GOTO(); // case 0xa8: // return new JSR(); // case 0xa9: // return new RET(); case 0xaa: return new TABLE_SWITCH(); case 0xab: return new LOOKUP_SWITCH(); case 0xac: return ireturn; case 0xad: return lreturn; case 0xae: return freturn; case 0xaf: return dreturn; case 0xb0: return areturn; case 0xb1: return _return; case 0xb2: return new GET_STATIC(); case 0xb3: return new PUT_STATIC(); case 0xb4: return new GET_FIELD(); case 0xb5: return new PUT_FIELD(); case 0xb6: return new INVOKE_VIRTUAL(); case 0xb7: return new INVOKE_SPECIAL(); case 0xb8: return new INVOKE_STATIC(); case 0xb9: return new INVOKE_INTERFACE(); // case 0xba: // return new INVOKE_DYNAMIC(); case 0xbb: return new NEW(); case 0xbc: return new NEW_ARRAY(); case 0xbd: return new ANEW_ARRAY(); case 0xbe: return arraylength; case 0xbf: return athrow; case 0xc0: return new CHECK_CAST(); case 0xc1: return new INSTANCE_OF(); // case 0xc2: // return monitorenter; // case 0xc3: // return monitorexit; case 0xc4: return new WIDE(); case 0xc5: return new MULTI_ANEW_ARRAY(); case 0xc6: return new IFNULL(); case 0xc7: return new IFNONNULL(); case 0xc8: return new GOTO_W(); // case 0xc9: // return new JSR_W(); // case 0xca: breakpoint case 0xfe: return invoke_native; // case 0xff: impdep2 default: throw new RuntimeException("Unsupported opcode: " + opCode); } } } ================================================ FILE: Java/src/instructions/base/BranchInstruction.java ================================================ package instructions.base; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc:表示跳转指令,Offset字段存放跳转偏移量。 * 这个类是指令的子类,只负责读取offset,和BranchLogic类区别是: * BranchLogic负责将BranchInstruction拿到的offset值,从新计算pc,并赋值给Frame.pc; */ public abstract class BranchInstruction implements Instruction { public int offset; @Override public void fetchOperands(BytecodeReader reader) { offset = reader.readInt16(); } } ================================================ FILE: Java/src/instructions/base/BranchLogic.java ================================================ package instructions.base; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 真正的跳转逻辑,因为这个函数在很多指令中都会用到,所以把它定义base中 */ public class BranchLogic { public static void branch(Zframe frame, int offset) { int pc = frame.getThread().getPc(); int nextPC = pc + offset; frame.setNextPC(nextPC); } } ================================================ FILE: Java/src/instructions/base/BytecodeReader.java ================================================ package instructions.base; import Utils.ByteUtils; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class BytecodeReader { private byte[] code; //byte的范围四-128~127,和go中的byte:0~255不同,所以在取数据的时候需要注意; private int pc; /** * @param code * @param pc */ public void reset(byte[] code, int pc) { this.code = code; this.pc = pc; } public int getPc() { return pc; } public byte readInt8() { byte res = code[pc]; pc++; return res; } public int readUint8() { int res = code[pc]; res = (res + 256) % 256; pc++; return res; } public int readInt16() { return (short) readUint16(); } public int readUint16() { int a1 = readUint8(); int a2 = readUint8(); return (a1 << 8 | a2); } public int readInt32() { byte[] data = new byte[4]; data[0] = readInt8(); data[1] = readInt8(); data[2] = readInt8(); data[3] = readInt8(); return ByteUtils.byteToInt32(data); } public int[] readInt32s(int n) { int[] data = new int[n]; for (int i = 0; i < n; i++) { data[i] = readInt32(); } return data; } //4k对齐,没有对齐的会有填充数据,这些数据要忽略掉; public void skipPadding() { while (pc % 4 != 0) { readInt8(); } } } ================================================ FILE: Java/src/instructions/base/ClassInitLogic.java ================================================ package instructions.base; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.Zclass; import runtimedata.heap.Zmethod; /** * @author zachaxy * @date 17/12/28 * desc:执行类的初始化 */ public class ClassInitLogic { public static void initClass(Zthread thread, Zclass clazz) { clazz.startInit(); scheduleClinit(thread, clazz); initSuperClass(thread, clazz); } private static void scheduleClinit(Zthread thread, Zclass clazz) { Zmethod clinit = clazz.getMethod("", "()V"); if (clinit != null && clinit.getClazz() == clazz) { // exec Zframe newFrame = thread.createFrame(clinit); thread.pushFrame(newFrame); } } private static void initSuperClass(Zthread thread, Zclass clazz) { if (!clazz.isInterface()) { Zclass superClass = clazz.getSuperClass(); if (superClass != null && !superClass.isInitStarted()) { initClass(thread, superClass); } } } } ================================================ FILE: Java/src/instructions/base/Index16Instruction.java ================================================ package instructions.base; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc:有一些指令需要访问运行时常量池,常量池索引由两字节操作数给出。 */ public abstract class Index16Instruction implements Instruction { public int index; @Override public void fetchOperands(BytecodeReader reader) { index = reader.readUint16(); } } ================================================ FILE: Java/src/instructions/base/Index8Instruction.java ================================================ package instructions.base; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc:存储和加载类指令需要根据索引存取局部变量表,索引由单字节操作数给出 * 部分存储和加载指令是自带操作数的,所以不需要index; * 然后其余部分的指令,只有加载/存储的语义,并不知道将数据存储/加载到局部变量表的哪一位,所以需要index */ public abstract class Index8Instruction implements Instruction { public Index8Instruction(){} public int index; @Override public void fetchOperands(BytecodeReader reader) { index = reader.readUint8(); } } ================================================ FILE: Java/src/instructions/base/Instruction.java ================================================ package instructions.base; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 每个指令都会实现该接口,所有的指令逻辑都是先从字节码数组中取数据,然后执行各自的逻辑 */ public interface Instruction { //从字节码中提取操作数 void fetchOperands(BytecodeReader reader); //执行指令逻辑 void execute(Zframe frame); } ================================================ FILE: Java/src/instructions/base/MethodInvokeLogic.java ================================================ package instructions.base; import runtimedata.Slot; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.Zmethod; /** * @author zachaxy * @date 17/12/27 */ public class MethodInvokeLogic { public static void invokeMethod(Zframe invokerFrame, Zmethod method) { Zthread thread = invokerFrame.getThread(); Zframe newFrame = thread.createFrame(method); thread.pushFrame(newFrame); int argSlotCount = method.getArgSlotCount(); if (argSlotCount > 0) { for (int i = argSlotCount - 1; i >= 0; i--) { Slot slot = invokerFrame.getOperandStack().popSlot(); newFrame.getLocalVars().setSlot(i, slot); } } } } ================================================ FILE: Java/src/instructions/base/NoOperandsInstruction.java ================================================ package instructions.base; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc:表示没有操作数的指令,所以没有定义 任何字段。FetchOperands方法也是空实现,什么也不用读 */ public abstract class NoOperandsInstruction implements Instruction{ @Override public void fetchOperands(BytecodeReader reader) { } } ================================================ FILE: Java/src/instructions/comparisons/dcmp/DCMP.java ================================================ package instructions.comparisons.dcmp; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 由于浮点数计算有可能产生NaN(Not a Number)值,所以比较两个浮点数时,除了大于、等于、小于之外, 还有第4种结果:无法比较 * fcmpg和fcmpl指令的区别就在于对第4种结果的定义; * 当两个float变量中至少有一个是NaN时,用fcmpg指令比较的结果是1,而用fcmpl指令比较的结果是-1。 */ public class DCMP { static void _dcmp(Zframe frame, boolean flag) { OperandStack stack = frame.getOperandStack(); double val2 = stack.popDouble(); double val1 = stack.popDouble(); if (val1 > val2) { stack.pushInt(1); } else if (val1 == val2) { stack.pushInt(0); } else if (val1 > val2) { stack.pushInt(-1); } else if (flag) { stack.pushInt(1); } else { stack.pushInt(-1); } } } ================================================ FILE: Java/src/instructions/comparisons/dcmp/DCMPG.java ================================================ package instructions.comparisons.dcmp; import instructions.base.NoOperandsInstruction; import instructions.comparisons.fcmp.FCMP; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DCMPG extends NoOperandsInstruction { @Override public void execute(Zframe frame) { DCMP._dcmp(frame, true); } } ================================================ FILE: Java/src/instructions/comparisons/dcmp/DCMPL.java ================================================ package instructions.comparisons.dcmp; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DCMPL extends NoOperandsInstruction { @Override public void execute(Zframe frame) { DCMP._dcmp(frame, false); } } ================================================ FILE: Java/src/instructions/comparisons/fcmp/FCMP.java ================================================ package instructions.comparisons.fcmp; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 由于浮点数计算有可能产生NaN(Not a Number)值,所以比较两个浮点数时,除了大于、等于、小于之外, 还有第4种结果:无法比较 * fcmpg和fcmpl指令的区别就在于对第4种结果的定义; * 当两个float变量中至少有一个是NaN时,用fcmpg指令比较的结果是1,而用fcmpl指令比较的结果是-1。 */ public class FCMP { static void _fcmp(Zframe frame, boolean flag) { OperandStack stack = frame.getOperandStack(); float val2 = stack.popFloat(); float val1 = stack.popFloat(); if (val1 > val2) { stack.pushInt(1); } else if (val1 == val2) { stack.pushInt(0); } else if (val1 > val2) { stack.pushInt(-1); } else if (flag) { stack.pushInt(1); } else { stack.pushInt(-1); } } } ================================================ FILE: Java/src/instructions/comparisons/fcmp/FCMPG.java ================================================ package instructions.comparisons.fcmp; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FCMPG extends NoOperandsInstruction { @Override public void execute(Zframe frame) { FCMP._fcmp(frame, true); } } ================================================ FILE: Java/src/instructions/comparisons/fcmp/FCMPL.java ================================================ package instructions.comparisons.fcmp; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FCMPL extends NoOperandsInstruction { @Override public void execute(Zframe frame) { FCMP._fcmp(frame, false); } } ================================================ FILE: Java/src/instructions/comparisons/ifacmp/IF_ACMPEQ.java ================================================ package instructions.comparisons.ifacmp; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IF_ACMPEQ extends BranchInstruction { @Override public void execute(Zframe frame) { if (IfAcmp._acmp(frame)) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ifacmp/IF_ACMPNE.java ================================================ package instructions.comparisons.ifacmp; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IF_ACMPNE extends BranchInstruction { @Override public void execute(Zframe frame) { if (!IfAcmp._acmp(frame)) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ifacmp/IfAcmp.java ================================================ package instructions.comparisons.ifacmp; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IfAcmp { public static boolean _acmp(Zframe frame) { OperandStack stack = frame.getOperandStack(); Zobject ref2 = stack.popRef(); Zobject ref1 = stack.popRef(); return ref1 == ref2; } } ================================================ FILE: Java/src/instructions/comparisons/ifcond/IFEQ.java ================================================ package instructions.comparisons.ifcond; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IFEQ extends BranchInstruction { @Override public void execute(Zframe frame) { int val = frame.getOperandStack().popInt(); if (val == 0) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ifcond/IFGE.java ================================================ package instructions.comparisons.ifcond; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IFGE extends BranchInstruction { @Override public void execute(Zframe frame) { int val = frame.getOperandStack().popInt(); if (val >= 0) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ifcond/IFGT.java ================================================ package instructions.comparisons.ifcond; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IFGT extends BranchInstruction { @Override public void execute(Zframe frame) { int val = frame.getOperandStack().popInt(); if (val > 0) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ifcond/IFLE.java ================================================ package instructions.comparisons.ifcond; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IFLE extends BranchInstruction { @Override public void execute(Zframe frame) { int val = frame.getOperandStack().popInt(); if (val <= 0) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ifcond/IFLT.java ================================================ package instructions.comparisons.ifcond; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IFLT extends BranchInstruction { @Override public void execute(Zframe frame) { int val = frame.getOperandStack().popInt(); if (val < 0) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ifcond/IFNE.java ================================================ package instructions.comparisons.ifcond; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IFNE extends BranchInstruction { @Override public void execute(Zframe frame) { int val = frame.getOperandStack().popInt(); if (val != 0) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ificmp/IF_ICMPEQ.java ================================================ package instructions.comparisons.ificmp; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: */ public class IF_ICMPEQ extends BranchInstruction { @Override public void execute(Zframe frame) { int[] res = IfIcmp._icmpPop(frame); int val1 = res[0]; int val2 = res[1]; if (val1 == val2) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ificmp/IF_ICMPGE.java ================================================ package instructions.comparisons.ificmp; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: */ public class IF_ICMPGE extends BranchInstruction { @Override public void execute(Zframe frame) { int[] res = IfIcmp._icmpPop(frame); int val1 = res[0]; int val2 = res[1]; if (val1 >= val2) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ificmp/IF_ICMPGT.java ================================================ package instructions.comparisons.ificmp; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: */ public class IF_ICMPGT extends BranchInstruction { @Override public void execute(Zframe frame) { int[] res = IfIcmp._icmpPop(frame); int val1 = res[0]; int val2 = res[1]; if (val1 > val2) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ificmp/IF_ICMPLE.java ================================================ package instructions.comparisons.ificmp; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: */ public class IF_ICMPLE extends BranchInstruction { @Override public void execute(Zframe frame) { int[] res = IfIcmp._icmpPop(frame); int val1 = res[0]; int val2 = res[1]; if (val1 <= val2) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ificmp/IF_ICMPLT.java ================================================ package instructions.comparisons.ificmp; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: */ public class IF_ICMPLT extends BranchInstruction { @Override public void execute(Zframe frame) { int[] res = IfIcmp._icmpPop(frame); int val1 = res[0]; int val2 = res[1]; if (val1 < val2) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ificmp/IF_ICMPNE.java ================================================ package instructions.comparisons.ificmp; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: */ public class IF_ICMPNE extends BranchInstruction { @Override public void execute(Zframe frame) { int[] res = IfIcmp._icmpPop(frame); int val1 = res[0]; int val2 = res[1]; if (val1 != val2) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/comparisons/ificmp/IfIcmp.java ================================================ package instructions.comparisons.ificmp; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: */ public class IfIcmp { static int[] _icmpPop(Zframe frame) { OperandStack stack = frame.getOperandStack(); int[] res = new int[2]; res[1] = stack.popInt(); res[0] = stack.popInt(); return res; } } ================================================ FILE: Java/src/instructions/comparisons/lcmp/LCMP.java ================================================ package instructions.comparisons.lcmp; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LCMP extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val2 = stack.popLong(); long val1 = stack.popLong(); if (val1 > val2) { stack.pushInt(1); } else if (val1 == val2) { stack.pushInt(0); } else { stack.pushInt(-1); } } } ================================================ FILE: Java/src/instructions/constants/ACONST_NULL.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: push null */ public class ACONST_NULL extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushRef(null); } } ================================================ FILE: Java/src/instructions/constants/BIPUSH.java ================================================ package instructions.constants; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc:bipush指令从操作数中获取一个byte型整数,扩展成int型,然后推入栈顶 */ public class BIPUSH implements Instruction { int val; @Override public void fetchOperands(BytecodeReader reader) { val = reader.readInt8(); } @Override public void execute(Zframe frame) { // 源码是独到一个int8,然后再用int32将其扩展,那么就变成了实际值。但是在Java中直接扩展还是原值,所以要进行修正在push; frame.getOperandStack().pushInt((val + 256) % 256); } } ================================================ FILE: Java/src/instructions/constants/DCONST_0.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc:Push double */ public class DCONST_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushDouble(0.0); } } ================================================ FILE: Java/src/instructions/constants/DCONST_1.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DCONST_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushDouble(1.0); } } ================================================ FILE: Java/src/instructions/constants/FCONST_0.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push float */ public class FCONST_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushFloat(0.0f); } } ================================================ FILE: Java/src/instructions/constants/FCONST_1.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push float */ public class FCONST_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushFloat(1.0f); } } ================================================ FILE: Java/src/instructions/constants/FCONST_2.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push float */ public class FCONST_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushFloat(2.0f); } } ================================================ FILE: Java/src/instructions/constants/ICONST_0.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push int constant */ public class ICONST_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushInt(0); } } ================================================ FILE: Java/src/instructions/constants/ICONST_1.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push int constant */ public class ICONST_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushInt(1); } } ================================================ FILE: Java/src/instructions/constants/ICONST_2.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push int constant */ public class ICONST_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushInt(2); } } ================================================ FILE: Java/src/instructions/constants/ICONST_3.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push int constant */ public class ICONST_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushInt(3); } } ================================================ FILE: Java/src/instructions/constants/ICONST_4.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push int constant */ public class ICONST_4 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushInt(4); } } ================================================ FILE: Java/src/instructions/constants/ICONST_5.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push int constant */ public class ICONST_5 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushInt(5); } } ================================================ FILE: Java/src/instructions/constants/ICONST_M1.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push int constant */ public class ICONST_M1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushInt(-1); } } ================================================ FILE: Java/src/instructions/constants/LCONST_0.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push int constant */ public class LCONST_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushLong(0); } } ================================================ FILE: Java/src/instructions/constants/LCONST_1.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: Push int constant */ public class LCONST_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().pushLong(1); } } ================================================ FILE: Java/src/instructions/constants/LDC.java ================================================ package instructions.constants; import classfile.classconstant.ConstantInfo; import instructions.base.Index8Instruction; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.*; /** * @author zachaxy * @date 17/12/26 * desc:获取操作数index,通过 index 来获取运行时常量池中的常量,并将其压入操作数栈 */ public class LDC extends Index8Instruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); Zclass clazz = frame.getMethod().getClazz(); RuntimeConstantInfo runtimeConstant = clazz.getRuntimeConstantPool().getRuntimeConstant(index); switch (runtimeConstant.getType()) { case ConstantInfo.CONSTANT_Integer: operandStack.pushInt((Integer) runtimeConstant.getValue()); break; case ConstantInfo.CONSTANT_Float: operandStack.pushFloat((Float) runtimeConstant.getValue()); break; case ConstantInfo.CONSTANT_String: Zobject internedStr = StringPool.jString(clazz.getLoader(), (String) runtimeConstant.getValue()); operandStack.pushRef(internedStr); break; case ConstantInfo.CONSTANT_Class: ClassRef classRef = (ClassRef) runtimeConstant.getValue(); Zobject jObject = classRef.resolvedClass().getjObject(); operandStack.pushRef(jObject); break; // case MethodType, MethodHandle //Java7中的特性,不在本虚拟机范围内 default: break; } } } ================================================ FILE: Java/src/instructions/constants/LDC2_W.java ================================================ package instructions.constants; import classfile.classconstant.ConstantInfo; import instructions.base.Index16Instruction; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.RuntimeConstantInfo; import runtimedata.heap.Zclass; /** * @author zachaxy * @date 17/12/26 * desc:LDC2_W 和 LDC 的区别是,其获取常量池的常量类型为 Long 和 Double,都是 16bit 宽的 */ public class LDC2_W extends Index16Instruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); Zclass clazz = frame.getMethod().getClazz(); RuntimeConstantInfo runtimeConstant = clazz.getRuntimeConstantPool().getRuntimeConstant(index); switch (runtimeConstant.getType()){ case ConstantInfo.CONSTANT_Long: operandStack.pushLong((Long) runtimeConstant.getValue()); break; case ConstantInfo.CONSTANT_Double: operandStack.pushDouble((Double) runtimeConstant.getValue()); break; default: throw new ClassFormatError(); } } } ================================================ FILE: Java/src/instructions/constants/LDC_W.java ================================================ package instructions.constants; import instructions.base.BytecodeReader; /** * @author zachaxy * @date 17/12/26 * desc:LDC_W和 LDC 的 execute 是完全一样的,唯一的区别就是去操作数的位宽,w 取16位,非 w 取8位 * 所以 LDC_W 复用了 LDC 的 execute 过程,但是重写了其 fetch 方法,改为取16位宽 */ public class LDC_W extends LDC { @Override public void fetchOperands(BytecodeReader reader) { index = reader.readUint16(); } } ================================================ FILE: Java/src/instructions/constants/NOP.java ================================================ package instructions.constants; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: nop指令是最简单的一条指令,因为它什么也不做 */ public class NOP extends NoOperandsInstruction{ @Override public void execute(Zframe frame) { } } ================================================ FILE: Java/src/instructions/constants/SIPUSH.java ================================================ package instructions.constants; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc:sipush指令从操作数中获取一个short型整数,扩展成int型,然后推入栈顶 */ public class SIPUSH implements Instruction { int val; @Override public void fetchOperands(BytecodeReader reader) { val = reader.readInt16(); } @Override public void execute(Zframe frame) { frame.getOperandStack().pushInt((val + 65536) % 65536); } } ================================================ FILE: Java/src/instructions/control/ARETURN.java ================================================ package instructions.control; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/27 * desc:返回值为 实例对象 的 return 指令 */ public class ARETURN extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Zthread thread = frame.getThread(); Zframe currentFrame = thread.popFrame(); Zframe invokerFrame = thread.getCurrentFrame(); Zobject val = currentFrame.getOperandStack().popRef(); invokerFrame.getOperandStack().pushRef(val); } } ================================================ FILE: Java/src/instructions/control/DRETURN.java ================================================ package instructions.control; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; import runtimedata.Zthread; /** * @author zachaxy * @date 17/12/27 * desc:返回值为 double 的 return 指令 */ public class DRETURN extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Zthread thread = frame.getThread(); Zframe currentFrame = thread.popFrame(); Zframe invokerFrame = thread.getCurrentFrame(); double val = currentFrame.getOperandStack().popDouble(); invokerFrame.getOperandStack().pushDouble(val); } } ================================================ FILE: Java/src/instructions/control/FRETURN.java ================================================ package instructions.control; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; import runtimedata.Zthread; /** * @author zachaxy * @date 17/12/27 * desc:返回值为 float 的 return 指令 */ public class FRETURN extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Zthread thread = frame.getThread(); Zframe currentFrame = thread.popFrame(); Zframe invokerFrame = thread.getCurrentFrame(); float val = currentFrame.getOperandStack().popFloat(); invokerFrame.getOperandStack().pushFloat(val); } } ================================================ FILE: Java/src/instructions/control/GOTO.java ================================================ package instructions.control; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class GOTO extends BranchInstruction { @Override public void execute(Zframe frame) { BranchLogic.branch(frame,offset); } } ================================================ FILE: Java/src/instructions/control/IRETURN.java ================================================ package instructions.control; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; import runtimedata.Zthread; /** * @author zachaxy * @date 17/12/27 * desc:返回值为 int 的 return 指令 * 执行方法在执行结束后,如果有返回值,其返回值会放在该方法的操作数栈 * 执行方法的外部——调用方法,需要将执行方法的返回值,压入调用方法的操作数栈 */ public class IRETURN extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Zthread thread = frame.getThread(); Zframe currentFrame = thread.popFrame(); Zframe invokerFrame = thread.getCurrentFrame(); int val = currentFrame.getOperandStack().popInt(); invokerFrame.getOperandStack().pushInt(val); } } ================================================ FILE: Java/src/instructions/control/LOOKUP_SWITCH.java ================================================ package instructions.control; import instructions.base.BranchLogic; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc:如果case值不可以编码成一个索引表(case中的数值不是连续的),则实现成lookupswitch指令 */ public class LOOKUP_SWITCH implements Instruction { int defaultOffset; int npairs; //matchOffsets有点像Map,它的key是case值,value是跳转偏移,但是并没有实现成map,而是用数组代替,两个连续的数位key-value; int[] matchOffsets; @Override public void fetchOperands(BytecodeReader reader) { reader.skipPadding(); defaultOffset = reader.readInt32(); npairs = reader.readInt32(); matchOffsets = reader.readInt32s(npairs * 2); } @Override public void execute(Zframe frame) { int key = frame.getOperandStack().popInt(); for (int i = 0; i < npairs * 2; i += 2) { if (matchOffsets[i] == key) { int offset = matchOffsets[i + 1]; BranchLogic.branch(frame, defaultOffset); return; } } BranchLogic.branch(frame, defaultOffset); } } ================================================ FILE: Java/src/instructions/control/LRETURN.java ================================================ package instructions.control; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; import runtimedata.Zthread; /** * @author zachaxy * @date 17/12/27 * desc:返回值为 long 的 return 指令 */ public class LRETURN extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Zthread thread = frame.getThread(); Zframe currentFrame = thread.popFrame(); Zframe invokerFrame = thread.getCurrentFrame(); long val = currentFrame.getOperandStack().popLong(); invokerFrame.getOperandStack().pushLong(val); } } ================================================ FILE: Java/src/instructions/control/RETURN.java ================================================ package instructions.control; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * @author zachaxy * @date 17/12/27 * return 指令;没有具体的返回值,用在 void 类型的方法中,这种方法即使不在 Java 代码中写 return 语句 * 编译器也会自动在方法的结尾添加一条 return 指令; */ public class RETURN extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getThread().popFrame(); } } ================================================ FILE: Java/src/instructions/control/TABLE_SWITCH.java ================================================ package instructions.control; import instructions.base.BranchLogic; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 如果case值可以编码成一个索引表(case中的数值是连续的),则实现成tableswitch指令 */ public class TABLE_SWITCH implements Instruction { int defaultOffset; //low和high记录case的取值范围 int low; int high; //jumpOffsets是一个索引表,里面存放high-low+1个int值,,对应各种case情况下,执行跳转所需的字节码偏移量 int[] jumpOffsets; @Override public void fetchOperands(BytecodeReader reader) { //tableswitch指令操作码的后面有0~3字节的padding,以保证 defaultOffset在字节码中的地址是4的倍数 reader.skipPadding(); defaultOffset = reader.readInt32(); low = reader.readInt32(); high = reader.readInt32(); int jumpOffsetsCount = high - low + 1; jumpOffsets = reader.readInt32s(jumpOffsetsCount); } @Override public void execute(Zframe frame) { int index = frame.getOperandStack().popInt(); int offset; if ((index >= low) && (index <= high)) { offset = jumpOffsets[index - low]; } else { offset = defaultOffset; } BranchLogic.branch(frame, offset); } } ================================================ FILE: Java/src/instructions/conversions/d2x/D2F.java ================================================ package instructions.conversions.d2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class D2F extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); double val1 = stack.popDouble(); float val2 = (float) val1; stack.pushFloat(val2); } } ================================================ FILE: Java/src/instructions/conversions/d2x/D2I.java ================================================ package instructions.conversions.d2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class D2I extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); double val1 = stack.popDouble(); int val2 = (int) val1; stack.pushInt(val2); } } ================================================ FILE: Java/src/instructions/conversions/d2x/D2L.java ================================================ package instructions.conversions.d2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class D2L extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); double val1 = stack.popDouble(); long val2 = (long) val1; stack.pushLong(val2); } } ================================================ FILE: Java/src/instructions/conversions/f2x/F2D.java ================================================ package instructions.conversions.f2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class F2D extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); float val1 = stack.popFloat(); double val2 = val1; stack.pushDouble(val2); } } ================================================ FILE: Java/src/instructions/conversions/f2x/F2I.java ================================================ package instructions.conversions.f2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class F2I extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); float val1 = stack.popFloat(); int val2 = (int) val1; stack.pushInt(val2); } } ================================================ FILE: Java/src/instructions/conversions/f2x/F2L.java ================================================ package instructions.conversions.f2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class F2L extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); float val1 = stack.popFloat(); long val2 = (long) val1; stack.pushLong(val2); } } ================================================ FILE: Java/src/instructions/conversions/i2x/I2B.java ================================================ package instructions.conversions.i2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class I2B extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val1 = stack.popInt(); byte val2 = (byte) val1; stack.pushInt(val2); } } ================================================ FILE: Java/src/instructions/conversions/i2x/I2C.java ================================================ package instructions.conversions.i2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class I2C extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val1 = stack.popInt(); char val2 = (char) val1; stack.pushInt(val2); } } ================================================ FILE: Java/src/instructions/conversions/i2x/I2D.java ================================================ package instructions.conversions.i2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class I2D extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val1 = stack.popInt(); double val2 = (double) val1; stack.pushDouble(val2); } } ================================================ FILE: Java/src/instructions/conversions/i2x/I2F.java ================================================ package instructions.conversions.i2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class I2F extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val1 = stack.popInt(); float val2 = (float) val1; stack.pushFloat(val2); } } ================================================ FILE: Java/src/instructions/conversions/i2x/I2L.java ================================================ package instructions.conversions.i2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class I2L extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val1 = stack.popInt(); long val2 = (long) val1; stack.pushLong(val2); } } ================================================ FILE: Java/src/instructions/conversions/i2x/I2S.java ================================================ package instructions.conversions.i2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class I2S extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val1 = stack.popInt(); short val2 = (short) val1; stack.pushInt(val2); } } ================================================ FILE: Java/src/instructions/conversions/l2x/L2D.java ================================================ package instructions.conversions.l2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class L2D extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val1 = stack.popLong(); double val2 = (double) val1; stack.pushDouble(val2); } } ================================================ FILE: Java/src/instructions/conversions/l2x/L2F.java ================================================ package instructions.conversions.l2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class L2F extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val1 = stack.popLong(); float val2 = (float) val1; stack.pushFloat(val2); } } ================================================ FILE: Java/src/instructions/conversions/l2x/L2I.java ================================================ package instructions.conversions.l2x; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class L2I extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val1 = stack.popLong(); int val2 = (int) val1; stack.pushInt(val2); } } ================================================ FILE: Java/src/instructions/extended/GOTO_W.java ================================================ package instructions.extended; import instructions.base.BranchLogic; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: goto_w指令和goto指令的唯一区别就是索引从2字节变成了4字节 */ public class GOTO_W implements Instruction { int offset; @Override public void fetchOperands(BytecodeReader reader) { offset = reader.readInt32(); } @Override public void execute(Zframe frame) { BranchLogic.branch(frame, offset); } } ================================================ FILE: Java/src/instructions/extended/IFNONNULL.java ================================================ package instructions.extended; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: */ public class IFNONNULL extends BranchInstruction { @Override public void execute(Zframe frame) { Zobject ref = frame.getOperandStack().popRef(); if (ref != null) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/extended/IFNULL.java ================================================ package instructions.extended; import instructions.base.BranchInstruction; import instructions.base.BranchLogic; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: */ public class IFNULL extends BranchInstruction { @Override public void execute(Zframe frame) { Zobject ref = frame.getOperandStack().popRef(); if (ref == null) { BranchLogic.branch(frame, offset); } } } ================================================ FILE: Java/src/instructions/extended/WIDE.java ================================================ package instructions.extended; import instructions.base.BytecodeReader; import instructions.base.Instruction; import instructions.loads.loaddouble.DLOAD; import instructions.loads.loadfloat.FLOAD; import instructions.loads.loadint.ILOAD; import instructions.loads.loadlong.LLOAD; import instructions.loads.loadref.ALOAD; import instructions.math.iinc.IINC; import instructions.stores.storedouble.DSTORE; import instructions.stores.storefloat.FSTORE; import instructions.stores.storeint.ISTORE; import instructions.stores.storelong.LSTORE; import instructions.stores.storeref.ASTORE; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/6 0006. * Desc: */ public class WIDE implements Instruction { Instruction modifiedInstruction; /* 先从字节码中读取一字节的操作码,然后创建子指令实例,最后读取子指令的操作数。因为没有实现ret指令,所以暂时调用 RuntimeException 函数终止程序执行。 */ @Override public void fetchOperands(BytecodeReader reader) { int opCode = reader.readUint8(); switch (opCode) { case 0x15: ILOAD iload = new ILOAD(); iload.index = reader.readUint16(); modifiedInstruction = iload; break; case 0x16: LLOAD lload = new LLOAD(); lload.index = reader.readUint16(); modifiedInstruction = lload; break; case 0x17: FLOAD fload = new FLOAD(); fload.index = reader.readUint16(); modifiedInstruction = fload; break; case 0x18: DLOAD dload = new DLOAD(); dload.index = reader.readUint16(); modifiedInstruction = dload; break; case 0x19: ALOAD aload = new ALOAD(); aload.index = reader.readUint16(); modifiedInstruction = aload; break; case 0x36: ISTORE istore = new ISTORE(); istore.index = reader.readUint16(); modifiedInstruction = istore; break; case 0x37: LSTORE lstore = new LSTORE(); lstore.index = reader.readUint16(); modifiedInstruction = lstore; break; case 0x38: FSTORE fstore = new FSTORE(); fstore.index = reader.readUint16(); modifiedInstruction = fstore; break; case 0x39: DSTORE dstore = new DSTORE(); dstore.index = reader.readUint16(); modifiedInstruction = dstore; break; case 0x3a: ASTORE astore = new ASTORE(); astore.index = reader.readUint16(); modifiedInstruction = astore; break; case 0x84: IINC iinc = new IINC(); iinc.index = reader.readUint16(); iinc.offset = reader.readInt16(); modifiedInstruction = iinc; break; case 0xa9: // ret throw new RuntimeException("Unsupported opcode: 0xa9!"); } } //wide指令只是增加了索引宽度,并不改变子指令操作,所以其Execute() 方法只要调用子指令的Execute()方法即可 @Override public void execute(Zframe frame) { modifiedInstruction.execute(frame); } } ================================================ FILE: Java/src/instructions/loads/Load.java ================================================ package instructions.loads; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 工具类,为不同的数据类型提供不同的加载机制; * 总体原则是:先从本地变量表中取出变量,然后将该变量压入到操作数栈中; */ public class Load { public static void aload(Zframe frame, int index) { Zobject ref = frame.getLocalVars().getRef(index); frame.getOperandStack().pushRef(ref); } public static void dload(Zframe frame, int index) { double val = frame.getLocalVars().getDouble(index); frame.getOperandStack().pushDouble(val); } public static void fload(Zframe frame, int index) { float val = frame.getLocalVars().getFloat(index); frame.getOperandStack().pushFloat(val); } public static void iload(Zframe frame, int index) { int val = frame.getLocalVars().getInt(index); frame.getOperandStack().pushInt(val); } public static void lload(Zframe frame, int index) { long val = frame.getLocalVars().getLong(index); frame.getOperandStack().pushLong(val); } //用在 load 数组元素时,检测数组是否为 null public static void checkNotNull(Zobject arrRef) { if (arrRef == null) { throw new NullPointerException(); } } public static void checkIndex(int count, int index) { if (index < 0 || index >= count) { throw new ArrayIndexOutOfBoundsException("index: " + index + " array's count: " + count); } } } ================================================ FILE: Java/src/instructions/loads/loaddouble/DLOAD.java ================================================ package instructions.loads.loaddouble; import instructions.base.Index8Instruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DLOAD extends Index8Instruction { @Override public void execute(Zframe frame) { Load.dload(frame,index); } } ================================================ FILE: Java/src/instructions/loads/loaddouble/DLOAD_0.java ================================================ package instructions.loads.loaddouble; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DLOAD_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.dload(frame,0); } } ================================================ FILE: Java/src/instructions/loads/loaddouble/DLOAD_1.java ================================================ package instructions.loads.loaddouble; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DLOAD_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.dload(frame,1); } } ================================================ FILE: Java/src/instructions/loads/loaddouble/DLOAD_2.java ================================================ package instructions.loads.loaddouble; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DLOAD_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.dload(frame,2); } } ================================================ FILE: Java/src/instructions/loads/loaddouble/DLOAD_3.java ================================================ package instructions.loads.loaddouble; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DLOAD_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.dload(frame, 3); } } ================================================ FILE: Java/src/instructions/loads/loadfloat/FLOAD.java ================================================ package instructions.loads.loadfloat; import instructions.base.Index8Instruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FLOAD extends Index8Instruction { @Override public void execute(Zframe frame) { Load.fload(frame,index); } } ================================================ FILE: Java/src/instructions/loads/loadfloat/FLOAD_0.java ================================================ package instructions.loads.loadfloat; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FLOAD_0 extends NoOperandsInstruction{ @Override public void execute(Zframe frame) { Load.fload(frame,0); } } ================================================ FILE: Java/src/instructions/loads/loadfloat/FLOAD_1.java ================================================ package instructions.loads.loadfloat; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FLOAD_1 extends NoOperandsInstruction{ @Override public void execute(Zframe frame) { Load.fload(frame,1); } } ================================================ FILE: Java/src/instructions/loads/loadfloat/FLOAD_2.java ================================================ package instructions.loads.loadfloat; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FLOAD_2 extends NoOperandsInstruction{ @Override public void execute(Zframe frame) { Load.fload(frame,2); } } ================================================ FILE: Java/src/instructions/loads/loadfloat/FLOAD_3.java ================================================ package instructions.loads.loadfloat; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FLOAD_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.fload(frame, 3); } } ================================================ FILE: Java/src/instructions/loads/loadint/ILOAD.java ================================================ package instructions.loads.loadint; import instructions.base.Index8Instruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ILOAD extends Index8Instruction { @Override public void execute(Zframe frame) { Load.iload(frame,index); } } ================================================ FILE: Java/src/instructions/loads/loadint/ILOAD_0.java ================================================ package instructions.loads.loadint; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ILOAD_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.iload(frame,0); } } ================================================ FILE: Java/src/instructions/loads/loadint/ILOAD_1.java ================================================ package instructions.loads.loadint; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ILOAD_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.iload(frame,1); } } ================================================ FILE: Java/src/instructions/loads/loadint/ILOAD_2.java ================================================ package instructions.loads.loadint; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ILOAD_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.iload(frame,2); } } ================================================ FILE: Java/src/instructions/loads/loadint/ILOAD_3.java ================================================ package instructions.loads.loadint; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ILOAD_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.iload(frame, 3); } } ================================================ FILE: Java/src/instructions/loads/loadlong/LLOAD.java ================================================ package instructions.loads.loadlong; import instructions.base.Index8Instruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LLOAD extends Index8Instruction { @Override public void execute(Zframe frame) { Load.lload(frame,index); } } ================================================ FILE: Java/src/instructions/loads/loadlong/LLOAD_0.java ================================================ package instructions.loads.loadlong; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LLOAD_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.lload(frame,0); } } ================================================ FILE: Java/src/instructions/loads/loadlong/LLOAD_1.java ================================================ package instructions.loads.loadlong; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LLOAD_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.lload(frame,1); } } ================================================ FILE: Java/src/instructions/loads/loadlong/LLOAD_2.java ================================================ package instructions.loads.loadlong; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LLOAD_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.lload(frame,2); } } ================================================ FILE: Java/src/instructions/loads/loadlong/LLOAD_3.java ================================================ package instructions.loads.loadlong; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LLOAD_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.lload(frame, 3); } } ================================================ FILE: Java/src/instructions/loads/loadref/ALOAD.java ================================================ package instructions.loads.loadref; import instructions.base.Index8Instruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ALOAD extends Index8Instruction{ @Override public void execute(Zframe frame) { Load.aload(frame,index); } } ================================================ FILE: Java/src/instructions/loads/loadref/ALOAD_0.java ================================================ package instructions.loads.loadref; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ALOAD_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.aload(frame,0); } } ================================================ FILE: Java/src/instructions/loads/loadref/ALOAD_1.java ================================================ package instructions.loads.loadref; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ALOAD_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.aload(frame,1); } } ================================================ FILE: Java/src/instructions/loads/loadref/ALOAD_2.java ================================================ package instructions.loads.loadref; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ALOAD_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.aload(frame,2); } } ================================================ FILE: Java/src/instructions/loads/loadref/ALOAD_3.java ================================================ package instructions.loads.loadref; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ALOAD_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Load.aload(frame,3); } } ================================================ FILE: Java/src/instructions/loads/loadxarr/AALOAD.java ================================================ package instructions.loads.loadxarr; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * 获取数组指定索引值(非基本类型):eg String s = str[2]; */ public class AALOAD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //数组元素的索引值 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Load.checkNotNull(arrRef); //得到数组对象 Zobject[] refs = arrRef.getRefs(); Load.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的值压栈 operandStack.pushRef(refs[index]); } } ================================================ FILE: Java/src/instructions/loads/loadxarr/BALOAD.java ================================================ package instructions.loads.loadxarr; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * 获取数组指定索引值:eg byte b = bytes[2]; */ public class BALOAD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //数组元素的索引值 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Load.checkNotNull(arrRef); //得到数组对象 byte[] refs = arrRef.getBytes(); Load.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的值压栈 operandStack.pushInt(refs[index]); } } ================================================ FILE: Java/src/instructions/loads/loadxarr/CALOAD.java ================================================ package instructions.loads.loadxarr; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * 获取数组指定索引值:eg char c = chars[2]; */ public class CALOAD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //数组元素的索引值 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Load.checkNotNull(arrRef); //得到数组对象 char[] refs = arrRef.getChars(); Load.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的值压栈 operandStack.pushInt(refs[index]); } } ================================================ FILE: Java/src/instructions/loads/loadxarr/DALOAD.java ================================================ package instructions.loads.loadxarr; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * 获取数组指定索引值:eg double d = doubles[2]; */ public class DALOAD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //数组元素的索引值 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Load.checkNotNull(arrRef); //得到数组对象 double[] refs = arrRef.getDoubles(); Load.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的值压栈 operandStack.pushDouble(refs[index]); } } ================================================ FILE: Java/src/instructions/loads/loadxarr/FALOAD.java ================================================ package instructions.loads.loadxarr; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * 获取数组指定索引值:eg float b = floats[2]; */ public class FALOAD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //数组元素的索引值 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Load.checkNotNull(arrRef); //得到数组对象 float[] refs = arrRef.getFloats(); Load.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的值压栈 operandStack.pushFloat(refs[index]); } } ================================================ FILE: Java/src/instructions/loads/loadxarr/IALOAD.java ================================================ package instructions.loads.loadxarr; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * 获取数组指定索引值:eg int i = ints[2]; */ public class IALOAD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //数组元素的索引值 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Load.checkNotNull(arrRef); //得到数组对象 int[] refs = arrRef.getInts(); Load.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的值压栈 operandStack.pushInt(refs[index]); } } ================================================ FILE: Java/src/instructions/loads/loadxarr/LALOAD.java ================================================ package instructions.loads.loadxarr; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * 获取数组指定索引值:eg long l = longs[2]; */ public class LALOAD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //数组元素的索引值 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Load.checkNotNull(arrRef); //得到数组对象 long[] refs = arrRef.getLongs(); Load.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的值压栈 operandStack.pushLong(refs[index]); } } ================================================ FILE: Java/src/instructions/loads/loadxarr/SALOAD.java ================================================ package instructions.loads.loadxarr; import instructions.base.NoOperandsInstruction; import instructions.loads.Load; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * 获取数组指定索引值:eg short s = shorts[2]; */ public class SALOAD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //数组元素的索引值 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Load.checkNotNull(arrRef); //得到数组对象 short[] refs = arrRef.getShorts(); Load.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的值压栈 operandStack.pushInt(refs[index]); } } ================================================ FILE: Java/src/instructions/math/add/DADD.java ================================================ package instructions.math.add; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DADD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); double val1 = stack.popDouble(); double val2 = stack.popDouble(); double res = val1 + val2; stack.pushDouble(res); } } ================================================ FILE: Java/src/instructions/math/add/FADD.java ================================================ package instructions.math.add; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FADD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); float val1 = stack.popFloat(); float val2 = stack.popFloat(); float res = val1 + val2; stack.pushFloat(res); } } ================================================ FILE: Java/src/instructions/math/add/IADD.java ================================================ package instructions.math.add; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IADD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val1 = stack.popInt(); int val2 = stack.popInt(); int res = val1 + val2; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/add/LADD.java ================================================ package instructions.math.add; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LADD extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val1 = stack.popLong(); long val2 = stack.popLong(); long res = val1 + val2; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/math/and/IAND.java ================================================ package instructions.math.and; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IAND extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); int val1 = stack.popInt(); int res = val1 & val2; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/and/LAND.java ================================================ package instructions.math.and; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LAND extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val2 = stack.popLong(); long val1 = stack.popLong(); long res = val1 & val2; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/math/div/DDIV.java ================================================ package instructions.math.div; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DDIV extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); double val2 = stack.popDouble(); double val1 = stack.popDouble(); double res = val1 / val2; stack.pushDouble(res); } } ================================================ FILE: Java/src/instructions/math/div/FDIV.java ================================================ package instructions.math.div; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FDIV extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); float val2 = stack.popFloat(); float val1 = stack.popFloat(); float res = val1 / val2; stack.pushFloat(res); } } ================================================ FILE: Java/src/instructions/math/div/IDIV.java ================================================ package instructions.math.div; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IDIV extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); int val1 = stack.popInt(); int res = val1 / val2; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/div/LDIV.java ================================================ package instructions.math.div; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LDIV extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val2 = stack.popLong(); long val1 = stack.popLong(); long res = val1 / val2; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/math/iinc/IINC.java ================================================ package instructions.math.iinc; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.LocalVars; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: iinc指令给局部变量表中的int变量增加常量值,局部变量表索引和常量值都由指令的操作数提供。 */ public class IINC implements Instruction { public int index; public int offset; @Override public void fetchOperands(BytecodeReader reader) { index = reader.readUint8(); offset = reader.readInt8(); } @Override public void execute(Zframe frame) { LocalVars localVars = frame.getLocalVars(); int val = localVars.getInt(index); val += offset; localVars.setInt(index, val); } } ================================================ FILE: Java/src/instructions/math/mul/DMUL.java ================================================ package instructions.math.mul; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DMUL extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); double val1 = stack.popDouble(); double val2 = stack.popDouble(); double res = val1 * val2; stack.pushDouble(res); } } ================================================ FILE: Java/src/instructions/math/mul/FMUL.java ================================================ package instructions.math.mul; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FMUL extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); float val1 = stack.popFloat(); float val2 = stack.popFloat(); float res = val1 * val2; stack.pushFloat(res); } } ================================================ FILE: Java/src/instructions/math/mul/IMUL.java ================================================ package instructions.math.mul; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IMUL extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val1 = stack.popInt(); int val2 = stack.popInt(); int res = val1 * val2; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/mul/LMUL.java ================================================ package instructions.math.mul; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LMUL extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val1 = stack.popLong(); long val2 = stack.popLong(); long res = val1 * val2; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/math/neg/DNEG.java ================================================ package instructions.math.neg; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DNEG extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); double val = stack.popDouble(); stack.pushDouble(-val); } } ================================================ FILE: Java/src/instructions/math/neg/FNEG.java ================================================ package instructions.math.neg; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FNEG extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); float val = stack.popFloat(); stack.pushFloat(-val); } } ================================================ FILE: Java/src/instructions/math/neg/INEG.java ================================================ package instructions.math.neg; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class INEG extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val = stack.popInt(); stack.pushInt(-val); } } ================================================ FILE: Java/src/instructions/math/neg/LNEG.java ================================================ package instructions.math.neg; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LNEG extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val = stack.popLong(); stack.pushLong(-val); } } ================================================ FILE: Java/src/instructions/math/or/IOR.java ================================================ package instructions.math.or; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IOR extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); int val1 = stack.popInt(); int res = val1 | val2; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/or/LOR.java ================================================ package instructions.math.or; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LOR extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val2 = stack.popLong(); long val1 = stack.popLong(); long res = val1 | val2; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/math/rem/DREM.java ================================================ package instructions.math.rem; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DREM extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); double val2 = stack.popDouble(); double val1 = stack.popDouble(); double res = val1 % val2; stack.pushDouble(res); } } ================================================ FILE: Java/src/instructions/math/rem/FREM.java ================================================ package instructions.math.rem; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FREM extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); float val2 = stack.popFloat(); float val1 = stack.popFloat(); float res = val1 % val2; stack.pushFloat(res); } } ================================================ FILE: Java/src/instructions/math/rem/IREM.java ================================================ package instructions.math.rem; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IREM extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); int val1 = stack.popInt(); if (val2 == 0) { throw new ArithmeticException("java.lang.ArithmeticException: / by zero"); } int res = val1 % val2; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/rem/LREM.java ================================================ package instructions.math.rem; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LREM extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val2 = stack.popLong(); if (val2 == 0) { throw new ArithmeticException("java.lang.ArithmeticException: / by zero"); } long val1 = stack.popLong(); long res = val1 % val2; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/math/sh/ISHL.java ================================================ package instructions.math.sh; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: int 左位移 * 先从操作数栈中弹出两个int变量v2和v1。v1是要进行位移操作的变量,v2指出要移位多少比特。 */ public class ISHL extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); //要移动多少bit int val1 = stack.popInt(); //要进行位移操作的变量 int s = val2 & 0x1f; //int变量只有32位,所以只取val2的后5个比特就足够表示位移位数了,位移操作符右侧必须是无符号整数,所以需要对val2进行类型转换 //但是Java中对于大数左移超出后,也会变成负数,所以这里不做额外处理了 int res = val1 << s; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/sh/ISHR.java ================================================ package instructions.math.sh; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 算术右移,需要扩展符号位,使用最高位填充移位后左侧的空位。 */ public class ISHR extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); //要移动多少bit int val1 = stack.popInt(); //要进行位移操作的变量 int s = val2 & 0x1f; int res = val1 >> s; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/sh/IUSHR.java ================================================ package instructions.math.sh; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 逻辑右移,或叫无符号右移运算符“>>>“只对位进行操作,没有算术含义,它用0填充左侧的空位。 */ public class IUSHR extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); //要移动多少bit int val1 = stack.popInt(); //要进行位移操作的变量 int s = val2 & 0x1f; int res = val1 >>> s; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/sh/LSHL.java ================================================ package instructions.math.sh; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: int 左位移 * 先从操作数栈中弹出两个int变量v2和v1。v1是要进行位移操作的变量,v2指出要移位多少比特。 */ public class LSHL extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); //要移动多少bit long val1 = stack.popLong(); //要进行位移操作的变量 int s = val2 & 0x3f; //int变量只有32位,所以只取val2的后5个比特就足够表示位移位数了,位移操作符右侧必须是无符号整数,所以需要对val2进行类型转换 //但是Java中对于大数左移超出后,也会变成负数,所以这里不做额外处理了 long res = val1 << s; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/math/sh/LSHR.java ================================================ package instructions.math.sh; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: int 左位移 * 先从操作数栈中弹出两个int变量v2和v1。v1是要进行位移操作的变量,v2指出要移位多少比特。 */ public class LSHR extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); //要移动多少bit long val1 = stack.popLong(); //要进行位移操作的变量 int s = val2 & 0x3f; //int变量只有32位,所以只取val2的后5个比特就足够表示位移位数了,位移操作符右侧必须是无符号整数,所以需要对val2进行类型转换 //但是Java中对于大数左移超出后,也会变成负数,所以这里不做额外处理了 long res = val1 >> s; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/math/sh/LUSHR.java ================================================ package instructions.math.sh; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 逻辑右移,或叫无符号右移运算符“>>>“只对位进行操作,没有算术含义,它用0填充左侧的空位。 */ public class LUSHR extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); //要移动多少bit long val1 = stack.popLong(); //要进行位移操作的变量 int s = val2 & 0x3f; //int变量只有32位,所以只取val2的后5个比特就足够表示位移位数了,位移操作符右侧必须是无符号整数,所以需要对val2进行类型转换 //但是Java中对于大数左移超出后,也会变成负数,所以这里不做额外处理了 long res = val1 >>> s; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/math/sub/DSUB.java ================================================ package instructions.math.sub; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DSUB extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); double val2 = stack.popDouble(); double val1 = stack.popDouble(); double res = val1 - val2; stack.pushDouble(res); } } ================================================ FILE: Java/src/instructions/math/sub/FSUB.java ================================================ package instructions.math.sub; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FSUB extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); float val2 = stack.popFloat(); float val1 = stack.popFloat(); float res = val1 - val2; stack.pushFloat(res); } } ================================================ FILE: Java/src/instructions/math/sub/ISUB.java ================================================ package instructions.math.sub; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ISUB extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); int val1 = stack.popInt(); int res = val1 - val2; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/sub/LSUB.java ================================================ package instructions.math.sub; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LSUB extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val2 = stack.popLong(); long val1 = stack.popLong(); long res = val1 - val2; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/math/xor/IXOR.java ================================================ package instructions.math.xor; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class IXOR extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); int val2 = stack.popInt(); int val1 = stack.popInt(); int res = val1 ^ val2; stack.pushInt(res); } } ================================================ FILE: Java/src/instructions/math/xor/LXOR.java ================================================ package instructions.math.xor; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LXOR extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); long val2 = stack.popLong(); long val1 = stack.popLong(); long res = val1 ^ val2; stack.pushLong(res); } } ================================================ FILE: Java/src/instructions/references/ANEW_ARRAY.java ================================================ package instructions.references; import instructions.base.Index16Instruction; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.ClassRef; import runtimedata.heap.RuntimeConstantPool; import runtimedata.heap.Zclass; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:创建引用类型数组,注意这里是一维的!!! * 如果创建的是 String[],那么从运行时常量池拿到 String 的符号引用,通过符号引用将 String 类加载进来 * 接下来再将 String[] 类加载进来! * 最后通过 String[] 类创建 字符串数组对象,并压入操作数栈 */ public class ANEW_ARRAY extends Index16Instruction { @Override public void execute(Zframe frame) { RuntimeConstantPool runtimeConstantPool = frame.getMethod().getClazz().getRuntimeConstantPool(); //首先获取到该数组的引用类型;eg:String [] arr = new String[2]; 那么获取到的类是:java.lang.String ClassRef classRef = (ClassRef) runtimeConstantPool.getRuntimeConstant(this.index).getValue(); //该引用类型若没加载过,那么先将该引用类型加载进来; Zclass componentClass = classRef.resolvedClass(); OperandStack operandStack = frame.getOperandStack(); int count = operandStack.popInt(); if (count < 0) { throw new NegativeArraySizeException("" + count); } //根据基础类型:java/lang/String,得到数组类[Ljava/lang/String; Zclass arrClazz = componentClass.arrayClass(); //根据数组类去创建具体的数组对象; Zobject arr = arrClazz.newArray(count); operandStack.pushRef(arr); } } ================================================ FILE: Java/src/instructions/references/ARRAY_LENGTH.java ================================================ package instructions.references; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:获取数组长度的指令 */ public class ARRAY_LENGTH extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); Zobject arrRef = operandStack.popRef(); if (arrRef == null) { throw new NullPointerException("called length on a null Object"); } int arrLen = arrRef.getArrayLen(); operandStack.pushInt(arrLen); } } ================================================ FILE: Java/src/instructions/references/ATHROW.java ================================================ package instructions.references; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.Zobject; import znative.java.lang.NStackTraceElement; /** * @author zachaxy * @date 18/1/2 */ public class ATHROW extends NoOperandsInstruction { @Override public void execute(Zframe frame) { //异常引用对象;throw new Exception(); Zobject ex = frame.getOperandStack().popRef(); if (ex == null) { throw new NullPointerException(); } //获取当前thread,是想从thread中获取所有的frame(一个frame就是一个方法调用过程的抽象) Zthread thread = frame.getThread(); if (!findAndGotoExceptionHandler(thread, ex)) { //所有的方法调用栈均不能处理该异常了,那么交由JVM来处理; handleUncaughtException(thread, ex); } } //从当前帧开始,遍历Java虚拟机栈,查找方法的异常处理表 private boolean findAndGotoExceptionHandler(Zthread thread, Zobject ex) { while (true) { Zframe frame = thread.getCurrentFrame(); //正常情况下,获取一条指令后,bytereader中的pc是要+1,指向下一条指令的地址 // 但是athrow指令比较特殊,因为现在已经抛出异常了,不能继续向下执行了,所以要回退; int pc = frame.getNextPC() - 1; //此时pc指向的是throw异常的那一行;因为接下来就要在当前方法的异常处理表中寻找可以处理当前pc指向的指令所抛出的一场了 int handlerPC = frame.getMethod().findExceptionHandler(ex.getClazz(), pc); //当前方法能处理自己抛出的异常 if (handlerPC > 0) { OperandStack operandStack = frame.getOperandStack(); operandStack.clear();//清空操作数栈 operandStack.pushRef(ex);//将抛出的异常放进去 frame.setNextPC(handlerPC);//指令跳转到对应的catch块中 return true; } //能走到这一步,说明当前方法不能处理当前方法抛出的异常,需要回到调用该方法的帧frame thread.popFrame(); //整个调用栈都无法处理异常,交由 JVM 来处理吧;JVM 处理的方法就是下面的 handleUncaughtException if (thread.isStackEmpty()) { break; } } return false; } //打印异常信息,包括调用栈的链;同时,此时虚拟机栈都已经清空了,所以整个JVM也就终止了; private void handleUncaughtException(Zthread thread, Zobject ex) { //其实能执行到这一步表明方法栈已经被清空了; thread.clearStack(); NStackTraceElement[] stet = (NStackTraceElement[]) ex.extra; for (int i = 0; i < stet.length; i++) { System.out.println(stet[i]); } } } ================================================ FILE: Java/src/instructions/references/CHECK_CAST.java ================================================ package instructions.references; import instructions.base.Index16Instruction; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.ClassRef; import runtimedata.heap.RuntimeConstantPool; import runtimedata.heap.Zclass; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/26 * desc:类型转换,该指令和instanceof指令的区别在于,instanceof判断后将结果压入操作数栈,而cast直接抛出异常 * String str = (String)obj * NOTE:checkcast 指令,在pop到引用 obj 之后,又将 obj push 到栈中!!! */ public class CHECK_CAST extends Index16Instruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); Zobject obj = stack.popRef(); stack.pushRef(obj); //如果 obj 为 null,则可以转换为任意类型 if (obj == null) { return; } RuntimeConstantPool runtimeConstantPool = frame.getMethod().getClazz().getRuntimeConstantPool(); ClassRef classRef = (ClassRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); Zclass clazz = classRef.resolvedClass(); if (!obj.isInstanceOf(clazz)) { throw new ClassCastException(obj.getClazz().thisClassName + " can't cast to " + clazz.thisClassName); } } } ================================================ FILE: Java/src/instructions/references/GET_FIELD.java ================================================ package instructions.references; import instructions.base.Index16Instruction; import runtimedata.OperandStack; import runtimedata.Slots; import runtimedata.Zframe; import runtimedata.heap.*; /** * Author: zhangxin * Time: 2017/7/27. * Desc: 从实例变量中获取值,并将之放在当前操作数栈 */ public class GET_FIELD extends Index16Instruction { @Override public void execute(Zframe frame) { Zmethod currentMethod = frame.getMethod(); Zclass currentClass = currentMethod.getClazz(); RuntimeConstantPool runtimeConstantPool = currentClass.getRuntimeConstantPool(); //获取到字段的符号引用 FieldRef fieldRef = (FieldRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); //将字段符号引用转换为直接引用 Zfield field = fieldRef.resolvedField(); if (field.isStatic()) { throw new IncompatibleClassChangeError("should not call a static field by an instance"); } String descriptor = field.getDescriptor(); int slotId = field.getSlotId(); OperandStack stack = frame.getOperandStack(); //获取字段所在的实例 Zobject instance = stack.popRef(); if (instance == null) { throw new NullPointerException("call " + field.getName() + " on a null object"); } Slots slots = instance.getFields(); switch (descriptor.charAt(0)) { case 'Z': case 'B': case 'C': case 'S': case 'I': stack.pushInt(slots.getInt(slotId)); break; case 'F': stack.pushFloat(slots.getFloat(slotId)); break; case 'J': stack.pushLong(slots.getLong(slotId)); break; case 'D': stack.pushDouble(slots.getDouble(slotId)); break; case 'L': case '[': stack.pushRef(slots.getRef(slotId)); break; default: break; } } } ================================================ FILE: Java/src/instructions/references/GET_STATIC.java ================================================ package instructions.references; import instructions.base.ClassInitLogic; import instructions.base.Index16Instruction; import runtimedata.OperandStack; import runtimedata.Slots; import runtimedata.Zframe; import runtimedata.heap.*; /** * Author: zhangxin * Time: 2017/7/26. * Desc:获取静态变量的值,将其值放在操作数栈中 */ public class GET_STATIC extends Index16Instruction { @Override public void execute(Zframe frame) { Zmethod currentMethod = frame.getMethod(); Zclass currentClass = currentMethod.getClazz(); RuntimeConstantPool runtimeConstantPool = currentClass.getRuntimeConstantPool(); FieldRef fieldRef = (FieldRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); Zfield field = fieldRef.resolvedField(); Zclass clazz = field.getClazz(); //判断其Class是否已经加载过,如果还未加载,那么调用其类的方法压栈 if (!clazz.isInitStarted()) { //当前指令已经是在执行new了,但是类还没有加载,所以当前帧先回退,让类初始化的帧入栈,等类初始化完成后,重新执行new; frame.revertNextPC(); ClassInitLogic.initClass(frame.getThread(), clazz); return; } if (!field.isStatic()) { throw new IncompatibleClassChangeError("can't access unstatic field: " + field.getName()); } String descriptor = field.getDescriptor(); int slotId = field.getSlotId(); Slots slots = clazz.getStaticVars(); OperandStack stack = frame.getOperandStack(); switch (descriptor.charAt(0)) { case 'Z': case 'B': case 'C': case 'S': case 'I': stack.pushInt(slots.getInt(slotId)); break; case 'F': stack.pushFloat(slots.getFloat(slotId)); break; case 'J': stack.pushLong(slots.getLong(slotId)); break; case 'D': stack.pushDouble(slots.getDouble(slotId)); break; case 'L': case '[': stack.pushRef(slots.getRef(slotId)); break; default: break; } } } ================================================ FILE: Java/src/instructions/references/INSTANCE_OF.java ================================================ package instructions.references; import instructions.base.Index16Instruction; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.ClassRef; import runtimedata.heap.RuntimeConstantPool; import runtimedata.heap.Zclass; import runtimedata.heap.Zobject; /** * Author: zhangxin * Time: 2017/7/26. * Desc: java 中的 instanceof 关键字,会被解析成 INSTANCE_OF 指令 eg:(obj instanceof Object) * 将判断的结果写入操作数栈 */ public class INSTANCE_OF extends Index16Instruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); Zobject obj = stack.popRef(); //如果 obj 为 null,对任何 class 类型的判断都是 false; if (obj == null) { stack.pushInt(0); return; } RuntimeConstantPool runtimeConstantPool = frame.getMethod().getClazz().getRuntimeConstantPool(); ClassRef classRef = (ClassRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); Zclass clazz = classRef.resolvedClass(); //obj是不是class的实例 if (obj.isInstanceOf(clazz)) { stack.pushInt(1); } else { stack.pushInt(0); } } } ================================================ FILE: Java/src/instructions/references/INVOKE_INTERFACE.java ================================================ package instructions.references; import instructions.base.BytecodeReader; import instructions.base.Index16Instruction; import instructions.base.MethodInvokeLogic; import runtimedata.Zframe; import runtimedata.heap.*; /** * @author zachaxy * @date 17/12/27 * desc:调用接口方法,与其它三个调用指令不同的是,其后面跟4字节,这里继承了 index16 的父类,但是要重写获取操作数的方法 */ public class INVOKE_INTERFACE extends Index16Instruction { @Override public void fetchOperands(BytecodeReader reader) { super.fetchOperands(reader); reader.readUint8();//第三个字节是接口方法的参数数量,其实可以像实例方法那样计算出来,但是历史原因保留了下来 reader.readUint8();//第四个字节必须为0 } @Override public void execute(Zframe frame) { //调用该方法所在的类 Zclass currentClass = frame.getMethod().getClazz(); RuntimeConstantPool runtimeConstantPool = currentClass.getRuntimeConstantPool(); //通过index,拿到方法符号引用 InterfaceMethodRef methodRef = (InterfaceMethodRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); Zmethod resolvedMethod = methodRef.resolvedInterfaceMethod(); if (resolvedMethod.isStatic() || resolvedMethod.isPrivate()) { throw new IncompatibleClassChangeError(resolvedMethod.getName()); } //接口方法核心在于确定一个实现了该接口的实例 Zobject ref = frame.getOperandStack().getRefFromTop(resolvedMethod.getArgSlotCount() - 1); if (ref == null) { throw new NullPointerException("called " + resolvedMethod.getName() + " on a null reference!"); } //验证该实例是否确实实现了对应的接口 if (!ref.getClazz().isImplements(methodRef.resolvedClass())) { throw new IncompatibleClassChangeError(ref.getClazz().thisClassName + " doesn't implements " + methodRef.resolvedClass().thisClassName); } Zmethod methodToBeInvoked = MethodLookup.lookupMethodInClass(ref.getClazz(), methodRef.getName(), methodRef.getDescriptor()); if (methodToBeInvoked == null || methodToBeInvoked.isAbstract()) { throw new AbstractMethodError(methodToBeInvoked.getName()); } if (!methodToBeInvoked.isPublic()) { throw new IllegalAccessError(methodToBeInvoked.getName() + " is not public"); } MethodInvokeLogic.invokeMethod(frame, methodToBeInvoked); } } ================================================ FILE: Java/src/instructions/references/INVOKE_NATIVE.java ================================================ package instructions.references; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; import runtimedata.heap.Zmethod; import znative.NativeMethod; import znative.RegisterCenter; /** * @author zachaxy * @date 18/1/2 * desc:nativie 方法执行的指令 */ public class INVOKE_NATIVE extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Zmethod method = frame.getMethod(); String clazzName = method.getClazz().thisClassName; String methodName = method.getName(); String descriptor = method.getDescriptor(); NativeMethod nativeMethod = RegisterCenter.findNativeMethod(clazzName, methodName, descriptor); if (nativeMethod == null) { String methodInfo = clazzName + "." + methodName + descriptor; throw new UnsatisfiedLinkError(methodInfo); } nativeMethod.run(frame); } } ================================================ FILE: Java/src/instructions/references/INVOKE_SPECIAL.java ================================================ package instructions.references; import instructions.base.Index16Instruction; import instructions.base.MethodInvokeLogic; import runtimedata.Zframe; import runtimedata.heap.*; /** * @author zachaxy * @date 17/12/26 * desc:调用无须动态绑定的实例方法(包括:构造函数,私有方法,通过super关键字调用的超类方法) * JVM特意为这种不需要动态绑定的方法创建的invokespecial,目的是为了加快方法调用(解析)的速度 */ public class INVOKE_SPECIAL extends Index16Instruction { @Override public void execute(Zframe frame) { //调用该方法所在的类 Zclass currentClass = frame.getMethod().getClazz(); RuntimeConstantPool runtimeConstantPool = currentClass.getRuntimeConstantPool(); //通过index,拿到方法符号引用 MethodRef methodRef = (MethodRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); //和静态方法不同的是,要先加载方法所在的类 Zclass resolvedClass = methodRef.resolvedClass(); //将方法引用转换为方法 Zmethod resolvedMethod = methodRef.resolvedMethod(); //方法必须在其对应的类进行声明,这里必须要验证类是否匹配 if ("".equals(resolvedMethod.getName()) && resolvedMethod.getClazz() != resolvedClass) { throw new NoSuchMethodError(resolvedMethod.getName()); } if (resolvedMethod.isStatic()) { throw new IncompatibleClassChangeError(resolvedMethod.getName() + " in unstatic context"); } //从操作数栈中获取调用该非静态方法的引用;参数的传递是从当前frame的操作数栈中根据参数个数,完整的拷贝到调用frame的本地变量表中; Zobject ref = frame.getOperandStack().getRefFromTop(resolvedMethod.getArgSlotCount() - 1); if (ref == null) { throw new NullPointerException("called " + resolvedMethod.getName() + " on a null reference!"); } //验证protected的方法的调用权限 if (resolvedMethod.isProtected() && resolvedMethod.getClazz().isSuperClassOf(currentClass) && !resolvedMethod.getClazz().getPackageName().equals(currentClass.getPackageName()) && ref.getClazz() != currentClass && !ref.getClazz().isSubClassOf(currentClass)) { throw new IllegalAccessError(); } Zmethod methodToBeInvoked = resolvedMethod; //首先 ACC_SUPER:在jdk1.02之后编译出来的类,该标志均为真; //解决 super.func()的形式;但是不能是方法;因为父类中可能定义了func方法,同时子类又覆盖了父类的func, //那么解析func的符号引用时首先能在子类中解析到,但此时显示的调用了父类的func方法,所以还需要在父类中去解析; if (currentClass.isSuper() && resolvedClass.isSuperClassOf(currentClass) && !"".equals(resolvedMethod.getName())) { methodToBeInvoked = MethodLookup.lookupMethodInClass(currentClass.getSuperClass(), methodRef.getName(), methodRef.getDescriptor()); } if (methodToBeInvoked == null || methodToBeInvoked.isAbstract()) { throw new AbstractMethodError(methodToBeInvoked.getName()); } MethodInvokeLogic.invokeMethod(frame, methodToBeInvoked); } } ================================================ FILE: Java/src/instructions/references/INVOKE_STATIC.java ================================================ package instructions.references; import instructions.base.ClassInitLogic; import instructions.base.Index16Instruction; import instructions.base.MethodInvokeLogic; import runtimedata.Zframe; import runtimedata.heap.MethodRef; import runtimedata.heap.RuntimeConstantPool; import runtimedata.heap.Zclass; import runtimedata.heap.Zmethod; /** * @author zachaxy * @date 17/12/27 * desc:静态方法调用指令 * 静态方法,在调用阶段即可确定是哪个方法 */ public class INVOKE_STATIC extends Index16Instruction { @Override public void execute(Zframe frame) { RuntimeConstantPool runtimeConstantPool = frame.getMethod().getClazz().getRuntimeConstantPool(); //通过index,拿到方法符号引用 MethodRef methodRef = (MethodRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); Zmethod resolvedMethod = methodRef.resolvedMethod(); if (!resolvedMethod.isStatic()) { throw new IncompatibleClassChangeError(); } Zclass clazz = resolvedMethod.getClazz(); //判断其Class是否已经加载过,如果还未加载,那么调用其类的方法压栈 if (!clazz.isInitStarted()) { //当前指令已经是在执行new了,但是类还没有加载,所以当前帧先回退,让类初始化的帧入栈,等类初始化完成后,重新执行new; frame.revertNextPC(); ClassInitLogic.initClass(frame.getThread(), clazz); return; } MethodInvokeLogic.invokeMethod(frame, resolvedMethod); } } ================================================ FILE: Java/src/instructions/references/INVOKE_VIRTUAL.java ================================================ package instructions.references; import instructions.base.Index16Instruction; import instructions.base.MethodInvokeLogic; import runtimedata.Zframe; import runtimedata.heap.*; /** * @author zachaxy * @date 17/12/26 * desc:调用虚方法,一般用在多态; */ public class INVOKE_VIRTUAL extends Index16Instruction { @Override public void execute(Zframe frame) { //调用该方法所在的类 Zclass currentClass = frame.getMethod().getClazz(); RuntimeConstantPool runtimeConstantPool = currentClass.getRuntimeConstantPool(); //通过index,拿到方法符号引用,虚方法(用到了多态),这个方法引用指向的其实是父类的 MethodRef methodRef = (MethodRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); //将方法引用转换为方法 //这一步拿到解析后的resolvedMethod主要是用来做下面权限的验证; //而真正的resolvedMethod是在下面拿到真正的调用者,再次解析到的methodToBeInvoked Zmethod resolvedMethod = methodRef.resolvedMethod(); if (resolvedMethod.isStatic()) { throw new IncompatibleClassChangeError(resolvedMethod.getName() + " in unstatic context"); } //从操作数栈中获取调用该非静态方法的引用;参数的传递是从当前frame的操作数栈中根据参数个数,完整的拷贝到调用frame的本地变量表中; Zobject ref = frame.getOperandStack().getRefFromTop(resolvedMethod.getArgSlotCount() - 1); if (ref == null) { throw new NullPointerException("called " + resolvedMethod.getName() + " on a null reference!"); } //验证protected的方法的调用权限 if (resolvedMethod.isProtected() && resolvedMethod.getClazz().isSuperClassOf(currentClass) && !resolvedMethod.getClazz().getPackageName().equals(currentClass.getPackageName()) && ref.getClazz() != currentClass && !ref.getClazz().isSubClassOf(currentClass)) { if (!(ref.getClazz().isArray() && "clone".equals(resolvedMethod.getName()))) { throw new IllegalAccessError(resolvedMethod.getName() + "called in " + ref.getClazz().thisClassName); } } //相对于invokespecial,本指令还多了这一步,因为ref才是真正的调用者 //而这次解析到的才是真正的method,这是多态的核心! Zmethod methodToBeInvoked = MethodLookup.lookupMethodInClass(ref.getClazz(), methodRef.getName(), methodRef.getDescriptor()); if (methodToBeInvoked == null || methodToBeInvoked.isAbstract()) { throw new AbstractMethodError(methodToBeInvoked.getName()); } MethodInvokeLogic.invokeMethod(frame, methodToBeInvoked); } } ================================================ FILE: Java/src/instructions/references/MULTI_ANEW_ARRAY.java ================================================ package instructions.references; import instructions.base.BytecodeReader; import instructions.base.Index16Instruction; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.ClassRef; import runtimedata.heap.RuntimeConstantPool; import runtimedata.heap.Zclass; import runtimedata.heap.Zobject; import java.util.LinkedList; /** * @author zachaxy * @date 17/12/30 * desc:创建多维数组:基础类型+引用类型的都是这个指令; * 这里以 int[][][] arr = new int[3][4][5] 为例 * 其产生的字节码为: * iconst_3 * iconst_4 * iconst_5 * multianewarray #5 ([[[I,3) *

* 首先将三维数组各个维度压入操作数栈,栈顶向下一次为: 5,4,3 * multianewarray指令 获取两个操作数,第一个 index 表示运行时常量池的类符号引用,其类名为[[[I * 接着获取第二个操作数3,表明这是一个三维数组 *

* multianewarray指令的执行:首先将获取到的类符号引用转为直接引用:转换依然是用 classloader,因为是数组类, * 所以不用从 class 文件中读取字节流,而是直接创建一个 class,该 class 只需将类名指定为 [[[I,即可。 * 接下来依次从操作数栈中弹出三个整数,表示该多维数组每一维的大小;然后开始创建该多维数组的对象 *

* 多维数组对象的创建过程:此时拿到的类名是:[[[I,各个维的大小是3,4,5; * 首先利用数组类[[[I,创建第一维 arr1 ,大小为3,(多维数组对外表现的就是一维数组,只不过该数组中的元素依然是数组。) * 接下来创建 arr1 中的每一个元素,其元素也是数组,我们称之为第2维,arr2(arr1中的三个元素都是 arr2) * arr2 此时的类型为 [[I,依然需要用 classloader 进行加载,然后创建; * 接下来创建 arr2 中的每一个元素,其元素还是数组,我们称之为第3维,arr3(arr2中的三个元素都是 arr3) * arr3 此时的类型为 [I,依然需要用classloader 进行加载,然后创建; * 最终将创建好的 arr1,压入操作数栈,结束! *

*

* 当counts==2的时候,即if len(counts)>1,在if方法体内,调用了newMultiDimensionalArray方法,但是传入的counts是1, * 而在newMultiDimensionalArray方法刚一开始的时候,就创建了一维数组; * newMultiDimensionalArray方法没有问题;就是看着有点绕; */ public class MULTI_ANEW_ARRAY extends Index16Instruction { //数组的纬度 private int dimensions; @Override public void fetchOperands(BytecodeReader reader) { super.fetchOperands(reader); dimensions = reader.readUint8(); } @Override public void execute(Zframe frame) { RuntimeConstantPool runtimeConstantPool = frame.getMethod().getClazz().getRuntimeConstantPool(); //多维数组的类符号引用 ClassRef classRef = (ClassRef) runtimeConstantPool.getRuntimeConstant(this.index).getValue(); //解析该数组引用,就能得到该多维数组的类 Zclass arrClazz = classRef.resolvedClass(); OperandStack operandStack = frame.getOperandStack(); //各个维的大小; LinkedList list = popAndCheckCounts(operandStack, dimensions); Zobject arr = newMultiDimensionalArray(list, arrClazz); operandStack.pushRef(arr); } //从操作数栈中弹出dimensions个整数,分别表示各个维度的大小 private LinkedList popAndCheckCounts(OperandStack operandStack, int dimensions) { LinkedList list = new LinkedList<>(); for (int i = dimensions - 1; i >= 0; i--) { int count = operandStack.popInt(); if (count < 0) { throw new NegativeArraySizeException(count + " for " + i + "th"); } list.add(count); } return list; } //创建多维数组 private Zobject newMultiDimensionalArray(LinkedList list, Zclass arrClazz) { int count = list.peek(); //首先创建第一纬(行);后面几纬整体作为一个类相继往直前的数组中填充; arrClass只是类名,可以创建其一维数组 Zobject arrObj = arrClazz.newArray(count); if (list.size() > 1) { Zobject[] refs = arrObj.getRefs(); list.poll(); for (int i = 0; i < refs.length; i++) { //在创建新的数组,传入的 class 是上面一层 class 的名称,退去了一层 [ refs[i] = newMultiDimensionalArray(list, arrClazz.getComponentClass()); } } return arrObj; } } ================================================ FILE: Java/src/instructions/references/NEW.java ================================================ package instructions.references; import instructions.base.ClassInitLogic; import instructions.base.Index16Instruction; import runtimedata.Zframe; import runtimedata.heap.ClassRef; import runtimedata.heap.RuntimeConstantPool; import runtimedata.heap.Zclass; import runtimedata.heap.Zobject; /** * Author: zhangxin * Time: 2017/7/24. * Desc: uint16的索引,来自字节码,通过该索引,从当前类的运行时常量池中找到类符号引用; * 解析该类符号引用,可以拿到类数据,然后创建对象,并把对象引用压入操作数栈; */ public class NEW extends Index16Instruction { @Override public void execute(Zframe frame) { RuntimeConstantPool runtimeConstantPool = frame.getMethod().getClazz().getRuntimeConstantPool(); ClassRef classRef = (ClassRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); Zclass clazz = classRef.resolvedClass(); //判断其Class是否已经加载过,如果还未加载,那么调用其类的方法压栈 if (!clazz.isInitStarted()) { //当前指令已经是在执行new了,但是类还没有加载,所以当前帧先回退,让类初始化的帧入栈,等类初始化完成后,重新执行new; frame.revertNextPC(); ClassInitLogic.initClass(frame.getThread(), clazz); return; } if(clazz.isInterface() || clazz.isAbstract()){ throw new InstantiationError(clazz.thisClassName + " can't new"); } Zobject ref = clazz.newObject(); frame.getOperandStack().pushRef(ref); } } ================================================ FILE: Java/src/instructions/references/NEW_ARRAY.java ================================================ package instructions.references; import instructions.base.Index8Instruction; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zclass; import runtimedata.heap.ZclassLoader; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:创建基本类型的数组的指令,一维的! */ public class NEW_ARRAY extends Index8Instruction { //Array Type atype private final int AT_BOOLEAN = 4; private final int AT_CHAR = 5; private final int AT_FLOAT = 6; private final int AT_DOUBLE = 7; private final int AT_BYTE = 8; private final int AT_SHORT = 9; private final int AT_INT = 10; private final int AT_LONG = 11; @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //从栈中获取数组的大小 int count = operandStack.popInt(); if (count < 0) { throw new NegativeArraySizeException("" + count); } ZclassLoader loader = frame.getMethod().getClazz().getLoader(); Zclass arrClazz = getPrimitiveArrayClass(loader); Zobject arr = arrClazz.newArray(count); operandStack.pushRef(arr); } //获取基本类型数组的class;如果没有加载过,需要加载进JVM private Zclass getPrimitiveArrayClass(ZclassLoader loader) { //从字节码中获取到的 index 表明的是哪种类型的数组 switch (this.index) { case AT_BOOLEAN: return loader.loadClass("[Z"); case AT_BYTE: return loader.loadClass("[B"); case AT_CHAR: return loader.loadClass("[C"); case AT_SHORT: return loader.loadClass("[S"); case AT_INT: return loader.loadClass("[I"); case AT_LONG: return loader.loadClass("[J"); case AT_FLOAT: return loader.loadClass("[F"); case AT_DOUBLE: return loader.loadClass("[D"); default: throw new RuntimeException("Invalid atype!"); } } } ================================================ FILE: Java/src/instructions/references/PUT_FIELD.java ================================================ package instructions.references; import instructions.base.Index16Instruction; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.*; /** * Author: zhangxin * Time: 2017/7/27. * Desc: 给实例变量赋值,所赋的值保存在操作数栈中; * 和静态变量赋值不同的是:静态变量在class中,而实例变量在每一个对象中,该对象也在当前操作数栈; */ public class PUT_FIELD extends Index16Instruction { @Override public void execute(Zframe frame) { Zmethod currentMethod = frame.getMethod(); Zclass currentClass = currentMethod.getClazz(); RuntimeConstantPool runtimeConstantPool = currentClass.getRuntimeConstantPool(); //首先获取到fieldRef引用; FieldRef fieldRef = (FieldRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); //根据引用获取到字段; Zfield field = fieldRef.resolvedField(); Zclass clazz = field.getClazz(); //NOTE:其实是可以通过实例访问类静态变量的,但这样无谓的增加了编译器解析的成本,因此这里直接抛出异常 if (field.isStatic()) { throw new IncompatibleClassChangeError("should not call a static field by an instance"); } if (field.isFinal()) { if (currentClass != clazz || "".equals(currentMethod.getName())) { throw new IllegalAccessError(field.getName()+" can't be assigned out of instance"); } } String descriptor = field.getDescriptor(); int slotId = field.getSlotId(); OperandStack stack = frame.getOperandStack(); Zobject instance; switch (descriptor.charAt(0)) { case 'Z': case 'B': case 'C': case 'S': case 'I': { int val = stack.popInt(); instance = stack.popRef(); if (instance == null) { throw new NullPointerException("call "+field.getName()+" on a null object"); } instance.getFields().setInt(slotId, val); break; } case 'F': { float val = stack.popFloat(); instance = stack.popRef(); if (instance == null) { throw new NullPointerException("call "+field.getName()+" on a null object"); } instance.getFields().setFloat(slotId, val); break; } case 'J': { long val = stack.popLong(); instance = stack.popRef(); if (instance == null) { throw new NullPointerException("call "+field.getName()+" on a null object"); } instance.getFields().setLong(slotId, val); break; } case 'D': { double val = stack.popDouble(); instance = stack.popRef(); if (instance == null) { throw new NullPointerException("call "+field.getName()+" on a null object"); } instance.getFields().setDouble(slotId, val); break; } case 'L': case '[': { Zobject val = stack.popRef(); instance = stack.popRef(); if (instance == null) { throw new NullPointerException("call "+field.getName()+" on a null object"); } instance.getFields().setRef(slotId, val); break; } default: break; } } } ================================================ FILE: Java/src/instructions/references/PUT_STATIC.java ================================================ package instructions.references; import instructions.base.ClassInitLogic; import instructions.base.Index16Instruction; import runtimedata.OperandStack; import runtimedata.Slots; import runtimedata.Zframe; import runtimedata.heap.*; /** * Author: zhangxin * Time: 2017/7/26. * Desc: 为静态变量赋值,所赋的值在操作数栈中 */ public class PUT_STATIC extends Index16Instruction { @Override public void execute(Zframe frame) { Zmethod currentMethod = frame.getMethod(); Zclass currentClass = currentMethod.getClazz(); RuntimeConstantPool runtimeConstantPool = currentClass.getRuntimeConstantPool(); FieldRef fieldRef = (FieldRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); Zfield field = fieldRef.resolvedField(); Zclass clazz = field.getClazz(); //判断其Class是否已经加载过,如果还未加载,那么调用其类的方法压栈 if (!clazz.isInitStarted()) { //当前指令已经是在执行new了,但是类还没有加载,所以当前帧先回退,让类初始化的帧入栈,等类初始化完成后,重新执行new; frame.revertNextPC(); ClassInitLogic.initClass(frame.getThread(), clazz); return; } if (!field.isStatic()) { throw new IncompatibleClassChangeError("can't access unstatic field: " + field.getName()); } if (field.isFinal()) { if (currentClass != clazz || !"".equals(currentMethod.getName())) { throw new IllegalAccessError("java.lang.IllegalAccessError"); } } String descriptor = field.getDescriptor(); int slotId = field.getSlotId(); Slots slots = clazz.getStaticVars(); OperandStack stack = frame.getOperandStack(); switch (descriptor.charAt(0)) { case 'Z': case 'B': case 'C': case 'S': case 'I': slots.setInt(slotId, stack.popInt()); break; case 'F': slots.setFloat(slotId, stack.popFloat()); break; case 'J': slots.setLong(slotId, stack.popLong()); break; case 'D': slots.setDouble(slotId, stack.popDouble()); case 'L': case '[': slots.setRef(slotId, stack.popRef()); break; default: break; } } } ================================================ FILE: Java/src/instructions/stack/dup/DUP.java ================================================ package instructions.stack.dup; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Slot; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: DUP指令复制栈顶的单个变量 */ public class DUP extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); Slot slot = stack.popSlot(); stack.pushSlot(slot); stack.pushSlot(slot); } } ================================================ FILE: Java/src/instructions/stack/dup/DUP2.java ================================================ package instructions.stack.dup; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Slot; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: b a => b a b a; */ public class DUP2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); Slot slot1 = stack.popSlot(); Slot slot2 = stack.popSlot(); stack.pushSlot(slot2); stack.pushSlot(slot1); stack.pushSlot(slot2); stack.pushSlot(slot1); } } ================================================ FILE: Java/src/instructions/stack/dup/DUP2_X1.java ================================================ package instructions.stack.dup; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Slot; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DUP2_X1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); Slot slot1 = stack.popSlot(); Slot slot2 = stack.popSlot(); Slot slot3 = stack.popSlot(); stack.pushSlot(slot2); stack.pushSlot(slot1); stack.pushSlot(slot3); stack.pushSlot(slot2); stack.pushSlot(slot1); } } ================================================ FILE: Java/src/instructions/stack/dup/DUP2_X2.java ================================================ package instructions.stack.dup; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Slot; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DUP2_X2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); Slot slot1 = stack.popSlot(); Slot slot2 = stack.popSlot(); Slot slot3 = stack.popSlot(); Slot slot4 = stack.popSlot(); stack.pushSlot(slot2); stack.pushSlot(slot1); stack.pushSlot(slot4); stack.pushSlot(slot3); stack.pushSlot(slot2); stack.pushSlot(slot1); } } ================================================ FILE: Java/src/instructions/stack/dup/DUP_X1.java ================================================ package instructions.stack.dup; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Slot; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: DUP_X1 指令 先将栈顶的两个变量交换,然后再将原栈顶元素添加到栈顶 ab => bab; */ public class DUP_X1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); Slot slot1 = stack.popSlot(); Slot slot2 = stack.popSlot(); stack.pushSlot(slot1); stack.pushSlot(slot2); stack.pushSlot(slot1); } } ================================================ FILE: Java/src/instructions/stack/dup/DUP_X2.java ================================================ package instructions.stack.dup; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Slot; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 3 2 1 => 1 3 2 1; */ public class DUP_X2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); Slot slot1 = stack.popSlot(); Slot slot2 = stack.popSlot(); Slot slot3 = stack.popSlot(); stack.pushSlot(slot1); stack.pushSlot(slot3); stack.pushSlot(slot2); stack.pushSlot(slot1); } } ================================================ FILE: Java/src/instructions/stack/pop/POP.java ================================================ package instructions.stack.pop; import instructions.base.NoOperandsInstruction; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: pop指令把栈顶变量弹出 * 只能用于弹出int、float等占用一个操作数栈位置的变量 */ public class POP extends NoOperandsInstruction { @Override public void execute(Zframe frame) { frame.getOperandStack().popSlot(); } } ================================================ FILE: Java/src/instructions/stack/pop/POP2.java ================================================ package instructions.stack.pop; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: double和long变量在操作数栈中占据两个位置,需要使用pop2指令弹出 */ public class POP2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); stack.popSlot(); stack.popSlot(); } } ================================================ FILE: Java/src/instructions/stack/swap/SWAP.java ================================================ package instructions.stack.swap; import instructions.base.NoOperandsInstruction; import runtimedata.OperandStack; import runtimedata.Slot; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: swap指令交换栈顶的两个变量 */ public class SWAP extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack stack = frame.getOperandStack(); Slot slot1 = stack.popSlot(); Slot slot2 = stack.popSlot(); stack.pushSlot(slot1); stack.pushSlot(slot2); } } ================================================ FILE: Java/src/instructions/stores/Store.java ================================================ package instructions.stores; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: 存储指令工具类,针对引用,int,long,double,float五种类型; */ public class Store { public static void astore(Zframe frame, int index) { Zobject ref = frame.getOperandStack().popRef(); frame.getLocalVars().setRef(index, ref); } public static void istore(Zframe frame, int index) { int val = frame.getOperandStack().popInt(); frame.getLocalVars().setInt(index, val); } public static void lstore(Zframe frame, int index) { long val = frame.getOperandStack().popLong(); frame.getLocalVars().setLong(index, val); } public static void fstore(Zframe frame, int index) { float val = frame.getOperandStack().popFloat(); frame.getLocalVars().setFloat(index, val); } public static void dstote(Zframe frame, int index) { double val = frame.getOperandStack().popDouble(); frame.getLocalVars().setDouble(index, val); } //用在 store 数组元素时,检测数组是否为 null public static void checkNotNull(Zobject arrRef) { if (arrRef == null) { throw new NullPointerException(); } } public static void checkIndex(int count, int index) { if (index < 0 || index >= count) { throw new ArrayIndexOutOfBoundsException("index: " + index + " array's count: " + count); } } } ================================================ FILE: Java/src/instructions/stores/storedouble/DSTORE.java ================================================ package instructions.stores.storedouble; import instructions.base.Index8Instruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DSTORE extends Index8Instruction { @Override public void execute(Zframe frame) { Store.dstote(frame,index); } } ================================================ FILE: Java/src/instructions/stores/storedouble/DSTORE_0.java ================================================ package instructions.stores.storedouble; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DSTORE_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.dstote(frame,0); } } ================================================ FILE: Java/src/instructions/stores/storedouble/DSTORE_1.java ================================================ package instructions.stores.storedouble; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DSTORE_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.dstote(frame,1); } } ================================================ FILE: Java/src/instructions/stores/storedouble/DSTORE_2.java ================================================ package instructions.stores.storedouble; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DSTORE_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.dstote(frame,2); } } ================================================ FILE: Java/src/instructions/stores/storedouble/DSTORE_3.java ================================================ package instructions.stores.storedouble; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class DSTORE_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.dstote(frame,3); } } ================================================ FILE: Java/src/instructions/stores/storefloat/FSTORE.java ================================================ package instructions.stores.storefloat; import instructions.base.Index8Instruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FSTORE extends Index8Instruction { @Override public void execute(Zframe frame) { Store.fstore(frame,index); } } ================================================ FILE: Java/src/instructions/stores/storefloat/FSTORE_0.java ================================================ package instructions.stores.storefloat; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FSTORE_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.fstore(frame,0); } } ================================================ FILE: Java/src/instructions/stores/storefloat/FSTORE_1.java ================================================ package instructions.stores.storefloat; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FSTORE_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.fstore(frame,1); } } ================================================ FILE: Java/src/instructions/stores/storefloat/FSTORE_2.java ================================================ package instructions.stores.storefloat; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FSTORE_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.fstore(frame,2); } } ================================================ FILE: Java/src/instructions/stores/storefloat/FSTORE_3.java ================================================ package instructions.stores.storefloat; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class FSTORE_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.fstore(frame,3); } } ================================================ FILE: Java/src/instructions/stores/storeint/ISTORE.java ================================================ package instructions.stores.storeint; import instructions.base.Index8Instruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ISTORE extends Index8Instruction { @Override public void execute(Zframe frame) { Store.istore(frame,index); } } ================================================ FILE: Java/src/instructions/stores/storeint/ISTORE_0.java ================================================ package instructions.stores.storeint; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ISTORE_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.istore(frame,0); } } ================================================ FILE: Java/src/instructions/stores/storeint/ISTORE_1.java ================================================ package instructions.stores.storeint; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ISTORE_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.istore(frame,1); } } ================================================ FILE: Java/src/instructions/stores/storeint/ISTORE_2.java ================================================ package instructions.stores.storeint; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ISTORE_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.istore(frame,2); } } ================================================ FILE: Java/src/instructions/stores/storeint/ISTORE_3.java ================================================ package instructions.stores.storeint; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ISTORE_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.istore(frame,3); } } ================================================ FILE: Java/src/instructions/stores/storelong/LSTORE.java ================================================ package instructions.stores.storelong; import instructions.base.Index8Instruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LSTORE extends Index8Instruction { @Override public void execute(Zframe frame) { Store.lstore(frame,index); } } ================================================ FILE: Java/src/instructions/stores/storelong/LSTORE_0.java ================================================ package instructions.stores.storelong; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LSTORE_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.lstore(frame,0); } } ================================================ FILE: Java/src/instructions/stores/storelong/LSTORE_1.java ================================================ package instructions.stores.storelong; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LSTORE_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.lstore(frame,1); } } ================================================ FILE: Java/src/instructions/stores/storelong/LSTORE_2.java ================================================ package instructions.stores.storelong; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LSTORE_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.lstore(frame,2); } } ================================================ FILE: Java/src/instructions/stores/storelong/LSTORE_3.java ================================================ package instructions.stores.storelong; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class LSTORE_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.lstore(frame,3); } } ================================================ FILE: Java/src/instructions/stores/storeref/ASTORE.java ================================================ package instructions.stores.storeref; import instructions.base.Index8Instruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ASTORE extends Index8Instruction { @Override public void execute(Zframe frame) { Store.astore(frame,index); } } ================================================ FILE: Java/src/instructions/stores/storeref/ASTORE_0.java ================================================ package instructions.stores.storeref; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ASTORE_0 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.astore(frame,0); } } ================================================ FILE: Java/src/instructions/stores/storeref/ASTORE_1.java ================================================ package instructions.stores.storeref; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ASTORE_1 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.astore(frame,1); } } ================================================ FILE: Java/src/instructions/stores/storeref/ASTORE_2.java ================================================ package instructions.stores.storeref; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ASTORE_2 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.astore(frame,2); } } ================================================ FILE: Java/src/instructions/stores/storeref/ASTORE_3.java ================================================ package instructions.stores.storeref; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.Zframe; /** * Author: zhangxin * Time: 2017/5/5 0005. * Desc: */ public class ASTORE_3 extends NoOperandsInstruction { @Override public void execute(Zframe frame) { Store.astore(frame,3); } } ================================================ FILE: Java/src/instructions/stores/storexarr/AASTORE.java ================================================ package instructions.stores.storexarr; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:对数组某一元素的赋值 x[0] = y */ public class AASTORE extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //所要赋的值 Zobject val = operandStack.popRef(); //数组索引 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Store.checkNotNull(arrRef); //得到数组对象 Zobject[] refs = arrRef.getRefs(); Store.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的元素进行赋值 refs[index] = val; } } ================================================ FILE: Java/src/instructions/stores/storexarr/BASTORE.java ================================================ package instructions.stores.storexarr; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:对数组某一元素的赋值 x[0] = y */ public class BASTORE extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //所要赋的值 byte val = (byte) operandStack.popInt(); //数组索引 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Store.checkNotNull(arrRef); //得到数组对象 byte[] refs = arrRef.getBytes(); Store.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的元素进行赋值 refs[index] = val; } } ================================================ FILE: Java/src/instructions/stores/storexarr/CASTORE.java ================================================ package instructions.stores.storexarr; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:对数组某一元素的赋值 x[0] = y */ public class CASTORE extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //所要赋的值 char val = (char) operandStack.popInt(); //数组索引 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Store.checkNotNull(arrRef); //得到数组对象 char[] refs = arrRef.getChars(); Store.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的元素进行赋值 refs[index] = val; } } ================================================ FILE: Java/src/instructions/stores/storexarr/DASTORE.java ================================================ package instructions.stores.storexarr; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:对数组某一元素的赋值 x[0] = y */ public class DASTORE extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //所要赋的值 double val = operandStack.popDouble(); //数组索引 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Store.checkNotNull(arrRef); //得到数组对象 double[] refs = arrRef.getDoubles(); Store.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的元素进行赋值 refs[index] = val; } } ================================================ FILE: Java/src/instructions/stores/storexarr/FASTORE.java ================================================ package instructions.stores.storexarr; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:对数组某一元素的赋值 x[0] = y */ public class FASTORE extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //所要赋的值 float val = operandStack.popFloat(); //数组索引 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Store.checkNotNull(arrRef); //得到数组对象 float[] refs = arrRef.getFloats(); Store.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的元素进行赋值 refs[index] = val; } } ================================================ FILE: Java/src/instructions/stores/storexarr/IASTORE.java ================================================ package instructions.stores.storexarr; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:对数组某一元素的赋值 x[0] = y */ public class IASTORE extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //所要赋的值 int val = operandStack.popInt(); //数组索引 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Store.checkNotNull(arrRef); //得到数组对象 int[] refs = arrRef.getInts(); Store.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的元素进行赋值 refs[index] = val; } } ================================================ FILE: Java/src/instructions/stores/storexarr/LASTORE.java ================================================ package instructions.stores.storexarr; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:对数组某一元素的赋值 x[0] = y */ public class LASTORE extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //所要赋的值 long val = operandStack.popLong(); //数组索引 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Store.checkNotNull(arrRef); //得到数组对象 long[] refs = arrRef.getLongs(); Store.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的元素进行赋值 refs[index] = val; } } ================================================ FILE: Java/src/instructions/stores/storexarr/SASTORE.java ================================================ package instructions.stores.storexarr; import instructions.base.NoOperandsInstruction; import instructions.stores.Store; import runtimedata.OperandStack; import runtimedata.Zframe; import runtimedata.heap.Zobject; /** * @author zachaxy * @date 17/12/29 * desc:对数组某一元素的赋值 x[0] = y */ public class SASTORE extends NoOperandsInstruction { @Override public void execute(Zframe frame) { OperandStack operandStack = frame.getOperandStack(); //所要赋的值 short val = (short) operandStack.popInt(); //数组索引 int index = operandStack.popInt(); //数组对象的引用 Zobject arrRef = operandStack.popRef(); Store.checkNotNull(arrRef); //得到数组对象 short[] refs = arrRef.getShorts(); Store.checkIndex(arrRef.getArrayLen(), index); //将数组的 index 的元素进行赋值 refs[index] = val; } } ================================================ FILE: Java/src/runtimedata/LocalVars.java ================================================ package runtimedata; /** * Author: zhangxin * Time: 2017/5/4 0004. * Desc: 局部变量表是按索引访问的,所以很自然,可以把它想象成一个数组。 * 根据Java虚拟机规范,这个数组的每个元素至少可以容纳一个int或引用值,两个连续的元素可以容纳一个long或double值。 * 注:这里并没有真的对boolean、byte、short和char类型定义存取方法,因为这些类型的值都是转换成int值类来处理的(4K对齐) */ public class LocalVars extends Slots { public LocalVars(int size) { super(size); } } ================================================ FILE: Java/src/runtimedata/OperandStack.java ================================================ package runtimedata; import runtimedata.heap.Zobject; /** * Author: zhangxin * Time: 2017/5/4 0004. * Desc:操作数栈,底层其实还是用数组来实现的,但是对外要暴露的接口是栈的特性 * 包含的操作和局部变量表类似 * 操作数栈的大小是编译期已经确定的,保存在code属性中,所以可以用Slot数组实现 * 但要和 LocalVars 区分开,本地变量表按索引访问,操作数栈是用数组模拟的栈;方法栈是用单向链表模拟的栈 *

* fixBug:统一说明:在操作数栈中,涉及到引用的操作:popRef 和 popSlot * 之前的做法是将 ref pop 出来之后,将数组中当前位置设置为 null, * 但是存在的问题是:操作数栈中的如果有多个的引用,都指向相同的一个实例对象, * 将其中的一个引用设置为 null,相当于把对象在堆中的空间设置为 null 了, * 这回导致操作数栈中所有的引用都会变成 null,后续会产生 NullPointerException * 所以这里在弹栈之后,不在设置为 null; * 操作数栈本身是不断复用的,故不考虑 GC 问题 */ public class OperandStack { //初始值为0,在运行中,代表当前栈顶的index,还未使用,可以直接用,用完记得size++; private int size; private Slot[] slots; public OperandStack(int maxStack) { if (maxStack >= 0) { slots = new Slot[maxStack]; } else { throw new NullPointerException("maxStack<0"); } } public void pushBoolean(boolean val) { if (val) { pushInt(1); } else { pushInt(0); } } public boolean popBoolean() { return popInt() == 1; } public void pushInt(int val) { Slot slot = new Slot(); slot.num = val; slots[size] = slot; size++; } public int popInt() { size--; return slots[size].num; } public void pushFloat(float val) { Slot slot = new Slot(); slot.num = Float.floatToIntBits(val); slots[size] = slot; size++; } public float popFloat() { size--; return Float.intBitsToFloat(slots[size].num); } public void pushLong(long val) { //低位 Slot slot1 = new Slot(); slot1.num = (int) (val); slots[size] = slot1; size++; //高位 Slot slot2 = new Slot(); slot2.num = (int) (val >> 32); slots[size] = slot2; size++; } public long popLong() { size -= 2; int low = slots[size].num; long high = slots[size + 1].num; //下面的low在和后面的数进行&运算时自动转换为long; return ((high & 0x000000ffffffffL) << 32) | (low & 0x00000000ffffffffL); } public void pushDouble(double val) { long bits = Double.doubleToLongBits(val); pushLong(bits); } public double popDouble() { long bits = popLong(); return Double.longBitsToDouble(bits); } public void pushRef(Zobject ref) { Slot slot = new Slot(); slot.ref = ref; slots[size] = slot; size++; } public Zobject popRef() { size--; return slots[size].ref; } public void pushSlot(Slot slot) { slots[size] = slot; size++; } public Slot popSlot() { size--; return slots[size]; } //新添加的方法,根据参数n,返回操作数栈中的倒数第n个引用; public Zobject getRefFromTop(int n) { return slots[size - 1 - n].ref; } //just for test! public boolean isEmpty() { return size == 0; } //清空操作数栈,直接将 size 设置为0,而不是将所有的 slot 都设为 null;因为这样可能会引起其它问题 public void clear() { size = 0; } } ================================================ FILE: Java/src/runtimedata/Slot.java ================================================ package runtimedata; import runtimedata.heap.Zobject; /** * Author: zhangxin * Time: 2017/5/4 0004. * Desc:局部变量表的数据,根据Java虚拟机规范,这个数组的每个元素至少可以容纳一个int或引用值,两个连续的元素可以容纳一个long或double值。 * 可问题是用什么数据结构来存储,目前并没有很好的方法,只能将这个类设计为既包含一个int有包含一个引用,但是在真正使用的时候,二者只会用其一 * 导致了一半内存的浪费; */ public class Slot { public int num; public Zobject ref; public Slot() {} } ================================================ FILE: Java/src/runtimedata/Slots.java ================================================ package runtimedata; import runtimedata.heap.Zobject; /** * Author: zhangxin * Time: 2017/7/22. * Desc: Slots 封装,针对静态变量表,在申请完空间后,如果没有显式赋值,那么获取值应该为0或 null * 然而 Slot[] 在创建完后,并不具备上述功能 * 因此在构造方法中,Slot[] 创建完后,再为其每一个元素都创建一个 slot 对象, * 这样在没有为静态变量赋值时,访问Slot[]的元素时,不会引发空指针异常! */ public class Slots { private Slot[] slots; public Slots(int size) { slots = new Slot[size]; for (int i = 0; i < size; i++) { slots[i] = new Slot(); } } //提供了对int,float,long,double,引用的存取,这里要注意的是long和double是占用8字节的,所以使用了局部变量表中的两个槽位分别存储前四字节和后四字节 public void setInt(int index, int val) { slots[index].num = val; } public int getInt(int index) { return slots[index].num; } public void setFloat(int index, float val) { slots[index].num = Float.floatToIntBits(val); } public float getFloat(int index) { return Float.intBitsToFloat(slots[index].num); } public void setLong(int index, long val) { //先存低32位 slots[index].num = (int) (val); //再存高32位 slots[index + 1].num = (int) (val >> 32); } public long getLong(int index) { int low = slots[index].num; long high = slots[index + 1].num; return ((high & 0x000000ffffffffL) << 32) | (low & 0x00000000ffffffffL); } public void setDouble(int index, double val) { long bits = Double.doubleToLongBits(val); setLong(index, bits); } public double getDouble(int index) { long bits = getLong(index); return Double.longBitsToDouble(bits); } public void setRef(int index, Zobject ref) { slots[index].ref = ref; } public Zobject getRef(int index) { return slots[index].ref; } public void setSlot(int index, Slot slot) { slots[index] = slot; } } ================================================ FILE: Java/src/runtimedata/Zframe.java ================================================ package runtimedata; import classfile.attribute.CodeAttribute; import runtimedata.heap.Zmethod; /** * Author: zhangxin * Time: 2017/5/4 0004. * Desc:栈帧,执行方法所需的局部变量表大小和操作数栈深度是由编译器预先计算好的,存储在class文件method_info结构的Code属性中 * 详细实现参考 {@link CodeAttribute} */ public class Zframe { Zframe lower; //当前帧的 前一帧的引用;相当于单向链表的前一个指针 LocalVars localVars; //局部变量表的引用; OperandStack operandStack; //操作数栈的引用; Zthread thread; //当前栈帧所在的线程; Zmethod method; int nextPC; //frame中并不改变PC的值,其PC值是由ByteReader读取字节码不断改变的 public Zframe(Zthread thread, int maxLocals, int maxStack) { this.thread = thread; localVars = new LocalVars(maxLocals); operandStack = new OperandStack(maxStack); } public Zframe(Zthread thread, Zmethod method) { this.thread = thread; this.method = method; localVars = new LocalVars(method.getMaxLocals()); operandStack = new OperandStack(method.getMaxStack()); } public LocalVars getLocalVars() { return localVars; } public OperandStack getOperandStack() { return operandStack; } public Zthread getThread() { return thread; } public int getNextPC() { return nextPC; } public void setNextPC(int nextPC) { this.nextPC = nextPC; } public Zmethod getMethod() { return method; } public void setMethod(Zmethod method) { this.method = method; } //用在new,getStatic,invokeStatic 等指令中,判断clinit 方法是否执行,如果执行,则需要保存当前thread 的 pc //eg:当前执行的是 new 指令,那么 thead 的 pc 指向的是 new, //再 push 一个新栈去执行,等直接结束后,在回到当前 frame,拿到 pc,此时的 pc 指向的还是 new //重新执行一遍 new public void revertNextPC() { this.nextPC = thread.getPc(); } } ================================================ FILE: Java/src/runtimedata/Zstack.java ================================================ package runtimedata; import java.util.EmptyStackException; /** * Author: zhangxin * Time: 2017/5/4 0004. * Desc: 并没有采用数组的形式来保存栈帧,而是使用单向链表的形式,Zframe中保存这前一个帧的引用; * 最多持有1024个栈帧,当然这个值可以设置; */ public class Zstack { int maxSize; //虚拟机栈中所包含栈帧的最大容量 int size; //当前虚拟机栈中包含帧的数量 private Zframe _top; //栈顶的帧 public Zstack(int maxSize) { this.maxSize = maxSize; } //新添加一个栈帧,将这个栈帧设置为top,当然如果当前栈之前有元素,那么将要push进的frame的lower是指为之前的top,当前frame变为top; void push(Zframe frame) { if (size > maxSize) { //throw new RuntimeException("java.lang.StackOverflowError"); //如果栈已经满了,按照Java虚拟机规范,应该抛出StackOverflowError异常 throw new StackOverflowError(); } if (_top != null) { frame.lower = _top; // frame中保存前一个帧的引用,使得当前帧被push的时,前一个帧顶上去; } _top = frame; size++; } Zframe pop() { if (_top == null) { throw new EmptyStackException(); } Zframe tmp = _top; _top = tmp.lower; tmp.lower = null; //tmp是带pop出的栈帧,既然要pop出来,那么将其lower设置为null,不在持有栈中的帧,避免内存泄露; size--; return tmp; } Zframe top() { if (_top == null) { throw new EmptyStackException(); } return _top; } Zframe[] getFrames() { Zframe[] frames = new Zframe[size]; int i = 0; for (Zframe frame = _top;frame!=null;frame = frame.lower) { frames[i] = frame; i++; } return frames; } } ================================================ FILE: Java/src/runtimedata/Zthread.java ================================================ package runtimedata; import runtimedata.heap.Zmethod; /** * Author: zhangxin * Time: 2017/5/4 0004. * Desc: 定义Thread结构体,目前只定义了pc和stack两个字段,每个线程中都持有一个虚拟机栈的引用 * Java虚拟机规范对Java虚拟机栈的约束也相当宽松, * 虚拟机栈可以是连续的空间,也可以不连续 * 可以是固定大小,也可以在运行时动态扩展 *

* 如果Java虚拟机栈有大小限制,且执行线程所需的栈空间超出了这个限制,会导致StackOverflowError异常抛出。 * 如果Java虚拟机栈可以动态扩展,但是内存已经耗尽,会导致OutOfMemoryError异常抛出。 *

* 其实Java命令提供了-Xss选项来设置Java虚拟机栈大小 */ public class Zthread { private int pc; //该PC也不是自己修改的,而是由外部传入供当前线程所持有的; private Zstack stack; //Stack结构体(Java虚拟机栈)的引用; public Zthread() { //默认栈的大小是1024,也就是说可以存放1024个栈帧 stack = new Zstack(1024); } public int getPc() { return pc; } public void setPc(int pc) { this.pc = pc; } public void pushFrame(Zframe frame) { stack.push(frame); } public Zframe popFrame() { return stack.pop(); } public Zframe getCurrentFrame() { return stack.top(); } public Zframe createFrame(int maxLocals, int maxStack) { return new Zframe(this, maxLocals, maxStack); } public Zframe createFrame(Zmethod method) { return new Zframe(this, method); } public boolean isStackEmpty() { return stack.size == 0; } public void clearStack() { while (!isStackEmpty()) { stack.pop(); } } public Zframe[] getFrames() { return stack.getFrames(); } } ================================================ FILE: Java/src/runtimedata/heap/AccessFlag.java ================================================ package runtimedata.heap; /** * Author: zhangxin * Time: 2017/5/19 0019. * Desc: 访问标示,对于类,方法,字段,都有自己的访问标示; * 这里进行统一的封装,以后类,方法,字段的访问标识都从这个类取 */ public class AccessFlag { public static final int ACC_PUBLIC = 0x0001; // class field method public static final int ACC_PRIVATE = 0x0002; // field method public static final int ACC_PROTECTED = 0x0004; // field method public static final int ACC_STATIC = 0x0008; // field method public static final int ACC_FINAL = 0x0010; // class field method public static final int ACC_SUPER = 0x0020; // class public static final int ACC_SYNCHRONIZED = 0x0020; // method public static final int ACC_VOLATILE = 0x0040; // field public static final int ACC_BRIDGE = 0x0040; // method public static final int ACC_TRANSIENT = 0x0080; // field public static final int ACC_VARARGS = 0x0080; // method public static final int ACC_NATIVE = 0x0100; // method public static final int ACC_INTERFACE = 0x0200; // class public static final int ACC_ABSTRACT = 0x0400; // class method public static final int ACC_STRICT = 0x0800; // method public static final int ACC_SYNTHETIC = 0x1000; // class field method public static final int ACC_ANNOTATION = 0x2000; // class public static final int ACC_ENUM = 0x4000; // class field } ================================================ FILE: Java/src/runtimedata/heap/ClassMember.java ================================================ package runtimedata.heap; import classfile.MemberInfo; /** * Author: zhangxin * Time: 2017/5/20 0020. * Desc: 字段和方法都属于类的成员,它们有一些相同的信息(访问标志、名字、描述符) * 所以这里定义一个父类ClassMember用来存放字段和方法共同的部分; * 但是字段和方法不同的部分还需要分开处理:Zfiled;Zmethod */ public class ClassMember { protected int accessFlags; //访问标示 protected String name; //字段、方法名称 protected String descriptor; //字段、方法描述 protected Zclass clazz; //所属的类,这样可以通过字段或方法访问到它所属的类 public ClassMember(Zclass clazz, MemberInfo classFileMemberInfo) { copyMemberInfo(classFileMemberInfo); this.clazz = clazz; } /** * 从class文件的memberInfo中复制数据 * * @param memberInfo */ private void copyMemberInfo(MemberInfo memberInfo) { accessFlags = memberInfo.getAccessFlags(); name = memberInfo.getName(); descriptor = memberInfo.getDescriptor(); } public boolean isPublic() { return 0 != (accessFlags & AccessFlag.ACC_PUBLIC); } public boolean isPrivate() { return 0 != (accessFlags & AccessFlag.ACC_PRIVATE); } public boolean isProtected() { return 0 != (accessFlags & AccessFlag.ACC_PROTECTED); } public boolean isStatic() { return 0 != (accessFlags & AccessFlag.ACC_STATIC); } public boolean isFinal() { return 0 != (accessFlags & AccessFlag.ACC_FINAL); } public boolean isSynthetic() { return 0 != (accessFlags & AccessFlag.ACC_SYNTHETIC); } public String getName() { return name; } public String getDescriptor() { return descriptor; } public Zclass getClazz() { return clazz; } public boolean isAccessTo(Zclass d) { if (isPublic()) { return true; } if (isProtected()) { return d == clazz || d.isSubClassOf(clazz) || d.getPackageName().equals(clazz.getPackageName()); } if (!isPrivate()) { return d.getPackageName().equals(clazz.getPackageName()); } return d == clazz; } public int getAccessFlags() { return accessFlags; } public void setClazz(Zclass clazz) { this.clazz = clazz; } } ================================================ FILE: Java/src/runtimedata/heap/ClassNameHelper.java ================================================ package runtimedata.heap; import java.util.HashMap; import java.util.Map; /** * @author zachaxy * @date 17/12/29 */ public class ClassNameHelper { public static HashMap primitiveTypes; static { primitiveTypes = new HashMap(); primitiveTypes.put("void", "V"); primitiveTypes.put("boolean", "Z"); primitiveTypes.put("byte", "B"); primitiveTypes.put("short", "S"); primitiveTypes.put("int", "I"); primitiveTypes.put("long", "J"); primitiveTypes.put("char", "C"); primitiveTypes.put("float", "F"); primitiveTypes.put("double", "D"); } // [XXX -> [[XXX // int -> [I // XXX -> [LXXX; public static String getArrayClassName(String className) { return "[" + toDescriptor(className); } // [[XXX -> [XXX // [LXXX; -> XXX // [I -> int public static String getComponentClassName(String className) { if (className.charAt(0) == '[') { String componentTypeDescriptor = className.substring(1); return toClassName(componentTypeDescriptor); } throw new RuntimeException("Not array: " + className); } // [XXX => [XXX // int => I // XXX => LXXX; private static String toDescriptor(String className) { if (className.charAt(0) == '[') { //array return className; } if (primitiveTypes.containsKey(className)) { return primitiveTypes.get(className); } // object return "L" + className + ";"; } // [XXX => [XXX // LXXX; => XXX // I => int private static String toClassName(String descriptor) { if (descriptor.charAt(0) == '[') { // array return descriptor; } if (descriptor.charAt(0) == 'L') { // object return descriptor.substring(1, descriptor.length() - 1); } for (Map.Entry entry : primitiveTypes.entrySet()) { if (entry.getValue().equals(descriptor)) { return entry.getKey(); } } throw new RuntimeException("Invalid descriptor: " + descriptor); } } ================================================ FILE: Java/src/runtimedata/heap/ClassRef.java ================================================ package runtimedata.heap; import classfile.classconstant.ConstantClassInfo; /** * Author: zhangxin * Time: 2017/7/22. * Desc: 类引用 */ public class ClassRef extends SymRef { public ClassRef(RuntimeConstantPool runtimeConstantPool, ConstantClassInfo classInfo) { super(runtimeConstantPool); this.className = classInfo.getName(); } } ================================================ FILE: Java/src/runtimedata/heap/ExceptionTable.java ================================================ package runtimedata.heap; import classfile.attribute.CodeAttribute; /** * @author zachaxy * @date 18/1/2 */ public class ExceptionTable { private ExceptionHandler[] exceptionTable; public ExceptionTable(CodeAttribute.ExceptionTableEntry[] entry, RuntimeConstantPool runtimeConstantPool) { exceptionTable = new ExceptionHandler[entry.length]; for (int i = 0; i < entry.length; i++) { exceptionTable[i] = new ExceptionHandler(); exceptionTable[i].startPc = entry[i].getStartPc(); exceptionTable[i].endPc = entry[i].getEndPc(); exceptionTable[i].handlerPc = entry[i].getHandlerPc(); exceptionTable[i].catchType = getCatchType(entry[i].getCatchType(), runtimeConstantPool); } } //将classFile中的异常类型(符号引用)转换为运行时的直接引用 public ClassRef getCatchType(int index, RuntimeConstantPool runtimeConstantPool) { if (index == 0) { // catch all return null; } return (ClassRef) runtimeConstantPool.getRuntimeConstant(index).getValue(); } //返回能解决当前Exception的handler=>多个catch块,决定用哪个 public ExceptionHandler findExceptionHandler(Zclass exClazz, int pc) { for (int i = 0; i < exceptionTable.length; i++) { ExceptionHandler handler = exceptionTable[i]; if (pc >= handler.startPc && pc < handler.endPc) { // catch all if (handler.catchType == null) { return handler; } // 如果catch 的异常是实际抛出的异常的父类,也可以捕获 Zclass catchClazz = handler.catchType.resolvedClass(); if (catchClazz == exClazz || catchClazz.isSuperClassOf(exClazz)) { return handler; } } } return null; } } class ExceptionHandler { int startPc; int endPc; int handlerPc; ClassRef catchType; } ================================================ FILE: Java/src/runtimedata/heap/FieldRef.java ================================================ package runtimedata.heap; import classfile.classconstant.ConstantFieldRefInfo; /** * Author: zhangxin * Time: 2017/7/22 * Desc: 字段引用 */ public class FieldRef extends MemberRef { Zfield field; public FieldRef(RuntimeConstantPool runtimeConstantPool, ConstantFieldRefInfo fieldRefInfo) { super(runtimeConstantPool); copyMemberRefInfo(fieldRefInfo); } //字段引用转直接引用 public Zfield resolvedField() { if (field == null) { resolvedRefField(); } return field; } public void resolvedRefField() { Zclass d = runtimeConstantPool.clazz; // 获取 fieldRef 所在的类 Zclass c = resolvedClass(); //在该类中找到对应的字段 field Zfield field = lookupField(c, name, descriptor); if (field == null) { throw new NoSuchFieldError("NoSuchFieldError:" + name); } if (!field.isAccessTo(d)) { throw new IllegalAccessError(d.thisClassName + " can't access " + name + "in Class " + c.thisClassName); } this.field = field; } private Zfield lookupField(Zclass c, String name, String descriptor) { for (Zfield zf : c.fileds) { if (zf.name.equals(name) && zf.getDescriptor().equals(descriptor)) { return zf; } } for (Zclass zin : c.interfaces) { return lookupField(zin, name, descriptor); } if (c.superClass != null) { return lookupField(c.superClass, name, descriptor); } return null; } } ================================================ FILE: Java/src/runtimedata/heap/InterfaceMethodRef.java ================================================ package runtimedata.heap; import classfile.classconstant.ConstantInterfaceMethodRefInfo; /** * Author: zhangxin * Time: 2017/7/22. * Desc:接口方法引用 */ public class InterfaceMethodRef extends MemberRef { Zmethod method; public InterfaceMethodRef(RuntimeConstantPool runtimeConstantPool, ConstantInterfaceMethodRefInfo interfaceMethodRefInfo) { super(runtimeConstantPool); copyMemberRefInfo(interfaceMethodRefInfo); } //接口方法引用转直接引用 public Zmethod resolvedInterfaceMethod() { if (method == null) { resolveInterfaceMethodRef(); } return method; } private void resolveInterfaceMethodRef() { Zclass d = runtimeConstantPool.clazz; //获取 methodRef 所在的接口 Zclass c = resolvedClass(); if (!c.isInterface()) { throw new IncompatibleClassChangeError(c.thisClassName); } //在该类中找到对应的方法 Zmethod method = lookupInterfaceMethod(c, name, descriptor); if (method == null) { throw new NoSuchMethodError("NoSuchMethodError:" + name); } if (!method.isAccessTo(d)) { throw new IllegalAccessError(d.thisClassName + " can't access " + name + "in Class " + c.thisClassName); } this.method = method; } private Zmethod lookupInterfaceMethod(Zclass iface, String name, String descriptor) { for (Zmethod method : iface.methods) { if (method.name.equals(name) && method.descriptor.equals(descriptor)) { return method; } } return MethodLookup.lookupMethodInInterfaces(iface.interfaces, name, descriptor); } } ================================================ FILE: Java/src/runtimedata/heap/MemberRef.java ================================================ package runtimedata.heap; import classfile.classconstant.ConstantMemberRefInfo; /** * Author: zhangxin * Time: 2017/7/22. * Desc: 字段和方法的符号引用保存的相同信息;包含全限名和描述符; * 字段和方法特有的属性,有其对应子类来实现; */ public class MemberRef extends SymRef { protected String name; //字段或方法名 protected String descriptor; //字段或方法描述符 public MemberRef(RuntimeConstantPool runtimeConstantPool) { super(runtimeConstantPool); } void copyMemberRefInfo(ConstantMemberRefInfo refInfo) { className = refInfo.getClassName(); name = refInfo.getName(); descriptor = refInfo.getDescriptor(); } public String getName() { return name; } public String getDescriptor() { return descriptor; } } ================================================ FILE: Java/src/runtimedata/heap/MethodDescriptor.java ================================================ package runtimedata.heap; import java.util.ArrayList; /** * @author zachaxy * @date 17/12/27 */ public class MethodDescriptor { private String raw; //在class文件中原始的描述eg:(Ljava/lang/String;IL)V private int offset; //解析raw的当前索引 private ArrayList parameterTypes; private String returnType; public MethodDescriptor(String raw) { this.raw = raw; parameterTypes = new ArrayList(); parse(); } private void addParameterType(String type) { parameterTypes.add(type); } private void parse() { startParams(); parseParamTypes(); endParams(); parseReturnType(); finish(); } //参数无论有无,都需要用(开始的 private void startParams() { if ('(' != readChar()) { causePanic(); } } //参数无论有无,都需要用)结束的 private void endParams() { if (')' != readChar()) { causePanic(); } } //解析结束后offset应该等于字符串的长度,都则报错! private void finish() { if (offset != raw.length()) { causePanic(); } } private void causePanic() { throw new RuntimeException("BAD descriptor: " + raw); } //获取当前字符串的一个字符; private char readChar() { char c = raw.charAt(offset); offset++; return c; } //字符解析回退,只将当前指针-1即可 private void unreadChar() { offset--; } //解析参数类型,解析到之后不断的向parameterTypes添加解析到的类型 private void parseParamTypes() { while (true) { String t = parseFieldType(); if (!"".equals(t)) { parameterTypes.add(t); } else { break; } } } //解析返回值类型 private void parseReturnType() { if ('V' == readChar()) { returnType = "V"; return; } unreadChar(); String t = parseFieldType(); if (!"".equals(t)) { returnType = t; return; } causePanic(); } //解析参数或返回值的具体类型 private String parseFieldType() { char c = readChar(); switch (c) { case 'B': return "B"; case 'C': return "C"; case 'D': return "D"; case 'F': return "F"; case 'I': return "I"; case 'J': return "J"; case 'S': return "S"; case 'Z': return "Z"; case 'L': return parseObjectType(); case '[': return parseArrayType(); default://如果产生这种情况,说明参数已经解析完毕了,目前的符号必定是),回退1,调用解析参数结束 unreadChar(); return ""; } } //如果是引用类型,其必定是以;结尾的----最终的返回值是形如:Ljava/lang/String的形式; private String parseObjectType() { int semicolonIndex = raw.indexOf(';', offset); if (semicolonIndex == -1) { causePanic(); return ""; } else { int start = offset - 1; int end = semicolonIndex + 1; offset = end; return raw.substring(start, end); } } //解析数组类型 private String parseArrayType() { int start = offset - 1; parseFieldType(); int end = offset; return raw.substring(start, end); } public ArrayList getParameterTypes() { return parameterTypes; } public String getReturnType() { return returnType; } } ================================================ FILE: Java/src/runtimedata/heap/MethodLookup.java ================================================ package runtimedata.heap; /** * @author zachaxy * @date 17/12/25 */ public class MethodLookup { public static Zmethod lookupMethodInClass(Zclass clazz, String name, String descriptor) { Zclass c = clazz; while (c != null) { for (Zmethod method : c.methods) { if (method.name.equals(name) && method.descriptor.equals(descriptor)) { return method; } } c = c.superClass; } return null; } public static Zmethod lookupMethodInInterfaces(Zclass[] ifaces, String name, String descriptor) { for (Zclass iface : ifaces) { for (Zmethod method : iface.methods) { if (method.name.equals(name) && method.descriptor.equals(descriptor)) { return method; } } Zmethod method = lookupMethodInInterfaces(iface.interfaces, name, descriptor); if (method != null) { return method; } } return null; } } ================================================ FILE: Java/src/runtimedata/heap/MethodRef.java ================================================ package runtimedata.heap; import classfile.classconstant.ConstantMethodRefInfo; /** * Author: zhangxin * Time: 2017/7/22. * Desc: 非接口方法引用; */ public class MethodRef extends MemberRef { Zmethod method; public MethodRef(RuntimeConstantPool runtimeConstantPool, ConstantMethodRefInfo methodRefInfo) { super(runtimeConstantPool); copyMemberRefInfo(methodRefInfo); } //非接口方法引用转直接引用 public Zmethod resolvedMethod() { if (method == null) { resolvedRefMethod(); } return method; } public void resolvedRefMethod() { Zclass d = runtimeConstantPool.clazz; //获取 methodRef 所在的类 Zclass c = resolvedClass(); if (c.isInterface()) { throw new IncompatibleClassChangeError(c.thisClassName); } //在该类中找到对应的方法 Zmethod method = lookupMethod(c, name, descriptor); if (method == null) { throw new NoSuchMethodError("NoSuchMethodError:" + name); } if (!method.isAccessTo(d)) { throw new IllegalAccessError(d.thisClassName + " can't access " + name + "in Class " + c.thisClassName); } this.method = method; } //TODO:需验证方法引用,在父类找不到后,是否需要从其接口中再去找? private Zmethod lookupMethod(Zclass c, String name, String descriptor) { return MethodLookup.lookupMethodInClass(c, name, descriptor); } } ================================================ FILE: Java/src/runtimedata/heap/RuntimeConstantInfo.java ================================================ package runtimedata.heap; /** * @author zachaxy * @date 17/12/25 * desc:运行时常量,区别于 class 文件中的常量 * 本想用泛型来约束运行时常量池的类型,这样在取运行时常量池的值时可以避免丑陋的类型强壮代码风格 * 无奈的是,运行时常量池是放在数组中的,一旦放入数组,其对象的泛型类型也就消失了 * 所以使用标志位 type 来识别类型,取出后再进行类型转换 */ public class RuntimeConstantInfo { private T value; private int type; RuntimeConstantInfo(T value,int type){ this.value = value; this.type = type; } public T getValue(){ return value; } public int getType() { return type; } } ================================================ FILE: Java/src/runtimedata/heap/RuntimeConstantPool.java ================================================ package runtimedata.heap; import classfile.ConstantPool; import classfile.classconstant.*; import java.util.NoSuchElementException; /** * Author: zhangxin * Time: 2017/5/20 0020. * Desc: 运行时常量池,注意和字节码中的常量池做区分,这里指的是线程共享区的常量; * 实现的功能是:把class文件中的常量池转换成运行时常量池 * 这里对两种常量池做了区分,class 文件中的常量池仍然用:ConstantPool * 而运行时常量池使用的是:RuntimeConstantPool * 核心在于将符号引用转为直接引用; * 符号引用,简单理解:在 class 文件中,所有的引用都是通过字符串来指引的,而现在是在内存中,则需要指向内存中一个实际的对象, * 可以理解为指针,而不能简单的用字符串来描述引用了; *

* 两种常量池类似的是:对 Long 和 Double 类型都进行了++的操作,以匹配 class文件中的常量索引。 * 本身的一个常量都可以用来保存Long 的,只是为了匹配class文件中的常量索引而已! */ public class RuntimeConstantPool { Zclass clazz; RuntimeConstantInfo[] infos; //主要作用是将class文件中的常量池转换为运行时常量池; public RuntimeConstantPool(Zclass clazz, ConstantPool classFileConstantPool) { this.clazz = clazz; ConstantInfo[] classFileConstantInfos = classFileConstantPool.getInfos(); int len = classFileConstantInfos.length; this.infos = new RuntimeConstantInfo[len]; for (int i = 1; i < len; i++) { ConstantInfo classFileConstantInfo = classFileConstantInfos[i]; switch (classFileConstantInfo.getType()) { case ConstantInfo.CONSTANT_Integer: ConstantIntegerInfo intInfo = (ConstantIntegerInfo) classFileConstantInfo; this.infos[i] = new RuntimeConstantInfo(intInfo.getVal(), ConstantInfo.CONSTANT_Integer); break; case ConstantInfo.CONSTANT_Float: ConstantFloatInfo floatInfo = (ConstantFloatInfo) classFileConstantInfo; this.infos[i] = new RuntimeConstantInfo(floatInfo.getVal(), ConstantInfo.CONSTANT_Float); break; case ConstantInfo.CONSTANT_Long: //Long 和 Double 在转换结束之后,都要进行 i++,以适配 class 文件中常量池的索引 ConstantLongInfo longInfo = (ConstantLongInfo) classFileConstantInfo; this.infos[i] = new RuntimeConstantInfo(longInfo.getVal(), ConstantInfo.CONSTANT_Long); i++; break; case ConstantInfo.CONSTANT_Double: ConstantDoubleInfo doubleInfo = (ConstantDoubleInfo) classFileConstantInfo; this.infos[i] = new RuntimeConstantInfo(doubleInfo.getVal(), ConstantInfo.CONSTANT_Double); i++; break; case ConstantInfo.CONSTANT_String: //在对字符串引用进行转换的时候,转为字符串直接引用 ConstantStringInfo stringInfo = (ConstantStringInfo) classFileConstantInfo; this.infos[i] = new RuntimeConstantInfo(stringInfo.getString(), ConstantInfo.CONSTANT_String); break; case ConstantInfo.CONSTANT_Class: ConstantClassInfo classInfo = (ConstantClassInfo) classFileConstantInfo; //ref 类中真正需要的是 传入上面的 clazz this.infos[i] = new RuntimeConstantInfo(new ClassRef(this, classInfo), ConstantInfo.CONSTANT_Class); break; case ConstantInfo.CONSTANT_Fieldref: ConstantFieldRefInfo fieldRefInfo = (ConstantFieldRefInfo) classFileConstantInfo; this.infos[i] = new RuntimeConstantInfo(new FieldRef(this, fieldRefInfo), ConstantInfo.CONSTANT_Fieldref); break; case ConstantInfo.CONSTANT_Methodref: ConstantMethodRefInfo methodRefInfo = (ConstantMethodRefInfo) classFileConstantInfo; this.infos[i] = new RuntimeConstantInfo(new MethodRef(this, methodRefInfo), ConstantInfo.CONSTANT_Methodref); break; case ConstantInfo.CONSTANT_InterfaceMethodref: ConstantInterfaceMethodRefInfo interfaceMethodRefInfo = (ConstantInterfaceMethodRefInfo) classFileConstantInfo; this.infos[i] = new RuntimeConstantInfo(new InterfaceMethodRef(this, interfaceMethodRefInfo), ConstantInfo.CONSTANT_InterfaceMethodref); break; default: //还有一些jdk1.7才开始支持的动态属性,不在本虚拟机的实现范围内 break; } } } //这里只是把ConstantInfo返回,至于具体是那种数据,可以根据其中保存的type字段来判断,并拿到对应类型的值; public RuntimeConstantInfo getRuntimeConstant(int index) { RuntimeConstantInfo info = infos[index]; if (info != null) { return info; } throw new NoSuchElementException("No constants at index " + index); } } ================================================ FILE: Java/src/runtimedata/heap/StringPool.java ================================================ package runtimedata.heap; import java.util.HashMap; /** * @author zachaxy * @date 17/12/30 * desc:这里用来模拟 JVM 中的字符串池,但是由于当前的 JVM 本身就是用 Java 写的,所以会省掉很多真正的细节 * 这里用一个 HasMap 来模拟字符串池,key 为从 class 文件中读到的字符串,value 为我们定义的 Zobject */ public class StringPool { public static HashMap internedStrings = new HashMap<>(); public static HashMap realInternedStrings = new HashMap<>(); public static Zobject jString(ZclassLoader loader, String str) { if (internedStrings.containsKey(str)) { return internedStrings.get(str); } // chars := stringToUtf16(goStr) // jChars := &Object{loader.LoadClass("[C"), chars, nil} // // //这里创建了一个String的对象 // jStr := loader.LoadClass("java/lang/String").NewObject() // //不是通过构造方法,而是通过直接setVar的方式,将上面创建的jChar数组设置进来; // jStr.SetRefVar("value", "[C", jChars) // // internedStrings[goStr] = jStr // return jStr char[] chars = str.toCharArray(); Zobject jChars = new Zobject(loader.loadClass("[C"), chars, null); Zobject jStr = loader.loadClass("java/lang/String").newObject(); jStr.setRefVar("value", "[C", jChars); internedStrings.put(str, jStr); //这一步的实现有些取巧了,Zobject 并没有实现 equals 和 hashCode 方法,但依然可以作为 key //是因为在 internedStrings 中的 key 是 java 中的String,这是合法的,相同的 String 取到的 value //也就是 Zobject ,也是一样的;这就保证了 Zobject 可以作为hashMap 的 key; realInternedStrings.put(jStr, str); return jStr; } //凡是调用该方法,必定是从上面的常量池中获取了相同的字符串,然后返回其在 JVM 中的 Zobject public static String realString(Zobject jStr) { if (realInternedStrings.containsKey(jStr)) { return realInternedStrings.get(jStr); } Zobject ref = jStr.getRefVar("value", "[C"); char[] chars = ref.getChars(); String realStr = new String(chars); realInternedStrings.put(jStr, realStr); return realStr; } } ================================================ FILE: Java/src/runtimedata/heap/SymRef.java ================================================ package runtimedata.heap; /** * Author: zhangxin * Time: 2017/5/24 0024. * Desc: 保存符号引用的一些共有属性; * 这里一个重要的工作是将被引用的类的class加载进来; */ public class SymRef { RuntimeConstantPool runtimeConstantPool; //存放符号引用所在的运行时常量池指针,可以通过符号引用访问到运行时常量池,进一步又可以访问到类数据 String className; //存放类的完全限定名 Zclass clazz; //上述运行时常量池的宿主类中的符号引用的真正类,在外面访问时,根据 clazz 是否为 null 来决定是否执行 loadClass public SymRef(RuntimeConstantPool runtimeConstantPool) { this.runtimeConstantPool = runtimeConstantPool; } //类引用转直接引用 public Zclass resolvedClass() { if (clazz == null) { resolvedClassRef(); } return clazz; } // 当前类(cp的宿主类)d中,如果引用了类c,那么就将c加载进来 private void resolvedClassRef() { Zclass d = runtimeConstantPool.clazz; Zclass c = d.loader.loadClass(className); //在这里判断下 d 能否访问 c if (!c.isAccessibleTo(d)) { throw new IllegalAccessError(d.thisClassName + " can't access " + c.thisClassName); } clazz = c; } } ================================================ FILE: Java/src/runtimedata/heap/Zclass.java ================================================ package runtimedata.heap; import classfile.ClassFile; import runtimedata.Slots; /** * Author: zhangxin * Time: 2017/5/19 0019. * Desc: 如何设法保证同一个对象的 class == 返回 true?如果不自己定义 classloader,那么由系统提供的统一的 * 类加载器去加载 class,可以保证同一个对象的 class == 返回 true;因为加载后的 class 对象保存在方法区的 hashMap中, * key 为类的全限定名。 */ public class Zclass { private int accessFlags; // 表示当前类的访问标志 public String thisClassName; //当前类名字(完全限定名) public String superClassName; //父类名字(完全限定名) public String[] interfaceNames;//接口名字(完全限定名,不可以为null,若为实现接口,数组大小为0) private RuntimeConstantPool runtimeConstantPool;//运行时常量池,注意和class文件中常量池区别; Zfield[] fileds; //字段表,包括静态和非静态,此时并不分配 slotId;下面的staticVars 是其子集 Zmethod[] methods; //方法表,包括静态和非静态 ZclassLoader loader; //类加载器 Zclass superClass; //当前类的父类class,由类加载时,给父类赋值; Zclass[] interfaces; //当前类的接口class,由类加载时,给父类赋值; int instanceSlotCount; //非静态变量占用slot大小,这里只是统计个数(从顶级父类Object开始算起) int staticSlotCount; // 静态变量所占空间大小 Slots staticVars; // 存放静态变量 boolean initStarted; //判断类是否已经初始化,执行了类的方法 Zobject jObject; // jObject 指向的是该类的元类对象obj。 eg:String.class 得到的结果 String sourceFile; public Zclass(ClassFile classFile) { accessFlags = classFile.getAccessFlags(); thisClassName = classFile.getClassName(); superClassName = classFile.getSuperClassName(); interfaceNames = classFile.getInterfaceNames(); runtimeConstantPool = new RuntimeConstantPool(this, classFile.getConstantPool()); fileds = Zfield.makeFields(this, classFile.getFields()); methods = Zmethod.makeMethods(this, classFile.getMethods()); sourceFile = classFile.getSourceFile(); } //用来创建数组类型 public Zclass(int accessFlags, String thisClassName, ZclassLoader loader, boolean initStarted, Zclass superClass, Zclass[] interfaces) { this.accessFlags = accessFlags; this.thisClassName = thisClassName; this.loader = loader; this.initStarted = initStarted; this.superClass = superClass; this.interfaces = interfaces; } public RuntimeConstantPool getRuntimeConstantPool() { return runtimeConstantPool; } public ZclassLoader getLoader() { return loader; } public Zclass getSuperClass() { return superClass; } public boolean isInitStarted() { return initStarted; } public void startInit() { initStarted = true; } public boolean isPublic() { return 0 != (accessFlags & AccessFlag.ACC_PUBLIC); } public boolean isFinal() { return 0 != (accessFlags & AccessFlag.ACC_FINAL); } public boolean isSuper() { return 0 != (accessFlags & AccessFlag.ACC_SUPER); } public boolean isInterface() { return 0 != (accessFlags & AccessFlag.ACC_INTERFACE); } public boolean isAbstract() { return 0 != (accessFlags & AccessFlag.ACC_ABSTRACT); } public boolean isSynthetic() { return 0 != (accessFlags & AccessFlag.ACC_SYNTHETIC); } public boolean isAnnotation() { return 0 != (accessFlags & AccessFlag.ACC_ANNOTATION); } public boolean isEnum() { return 0 != (accessFlags & AccessFlag.ACC_ENUM); } public boolean isAccessibleTo(Zclass other) { return isPublic() || getPackageName().equals(other.getPackageName()); } public Slots getStaticVars() { return staticVars; } public String getPackageName() { int i = thisClassName.lastIndexOf("/"); if (i > 0) { return thisClassName.substring(0, i); } return ""; } public String getJavaName() { return thisClassName.replace("/", "."); } public boolean isSubClassOf(Zclass parent) { for (Zclass c = superClass; c != null; c = c.superClass) { if (c == parent) { return true; } } return false; } public boolean isSuperClassOf(Zclass sub) { return sub.isSubClassOf(this); } //这里不太好理解,该方法是在下面的 isImplements 方法中被调用的,调用方是类的接口 //因此下面的 interfaces 数组表明的不是 source 的接口,而是 source 的某一个接口的接口 //虽然接口 sub 在java 语法中是用 extends 继承父接口 parent,但是其字节码中,parent 是 sub 的接口而不是父类 public boolean isSubInterfaceOf(Zclass iface) { for (Zclass superInterface : interfaces) { if (superInterface == iface || superInterface.isSubInterfaceOf(iface)) { return true; } } return false; } private boolean isSuperInterfaceOf(Zclass source) { return source.isSubInterfaceOf(this); } public boolean isImplements(Zclass iface) { for (Zclass c = this; c != null; c = c.superClass) { for (int i = 0; i < c.interfaces.length; i++) { if (c.interfaces[i] == iface || c.interfaces[i].isSubInterfaceOf(iface)) { return true; } } } return false; } public boolean isAssignableFrom(Zclass source) { // source 是否由 target 扩展而来(子类) Zclass target = this; if (source == target) { return true; } if (!source.isArray()) { if (!source.isInterface()) { if (!target.isInterface()) { return source.isSubClassOf(target); } else { // target 是接口 return source.isImplements(target); } } else { // source 是接口 if (!target.isInterface()) { return target.isJlObject(); } else { // target 也是接口 return target.isSuperInterfaceOf(source); } } } else { //source 是数组 if (!target.isArray()) { if (!target.isInterface()) { return target.isJlObject(); } else { // target 是接口 // t is interface;数组默认实现了Cloneable和Serializable接口 return target.isJlCloneable() || target.isJioSerializable(); } } else { // target 也是数组 Zclass sc = source.getComponentClass(); Zclass tc = target.getComponentClass(); return sc == tc || tc.isAssignableFrom(source); } } } public boolean isJlObject() { return "java/lang/Object".equals(thisClassName); } public boolean isJlCloneable() { return "java/lang/Cloneable".equals(thisClassName); } public boolean isJioSerializable() { return "java/io/Serializable".equals(thisClassName); } public Zobject newObject() { return new Zobject(this); } public Zclass arrayClass() { String arrayClassName = ClassNameHelper.getArrayClassName(thisClassName); return loader.loadClass(arrayClassName); } //根据方法名和描述符获取方法,在测试环境中使用; public Zmethod getMethod(String name, String desc) { for (Zclass clazz = this; clazz != null; clazz = clazz.superClass) { for (Zmethod method : methods) { if (method.name.equals(name) && method.descriptor.equals(desc)) { return method; } } } return null; } public Zfield getField(String name, String descriptor, boolean isStatic) { for (Zclass clazz = this; clazz != null; clazz = clazz.superClass) { for (Zfield field : clazz.fileds) { if (field.isStatic() == isStatic && field.name.equals(name) && field.descriptor.equals(descriptor)) { return field; } } } return null; } //---------------针对数组相关的方法 public boolean isArray() { return thisClassName.startsWith("["); } public Zobject newArray(int count) { if (!isArray()) { throw new RuntimeException("Not array class: " + thisClassName); } switch (thisClassName) { case "[Z": return new Zobject(this, new byte[count], null); case "[B": return new Zobject(this, new byte[count], null); case "[C": return new Zobject(this, new char[count], null); case "[S": return new Zobject(this, new short[count], null); case "[I": return new Zobject(this, new int[count], null); case "[J": return new Zobject(this, new long[count], null); case "[F": return new Zobject(this, new float[count], null); case "[D": return new Zobject(this, new double[count], null); default: return new Zobject(this, new Zobject[count], null); } } public Zclass getComponentClass() { String componentClassName = ClassNameHelper.getComponentClassName(thisClassName); return loader.loadClass(componentClassName); } public void setjObject(Zobject jObject) { this.jObject = jObject; } public Zobject getjObject() { return jObject; } public String getSourceFile() { return sourceFile; } } ================================================ FILE: Java/src/runtimedata/heap/ZclassLoader.java ================================================ package runtimedata.heap; import classfile.ClassFile; import classpath.ClassPath; import runtimedata.Slots; import java.util.HashMap; import java.util.Map; /** * Author: zhangxin * Time: 2017/5/19 0019. * Desc: 类加载器 */ public class ZclassLoader { ClassPath classPath; HashMap map; //作为缓存,之前加载过这个类,那么就将其class引用保存到map中,后面再用到这个类的时候,直接用map中取; public ZclassLoader(ClassPath classPath) { this.classPath = classPath; this.map = new HashMap(); loadBasicClasses(); loadPrimitiveClasses(); } private void loadBasicClasses() { //经过这一步load之后,classMap中就有Class的Class了,已经Object 和 Class 所实现的接口; Zclass jlClassClass = loadClass("java/lang/Class"); //接下来对classMap中的每一个Class都创建一个jClass;使用jlClassClass.NewObject()方法; // 通过调用 newObject 方法,为每一个 Class 都创建一个元类对象;这样在使用 String.class 时可以直接获取到; for (Map.Entry entry : map.entrySet()) { Zclass jClass = entry.getValue(); if (jClass.jObject == null) { jClass.jObject = jlClassClass.newObject(); jClass.jObject.extra = jClass; } } } //加载基本类型的类:void.class;boolean.class;byte.class private void loadPrimitiveClasses() { for (Map.Entry entry : ClassNameHelper.primitiveTypes.entrySet()) { String className = entry.getKey(); loadPrimitiveClass(className); } } //加载基本类型,和数组类似,也没有对应的class文件,只能在运行时创建;基本类型:无超类,也没有实现任何接口 /* 针对基本类型的三点说明: 1. void和基本类型的类型名字就是:void,int,float 等 2. 基本类型的类没有超类,也没有实现任何接口 3. 非基本类型的类对象是通过 ldc 指令加载到操作数栈中的 */ private void loadPrimitiveClass(String className) { Zclass clazz = new Zclass(AccessFlag.ACC_PUBLIC, className, this, true, null, new Zclass[]{}); clazz.jObject = map.get("java/lang/Class").newObject(); clazz.jObject.extra = clazz; map.put(className, clazz); } //先查找classMap,看类是否已经被加载。如果是,直接返回类数据,否则调用loadNonArrayClass()方法加载类。 //在类方法中的一个递归调用,也是classLoader中的入口方法 public Zclass loadClass(String name) { if (map.containsKey(name)) { return map.get(name); } Zclass clazz; if (name.charAt(0) == '[') { clazz = loadArrayClass(name); } else { clazz = loadNonArrayClass(name); } //为每一个 class 都关联一个元类 Zclass jlClassClass = map.get("java/lang/Class"); if (jlClassClass != null) { clazz.jObject = jlClassClass.newObject(); clazz.jObject.extra = clazz; } return clazz; } //数组类的字节码不是从 class 文件中获取的,而是在加载了基本类型之后,在 JVM 中动态创建的 private Zclass loadArrayClass(String name) { Zclass clazz = new Zclass(AccessFlag.ACC_PUBLIC, name, this, true, loadClass("java/lang/Object"), new Zclass[]{loadClass("java/lang/Cloneable"), loadClass("java/io/Serializable")}); map.put(name, clazz); return clazz; } private Zclass loadNonArrayClass(String name) { byte[] data = readClass(name); Zclass clazz = defineClass(data); link(clazz); // System.out.println("[Loaded " + name + " from " + name + "]");//因为我们没有返回加载的路径,所以这里只好以name来代替了; return clazz; } /** * 利用 ClassPath 把 class 文件读进来 * * @param name 类名,eg:java.lang.String 或者包含 main 方法的主类名 * @return class 字节数据 */ private byte[] readClass(String name) { byte[] data = classPath.readClass(name); if (data != null) { return data; } else { throw new ClassCastException("class name: " + name); } } /* * 首先把class文件数据转换成 ClassFile 对象,在转为 Zclass 对象; * 加载父类 * 加载接口 * resolveSuperClass:是一个递归的过程,不断的加载父类信息 * */ private Zclass defineClass(byte[] data) { Zclass clazz = parseClass(data); clazz.loader = this; resolveSuperClass(clazz); resolveInterfaces(clazz); map.put(clazz.thisClassName, clazz); return clazz; } private Zclass parseClass(byte[] data) { ClassFile cf = new ClassFile(data); return new Zclass(cf); } //加载当前类的父类,除非是Object类,否则需要递归调用LoadClass()方法加载它的超类 //默认情况下,父类和子类的类加载器是同一个; private void resolveSuperClass(Zclass clazz) { if (!"java/lang/Object".equals(clazz.thisClassName)) { clazz.superClass = clazz.loader.loadClass(clazz.superClassName); } } //加载当前类的接口类 private void resolveInterfaces(Zclass clazz) { int count = clazz.interfaceNames.length; clazz.interfaces = new Zclass[count]; for (int i = 0; i < count; i++) { clazz.interfaces[i] = clazz.loader.loadClass(clazz.interfaceNames[i]); } } private void link(Zclass clazz) { verify(clazz); prepare(clazz); } //在执行类的任何代码之前要对类进行严格的检验,这里忽略检验过程,作为空实现; private void verify(Zclass clazz) { } //给类变量分配空间并赋予初始值 private void prepare(Zclass clazz) { calcInstanceFieldSlotIds(clazz); calcStaticFieldSlotIds(clazz); allocAndInitStaticVars(clazz); } // 计算new一个对象所需的空间,单位是clazz.instanceSlotCount,主要包含了类的非静态成员变量(包含父类的) // 但是这里并没有真正的申请空间,只是计算大小,同时为每个非静态变量关联 slotId private void calcInstanceFieldSlotIds(Zclass clazz) { int slotId = 0; if (clazz.superClass != null) { slotId = clazz.superClass.instanceSlotCount; } for (Zfield field : clazz.fileds) { if (!field.isStatic()) { field.slotId = slotId; slotId++; if (field.isLongOrDouble()) { slotId++; } } } clazz.instanceSlotCount = slotId; } //计算类的静态成员变量所需的空间,不包含父类,同样也只是计算和分配 slotId,不申请空间 private void calcStaticFieldSlotIds(Zclass clazz) { int slotId = 0; for (Zfield field : clazz.fileds) { if (field.isStatic()) { field.slotId = slotId; slotId++; if (field.isLongOrDouble()) { slotId++; } } } clazz.staticSlotCount = slotId; } // 为静态变量申请空间,注意:这个申请空间的过程,就是将所有的静态变量赋值为0或者null; // 如果是 static final 的基本类型或者 String,其值会保存在ConstantValueAttribute属性中 private void allocAndInitStaticVars(Zclass clazz) { clazz.staticVars = new Slots(clazz.staticSlotCount); for (Zfield field : clazz.fileds) { if (field.isStatic() && field.isFinal()) { initStaticFinalVar(clazz, field); } } } // 为static final 修饰的成员赋值,这种类型的成员是ConstantXXXInfo类型的,该info中包含真正的值; private void initStaticFinalVar(Zclass clazz, Zfield zfield) { Slots staticVars = clazz.staticVars; RuntimeConstantPool runtimeConstantPool = clazz.getRuntimeConstantPool(); int index = zfield.constValueIndex; int slotId = zfield.slotId; if (index > 0) { switch (zfield.getDescriptor()) { case "Z": case "B": case "C": case "S": case "I": int intValue = (int) runtimeConstantPool.getRuntimeConstant(index).getValue(); staticVars.setInt(slotId, intValue); break; case "J": long longValue = (long) runtimeConstantPool.getRuntimeConstant(index).getValue(); staticVars.setLong(slotId, longValue); break; case "F": float floatValue = (float) runtimeConstantPool.getRuntimeConstant(index).getValue(); staticVars.setFloat(slotId, floatValue); break; case "D": double doubleValue = (double) runtimeConstantPool.getRuntimeConstant(index).getValue(); staticVars.setDouble(slotId, doubleValue); break; case "Ljava/lang/String;": String stringValue = (String) runtimeConstantPool.getRuntimeConstant(index).getValue(); Zobject jStr = StringPool.jString(clazz.getLoader(), stringValue); default: break; } } } } ================================================ FILE: Java/src/runtimedata/heap/Zfield.java ================================================ package runtimedata.heap; import classfile.attribute.ConstantValueAttribute; import classfile.MemberInfo; /** * Author: zhangxin * Time: 2017/5/19 0019. * Desc: 字段的抽象,是在class中定义的字段,包括静态的和非静态的 */ public class Zfield extends ClassMember { //运行时常量池中的索引,该属性只有在static final成员有初值的情况下才有; int constValueIndex; //类中字段数组slots中的的索引;其赋值在首次加载 class 文件后,为其分配的 slotId //如果是静态字段,该 slotId 表示的是在 Class 中staticVars数组中的索引 //如果是非静态字段,该 slotId 表示的是在 Object 中 fields 数组中的索引 int slotId; private Zfield(Zclass clazz, MemberInfo classFileField) { super(clazz, classFileField); copyAttributes(classFileField); } public static Zfield[] makeFields(Zclass zclass, MemberInfo[] cfFields) { Zfield[] fields = new Zfield[cfFields.length]; for (int i = 0; i < fields.length; i++) { Zfield field = new Zfield(zclass, cfFields[i]); fields[i] = field; } return fields; } public void copyAttributes(MemberInfo classFileField) { ConstantValueAttribute constantValueAttribute = classFileField.getConstantValueAttribute(); if (constantValueAttribute != null) { constValueIndex = constantValueAttribute.getConstantValueIndex(); } } public boolean isVolatile() { return 0 != (accessFlags & AccessFlag.ACC_VOLATILE); } public boolean isTransient() { return 0 != (accessFlags & AccessFlag.ACC_TRANSIENT); } public boolean isEnum() { return 0 != (accessFlags & AccessFlag.ACC_ENUM); } public int getConstValueIndex() { return constValueIndex; } public int getSlotId() { return slotId; } public boolean isLongOrDouble() { return getDescriptor().equals("J") || getDescriptor().equals("D"); } } ================================================ FILE: Java/src/runtimedata/heap/Zmethod.java ================================================ package runtimedata.heap; import classfile.MemberInfo; import classfile.attribute.CodeAttribute; import classfile.attribute.ExceptionsAttribute; import classfile.attribute.LineNumberTableAttribute; import java.util.ArrayList; /** * Author: zhangxin * Time: 2017/5/19 0019. * Desc: 方法的抽象,是在class中定义的方法,包括静态的和非静态的 */ public class Zmethod extends ClassMember { private int maxStack; private int maxLocals; private byte[] code; //如果没有code属性,取值为null;不过就算是空方法也有一个return 语句; private ExceptionTable exceptionTable; private LineNumberTableAttribute lineNumberTable; private ExceptionsAttribute exceptions; //由方法声明中显式throws显示的异常 private MethodDescriptor parsedDescriptor; //解析后的方法描述符 private int argSlotCount; //方法所需的参数个数;对于非静态方法,至少是1个(this) private Zmethod(Zclass clazz, MemberInfo classFileMethod) { super(clazz, classFileMethod); copyAttributes(classFileMethod); parsedDescriptor = new MethodDescriptor(this.descriptor); argSlotCount = calcArgSlotCount(parsedDescriptor.getParameterTypes()); if (isNative()) { injectCodeAttribute(parsedDescriptor.getReturnType()); } } //该方法用来初始化成员变量:maxStack,maxLocals,code,如果是 native 方法,是没有任何 code 字节码的; private void copyAttributes(MemberInfo classFileMethod) { CodeAttribute codeAttribute = classFileMethod.getCodeAttribute(); if (codeAttribute != null) { maxStack = codeAttribute.getMaxStack(); maxLocals = codeAttribute.getMaxLocals(); code = codeAttribute.getCode(); lineNumberTable = codeAttribute.lineNumberTableAttribute(); //这一步主要是将classFile中的异常处理表(符号引用),转换为运行时的异常处理表(直接引用);主要在于catchType的转换 exceptionTable = new ExceptionTable(codeAttribute.getExceptionTable(), clazz.getRuntimeConstantPool()); } exceptions = classFileMethod.getExceptionsAttribute(); } private int calcArgSlotCount(ArrayList args) { int slotCount = 0; //如果当前方法不是静态方法,那么其第一个参数为 ‘this’引用 if (!isStatic()) { slotCount++; } for (String arg : args) { slotCount++; if ("J".equals(arg) || "D".equals(arg)) { slotCount++; } } return slotCount; } // JVM 并没有规定如何实现和调用本地方法,这里我们依然使用 JVM 栈 来执行本地方法 // 但是本地方法中并不包含字节码,那么本地方法的调用,这里我们利用接口来实现调用对应的方法; // 同时 JVM 中预留了两条指令,操作码分别是 0xff 和 0xfe,下面使用 0xfe 来当前方法为表示本地方法 // 第二个字节为本地方法的返回指令,该指令和普通方法的返回指令是一样的。 private void injectCodeAttribute(String returnType) { //本地方法的操作数栈暂时为4;至少能容纳返回值 this.maxStack = 4; //本地方法的局部变量表只用来存放参数,因此直接这样赋值 this.maxLocals = this.argSlotCount; //接下来为本地方法构造字节码:起始第一个字节都是0xfe,用来表用这是本地方法; //第二个字节码则根据不同的返回值类型选择相应的xreturn的指令即可 //不必担心下面的 byte 的强转,因为在读取字节码时,使用的是 readUint8()方法 switch (returnType.charAt(0)) { case 'V': this.code = new byte[]{(byte) 0xfe, (byte) 0xb1}; // return break; case 'L': case '[': this.code = new byte[]{(byte) 0xfe, (byte) 0xb0}; // areturn break; case 'D': this.code = new byte[]{(byte) 0xfe, (byte) 0xaf}; // dreturn break; case 'F': this.code = new byte[]{(byte) 0xfe, (byte) 0xae}; // freturn break; case 'J': this.code = new byte[]{(byte) 0xfe, (byte) 0xad}; // lreturn break; default: this.code = new byte[]{(byte) 0xfe, (byte) 0xac};// ireturn } } public static Zmethod[] makeMethods(Zclass zclass, MemberInfo[] classFileMethods) { Zmethod[] methods = new Zmethod[classFileMethods.length]; for (int i = 0; i < methods.length; i++) { Zmethod method = new Zmethod(zclass, classFileMethods[i]); methods[i] = method; } return methods; } public boolean isSynchronized() { return 0 != (accessFlags & AccessFlag.ACC_SYNCHRONIZED); } public boolean isBridge() { return 0 != (accessFlags & AccessFlag.ACC_BRIDGE); } public boolean isVarargs() { return 0 != (accessFlags & AccessFlag.ACC_VARARGS); } public boolean isNative() { return 0 != (accessFlags & AccessFlag.ACC_NATIVE); } public boolean isAbstract() { return 0 != (accessFlags & AccessFlag.ACC_ABSTRACT); } public boolean isStrict() { return 0 != (accessFlags & AccessFlag.ACC_STRICT); } public int getMaxStack() { return maxStack; } public int getMaxLocals() { return maxLocals; } public byte[] getCode() { return code; } public int getArgSlotCount() { return argSlotCount; } //搜索自身方法的异常处理表,如果能找到对应的异常处理项,则返回其handlerPC字段(指出负责异常处理的catch块的位置),否则返回-1 public int findExceptionHandler(Zclass exClazz, int pc) { ExceptionHandler handler = exceptionTable.findExceptionHandler(exClazz, pc); if (handler != null) { return handler.handlerPc; } return -1; } public Zclass[] getExceptionTypes() { if (this.exceptions == null) { return new Zclass[0]; } int[] exceptionIndexTable = exceptions.getExceptionIndexTable(); Zclass[] exClasses = new Zclass[exceptionIndexTable.length]; RuntimeConstantPool runtimeConstantPool = clazz.getRuntimeConstantPool(); for (int i = 0; i < exceptionIndexTable.length; i++) { ClassRef classRef = (ClassRef) runtimeConstantPool.getRuntimeConstant(exceptionIndexTable[i]).getValue(); exClasses[i] = classRef.resolvedClass(); } return exClasses; } public int getLineNumber(int pc) { if (isNative()) { return -2; } if (lineNumberTable == null) { return -1; } return lineNumberTable.getLineNumber(pc); } } ================================================ FILE: Java/src/runtimedata/heap/Zobject.java ================================================ package runtimedata.heap; import runtimedata.Slots; /** * Author: zhangxin * Time: 2017/5/4 0004. * Desc: 用来模拟Java中的Object类,这里只是简单的模拟定义一个类,用来盛放索引的 */ public class Zobject { //存放一个class的成员,用来调用类的方法,静态成员变量 private Zclass clazz; //存放的是非静态成员变量,包含父类+ 自己的;或者存放数组 private Object data; // 该Object不仅作为普通对象的一个存在,同时也作为每个Class结构对应的object,该Class对象需要的额外信息保存在extra中 // 最简单的其可以用来记录类对象对应的Class结构体指针;(目前来看只有元类对象才会设置该 extra 字段) public Object extra; public Zobject(Zclass clazz) { this.clazz = clazz; data = new Slots(clazz.instanceSlotCount); } public Zobject(Zclass clazz, Object data, Object extra) { this.clazz = clazz; this.data = data; this.extra = extra; } public Slots getFields() { return (Slots) data; } public Zclass getClazz() { return clazz; } // 判断当前类是都是否是 target 的子类 public boolean isInstanceOf(Zclass target) { return target.isAssignableFrom(this.clazz); } //为数组添加一些特有的方法: public byte[] getBytes() { return (byte[]) data; } public char[] getChars() { return (char[]) data; } public short[] getShorts() { return (short[]) data; } public int[] getInts() { return (int[]) data; } public long[] getLongs() { return (long[]) data; } public float[] getFloats() { return (float[]) data; } public double[] getDoubles() { return (double[]) data; } public Zobject[] getRefs() { return (Zobject[]) data; } public int getArrayLen() { switch (data.getClass().getSimpleName()) { case "byte[]": return getBytes().length; case "short[]": return getShorts().length; case "char[]": return getChars().length; case "int[]": return getInts().length; case "long[]": return getLongs().length; case "float[]": return getFloats().length; case "double[]": return getDoubles().length; case "Zobject[]": return getRefs().length; default: throw new RuntimeException("called length on a none array object!"); } } // reflection,只实现了 int 和 ref,double 和 float 没有实现; public Zobject getRefVar(String name, String descriptor) { Zfield field = clazz.getField(name, descriptor, false); Slots slots = (Slots) data; return slots.getRef(field.slotId); } public void setRefVar(String name, String descriptor, Zobject ref) { Zfield field = clazz.getField(name, descriptor, false); Slots slots = (Slots) data; slots.setRef(field.slotId, ref); } public int getIntVar(String name, String descriptor) { Zfield field = clazz.getField(name, descriptor, false); Slots slots = (Slots) data; return slots.getInt(field.slotId); } public void setIntVar(String name, String descriptor, int val) { Zfield field = clazz.getField(name, descriptor, false); Slots slots = (Slots) data; slots.setInt(field.slotId, val); } public long getLongVar(String name, String descriptor) { Zfield field = clazz.getField(name, descriptor, false); Slots slots = (Slots) data; return slots.getLong(field.slotId); } public void setLongVar(String name, String descriptor, long val) { Zfield field = clazz.getField(name, descriptor, false); Slots slots = (Slots) data; slots.setLong(field.slotId, val); } public float getFloatVar(String name, String descriptor) { Zfield field = clazz.getField(name, descriptor, false); Slots slots = (Slots) data; return slots.getFloat(field.slotId); } public void setFloatVar(String name, String descriptor, float val) { Zfield field = clazz.getField(name, descriptor, false); Slots slots = (Slots) data; slots.setFloat(field.slotId, val); } public double getDoubleVar(String name, String descriptor) { Zfield field = clazz.getField(name, descriptor, false); Slots slots = (Slots) data; return slots.getDouble(field.slotId); } public void setDoubleVar(String name, String descriptor, double val) { Zfield field = clazz.getField(name, descriptor, false); Slots slots = (Slots) data; slots.setDouble(field.slotId, val); } } ================================================ FILE: Java/src/test/TestClassFile03.java ================================================ package test; import Utils.Cmd; import classfile.ClassFile; import classfile.MemberInfo; import classfile.attribute.AttributeInfo; import classpath.ClassPath; import java.util.Scanner; /** * @author zhangxin * @date 2017/12/23 0023 * testcase as flow: * (1)java java.lang.String * (2)java -cp C:\Users\zhangxin\Desktop Hello */ public class TestClassFile03 { public static void main(String[] args) { Scanner in = new Scanner(System.in); String cmdLine = in.nextLine(); String[] cmds = cmdLine.split("\\s+"); Cmd cmd = new Cmd(cmds); ClassPath classPath = new ClassPath(cmd.getXJreOption(), cmd.getCpOption()); byte[] classData = classPath.readClass(cmd.getClazz()); ClassFile classFile = new ClassFile(classData); System.out.println("classFile.getMajorVersion: " + classFile.getMajorVersion()); System.out.println("classFile.getMinorVersion: " + classFile.getMinorVersion()); System.out.println("classFile.getAccessFlags: " + classFile.getAccessFlags()); System.out.println("classFile.getClassName: " + classFile.getClassName()); System.out.println("classFile.getSuperClassName: " + classFile.getSuperClassName()); System.out.println("interface names:"); for (String name : classFile.getInterfaceNames()) { System.out.println(name); } System.out.println("---------------------"); System.out.println("field count: " + classFile.getFields().length); for (MemberInfo name : classFile.getFields()) { System.out.println(name.getName()); } System.out.println("---------------------"); System.out.println("method count: " + classFile.getMethods().length); for (MemberInfo name : classFile.getMethods()) { System.out.println(name.getName() + ":" + name.getDescriptor()); } System.out.println("---------------------"); System.out.println("constantPool count: "+classFile.getConstantPool().getConstantPoolCount()); System.out.println("---------------------"); System.out.println("attribute count:"+classFile.getAttributes().length); for (AttributeInfo attribute:classFile.getAttributes()){ System.out.println(attribute.getClass()); } } } ================================================ FILE: Java/src/test/TestClassLoader07.java ================================================ package test; import Utils.Cmd; import classpath.ClassPath; import instructions.InstructionFactory; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.Zclass; import runtimedata.heap.ZclassLoader; import runtimedata.heap.Zmethod; import java.util.Scanner; /** * @author zachaxy * @date 17/12/26 */ public class TestClassLoader07 { public static void main(String[] args) { System.out.println("the same as testInterpreter06!"); Scanner in = new Scanner(System.in); // java -cp /Users/zachaxy TestClassLoader7 String cmdLine = in.nextLine(); String[] cmds = cmdLine.split("\\s+"); Cmd cmd = new Cmd(cmds); ClassPath classPath = new ClassPath(cmd.getXJreOption(), cmd.getCpOption()); ZclassLoader classLoader = new ZclassLoader(classPath); Zclass testClass = classLoader.loadClass(cmd.getClazz()); Zmethod testMethod = testClass.getMethod("test", "()I"); if (testMethod != null) { Zthread thread = new Zthread(); Zframe frame = thread.createFrame(testMethod); //start loop BytecodeReader reader = new BytecodeReader(); byte[] byteCode = testMethod.getCode(); while (true) { int pc = frame.getNextPC(); //这第一次frame才刚初始化,获取的pc应该是默认值0吧。 thread.setPc(pc); reader.reset(byteCode, pc); //reset方法,其实是在不断的设置pc的位置。 int opCode = reader.readUint8(); //解析指令,创建指令,然后根据不同的指令执行不同的操作 try { Instruction instruction = InstructionFactory.createInstruction(opCode); instruction.fetchOperands(reader); frame.setNextPC(reader.getPc()); instruction.execute(frame); System.out.println("current instruction: " + instruction.getClass().getSimpleName()); } catch (Exception e) { e.printStackTrace(); if (!frame.getOperandStack().isEmpty()) { int returnVar = frame.getOperandStack().popInt(); System.out.println("return: " + returnVar); } return; } } } else { System.out.println("can't find testMethod!!!"); } } public static int staticVar; public int instanceVar; public static int test() { // ldc int x = 31415; //new TestClassLoader07 test = new TestClassLoader07(); //putstatic TestClassLoader07.staticVar = x; //getstatic x = TestClassLoader07.staticVar; //putfield test.instanceVar = x; //getfield x = test.instanceVar; Object obj = test; //instanceof if (obj instanceof TestClassLoader07) { // checkcast test = (TestClassLoader07) obj; System.out.println(test.instanceVar); } return x; } } ================================================ FILE: Java/src/test/TestClassPath02.java ================================================ package test; import Utils.Cmd; import classpath.ClassPath; import java.util.Scanner; /** * @author zhangxin * @date 2017/12/23 0023 * testcase as flow: * (1)java -cp C:\Users\zhangxin\Desktop Hello * (2)java java.lang.Object * for the first test case,you must confirm there is a Hello.class in your desktop * for the second test case,we just load the Object.class in your JAVA_HOME/jre/lib/rt.jar */ public class TestClassPath02 { public static void main(String[] args) { System.out.println("Usage: java [-options] class [args...]"); System.out.println("Specially,we don't support the path that contains space!"); Scanner in = new Scanner(System.in); String cmdLine = in.nextLine(); String[] cmds = cmdLine.split("\\s+"); Cmd cmd = new Cmd(cmds); if (!cmd.isRightFmt()) { System.out.println("Unrecognized command!"); cmd.printUsage(); } else if (!cmd.isRightOpt()) { System.out.println("Unrecognized option: " + cmds[1]); cmd.printUsage(); } else { if (cmd.isVersionFlag()) { System.out.println("java version \"1.8.0_20\"\n" + "Java(TM) SE Runtime Environment (build 1.8.0_20-b26)\n" + "Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)"); } else if (cmd.isHelpFlag()) { cmd.printUsage(); } else { System.out.println("cmd pared successful!"); ClassPath classPath = new ClassPath(cmd.getXJreOption(), cmd.getCpOption()); byte[] classData = classPath.readClass(cmd.getClazz()); int len = classData.length; System.out.println("the length of file is: " + len); for (int i = 0; i < len; i++) { if (i % 20 == 0) { System.out.println(); } System.out.printf("%04X ", classData[i], 16); } } } } } ================================================ FILE: Java/src/test/TestCmd01.java ================================================ package test; import Utils.Cmd; import java.util.Scanner; /** * @author zhangxin * @date 2017/12/22 0022 */ public class TestCmd01 { public static void main(String[] args) { System.out.println("Usage: java [-options] class [args...]"); System.out.println("Specially,we don't support the path that contains space!"); Scanner in = new Scanner(System.in); String cmdLine = in.nextLine(); String[] cmds = cmdLine.split("\\s+"); Cmd cmd = new Cmd(cmds); if (!cmd.isRightFmt()) { System.out.println("Unrecognized command!"); cmd.printUsage(); } else if(!cmd.isRightOpt()){ System.out.println("Unrecognized option: "+cmds[1]); cmd.printUsage(); }else { if (cmd.isVersionFlag()) { System.out.println("java version \"1.8.0_20\"\n" + "Java(TM) SE Runtime Environment (build 1.8.0_20-b26)\n" + "Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)"); } else if (cmd.isHelpFlag()) { cmd.printUsage(); } else { System.out.println("cmd pared successful!"); for (int i = 0; i < cmd.getArgs().length; i++) { System.out.println(cmd.getArgs()[i]); } } } } } ================================================ FILE: Java/src/test/TestException12.java ================================================ package test; import Utils.Cmd; import classpath.ClassPath; import instructions.InstructionFactory; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.*; import znative.RegisterCenter; import java.util.Scanner; /** * @author zachaxy * @date 18/1/3 */ public class TestException12 { public static void main(String[] args) { System.out.println("the same as testInterpreter06!"); Scanner in = new Scanner(System.in); // java -cp /Users/zachaxy/TestClassFiles TestException12 String cmdLine = in.nextLine(); Cmd cmd = new Cmd(cmdLine); RegisterCenter.init(); ClassPath classPath = new ClassPath(cmd.getXJreOption(), cmd.getCpOption()); ZclassLoader classLoader = new ZclassLoader(classPath); Zclass testClass = classLoader.loadClass(cmd.getClazz()); Zmethod testMethod = testClass.getMethod("test", "()V"); //初始化栈帧 Zthread thread = new Zthread(); Zframe frame = thread.createFrame(testMethod); Zframe outFrame = frame; thread.pushFrame(frame); BytecodeReader reader = new BytecodeReader(); while (true) { frame = thread.getCurrentFrame(); int pc = frame.getNextPC(); thread.setPc(pc); //decode reader.reset(frame.getMethod().getCode(), pc); int opCode = reader.readUint8(); //解析指令,创建指令,然后根据不同的指令执行不同的操作 try { Instruction instruction = InstructionFactory.createInstruction(opCode); instruction.fetchOperands(reader); frame.setNextPC(reader.getPc()); instruction.execute(frame); if (frame == outFrame) { System.out.println("current instruction: " + pc + ": " + instruction.getClass().getSimpleName()); } if (thread.isStackEmpty()) { if (!frame.getOperandStack().isEmpty()) { System.out.println("return: " + frame.getOperandStack().popInt()); } break; } } catch (Exception e) { e.printStackTrace(); //return; } } int i = outFrame.getLocalVars().getInt(0); System.out.println(i); } public static void test() { int i = 100; try { f1(); } catch (NumberFormatException e) { i = 200; } } public static void f1() { throw new IndexOutOfBoundsException(); } } ================================================ FILE: Java/src/test/TestGetClass11.java ================================================ package test; import Utils.Cmd; import classpath.ClassPath; import instructions.InstructionFactory; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.*; import znative.RegisterCenter; import java.util.Scanner; /** * @author zachaxy * @date 18/1/2 */ public class TestGetClass11 { public static void main(String[] args) { System.out.println("the same as testInterpreter06!"); Scanner in = new Scanner(System.in); // java -cp /Users/zachaxy/TestClassFiles TestGetClass11 String cmdLine = in.nextLine(); Cmd cmd = new Cmd(cmdLine); RegisterCenter.init(); ClassPath classPath = new ClassPath(cmd.getXJreOption(), cmd.getCpOption()); ZclassLoader classLoader = new ZclassLoader(classPath); Zclass testClass = classLoader.loadClass(cmd.getClazz()); Zmethod testMethod = testClass.getMethod("test", "()V"); //初始化栈帧 Zthread thread = new Zthread(); Zframe frame = thread.createFrame(testMethod); Zframe outFrame = frame; thread.pushFrame(frame); BytecodeReader reader = new BytecodeReader(); while (true) { frame = thread.getCurrentFrame(); int pc = frame.getNextPC(); thread.setPc(pc); //decode reader.reset(frame.getMethod().getCode(), pc); int opCode = reader.readUint8(); //解析指令,创建指令,然后根据不同的指令执行不同的操作 try { Instruction instruction = InstructionFactory.createInstruction(opCode); instruction.fetchOperands(reader); frame.setNextPC(reader.getPc()); instruction.execute(frame); if (frame == outFrame) { System.out.println("current instruction: " + pc + ": " + instruction.getClass().getSimpleName()); } if (thread.isStackEmpty()) { if (!frame.getOperandStack().isEmpty()) { System.out.println("return: " + frame.getOperandStack().popInt()); } break; } } catch (Exception e) { e.printStackTrace(); //return; } } Zobject ref = outFrame.getLocalVars().getRef(0); System.out.println(StringPool.realString(ref)); } public static void test() { // String s1 = int.class.getName(); // String s1 = void.class.getName(); // String s1 = double.class.getName(); String s1 = int[].class.getName(); // String s1 = "abc".getClass().getName(); } } ================================================ FILE: Java/src/test/TestInterpreter06.java ================================================ package test; import Utils.Cmd; import classfile.ClassFile; import classfile.MemberInfo; import classfile.attribute.CodeAttribute; import classpath.ClassPath; import instructions.InstructionFactory; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; import runtimedata.Zthread; import java.util.Scanner; /** * @author zachaxy * @date 17/12/25 */ public class TestInterpreter06 { public static void main(String[] args) { System.out.println("simply test a java method as 'public static void test()' in this class"); System.out.println("the test class file--'TestInterpreter06.class' as you see in the src/test dir"); System.out.println("ues 'java -cp your/path TestInterpreter06'"); System.out.println("your/path means the path where you place the 'TestInterpreter06.class'"); System.out.println("I beg you to place the 'TestInterpreter06.class' file in your desktop or other dir "); System.out.println("but not in the current project path!!!"); Scanner in = new Scanner(System.in); String cmdLine = in.nextLine(); String[] cmds = cmdLine.split("\\s+"); Cmd cmd = new Cmd(cmds); ClassPath classPath = new ClassPath(cmd.getXJreOption(), cmd.getCpOption()); byte[] classData = classPath.readClass(cmd.getClazz()); ClassFile classFile = new ClassFile(classData); MemberInfo[] methods = classFile.getMethods(); MemberInfo targetMethod = null; for (MemberInfo method : methods) { if (method.getName().equals("test") && method.getDescriptor().equals("()I")) { targetMethod = method; break; } } if (targetMethod != null) { //拿到Code属性,主要是拿到其中的字节码用来测试之间创建的指令是否有效 CodeAttribute codeAttribute = targetMethod.getCodeAttribute(); //获得执行方法所需的局部变量表和操作数栈空间 int maxLocals = codeAttribute.getMaxLocals(); int maxStack = codeAttribute.getMaxStack(); //拿到code的字节码; byte[] byteCode = codeAttribute.getCode(); //创建一个线程 Zthread thread = new Zthread(); //该线程中创建一帧 Zframe frame = thread.createFrame(maxLocals, maxStack); //把该帧push到虚拟机栈中,这时候虚拟机栈中已经有一帧了 //thead.pushFrame(frame); BytecodeReader reader = new BytecodeReader(); //这里循环的条件是true,因为在调用下面的 test 方法时,会遇到return,而现在还没有实现return // 目前遇到为能解析的指令,会抛出异常,那么循环也就终止了,此时查看其操作数栈,观察结果 while (true) { int pc = frame.getNextPC(); //这第一次frame才刚初始化,获取的pc应该是默认值0吧。 thread.setPc(pc); reader.reset(byteCode, pc); //reset方法,其实是在不断的设置pc的位置。 int opCode = reader.readUint8(); //解析指令,创建指令,然后根据不同的指令执行不同的操作 try { Instruction instruction = InstructionFactory.createInstruction(opCode); instruction.fetchOperands(reader); frame.setNextPC(reader.getPc()); instruction.execute(frame); } catch (Exception e) { System.out.print("return:"); System.out.println(frame.getOperandStack().popInt()); return; } } }else{ System.out.println("can't load test method"); } } public static int test() { int sum = 0; for (int i = 0; i < 100; i++) { sum += i; } return sum; } } ================================================ FILE: Java/src/test/TestInvokeMethod08.java ================================================ package test; import Utils.Cmd; import classpath.ClassPath; import instructions.InstructionFactory; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.Zclass; import runtimedata.heap.ZclassLoader; import runtimedata.heap.Zmethod; import java.util.Scanner; /** * @author zachaxy * @date 17/12/27 */ public class TestInvokeMethod08 implements Runnable { public static void main(String[] args) { System.out.println("the same as testInterpreter06!"); Scanner in = new Scanner(System.in); // java -cp /Users/zachaxy/TestClassFiles TestInvokeMethod08 String cmdLine = in.nextLine(); Cmd cmd = new Cmd(cmdLine); ClassPath classPath = new ClassPath(cmd.getXJreOption(), cmd.getCpOption()); ZclassLoader classLoader = new ZclassLoader(classPath); Zclass testClass = classLoader.loadClass(cmd.getClazz()); Zmethod testMethod = testClass.getMethod("test", "()I"); //初始化栈帧 Zthread thread = new Zthread(); //手动添加一帧,用来测试返回值;该帧 Zframe hackFrame = thread.createFrame(2, 2); thread.pushFrame(hackFrame); Zframe frame = thread.createFrame(testMethod); thread.pushFrame(frame); Zframe outFrame = frame; //解释器执行 BytecodeReader reader = new BytecodeReader(); while (true) { frame = thread.getCurrentFrame(); if (frame == hackFrame) { break; } int pc = frame.getNextPC(); thread.setPc(pc); //decode reader.reset(frame.getMethod().getCode(), pc); int opCode = reader.readUint8(); //解析指令,创建指令,然后根据不同的指令执行不同的操作 try { Instruction instruction = InstructionFactory.createInstruction(opCode); instruction.fetchOperands(reader); frame.setNextPC(reader.getPc()); instruction.execute(frame); if (thread.isStackEmpty()) { if (!frame.getOperandStack().isEmpty()) { System.out.println("return: " + frame.getOperandStack().popInt()); } break; } if (frame == outFrame) { System.out.println("current instruction: " + pc + ": " + instruction.getClass().getSimpleName()); } } catch (Exception e) { e.printStackTrace(); //return; } } if (!hackFrame.getOperandStack().isEmpty()) { int returnVar = hackFrame.getOperandStack().popInt(); System.out.println("return: " + returnVar); } } public static int test() { TestInvokeMethod08 test = new TestInvokeMethod08(); //new -> dup ->invokespecial test.instanceMethod(); //invokespecial test.equals(null); //invokespecial test.run(); //invokevirtual ((Runnable) test).run();//invokeinterface int i = staticMethod(5); //invokestatic return i; } public static int staticMethod(int n) { if (n <= 1) { return n; } return staticMethod(n - 1) + staticMethod(n - 2); } private void instanceMethod() { } @Override public void run() { } } ================================================ FILE: Java/src/test/TestLocalVars04.java ================================================ package test; import runtimedata.LocalVars; /** * @author zachaxy * @date 17/12/24 */ public class TestLocalVars04 { public static void main(String[] args) { LocalVars localVars = new LocalVars(10); localVars.setInt(0,100); localVars.setInt(1,-100); localVars.setLong(2,2997934580L); localVars.setLong(4,-2997934580L); localVars.setFloat(6,3.1415926f); localVars.setDouble(7,2.141592678912); System.out.println(localVars.getInt(0)); System.out.println(localVars.getInt(1)); System.out.println(localVars.getLong(2)); System.out.println(localVars.getLong(4)); System.out.println(localVars.getFloat(6)); System.out.println(localVars.getDouble(7)); } } ================================================ FILE: Java/src/test/TestNewArray09.java ================================================ package test; import Utils.Cmd; import classpath.ClassPath; import instructions.InstructionFactory; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.Zclass; import runtimedata.heap.ZclassLoader; import runtimedata.heap.Zmethod; import java.util.Scanner; /** * @author zachaxy * @date 17/12/30 */ public class TestNewArray09 { public static void main(String[] args) { System.out.println("the same as testInterpreter06!"); Scanner in = new Scanner(System.in); // java -cp /Users/zachaxy/TestClassFiles TestNewArray09 String cmdLine = in.nextLine(); Cmd cmd = new Cmd(cmdLine); ClassPath classPath = new ClassPath(cmd.getXJreOption(), cmd.getCpOption()); ZclassLoader classLoader = new ZclassLoader(classPath); Zclass testClass = classLoader.loadClass(cmd.getClazz()); Zmethod testMethod = testClass.getMethod("test", "()V"); //初始化栈帧 Zthread thread = new Zthread(); Zframe frame = thread.createFrame(testMethod); Zframe outFrame = frame; thread.pushFrame(frame); BytecodeReader reader = new BytecodeReader(); while (true) { frame = thread.getCurrentFrame(); int pc = frame.getNextPC(); thread.setPc(pc); //decode reader.reset(frame.getMethod().getCode(), pc); int opCode = reader.readUint8(); //解析指令,创建指令,然后根据不同的指令执行不同的操作 try { Instruction instruction = InstructionFactory.createInstruction(opCode); instruction.fetchOperands(reader); frame.setNextPC(reader.getPc()); instruction.execute(frame); if (frame == outFrame) { System.out.println("current instruction: " + pc + ": " + instruction.getClass().getSimpleName()); } if (thread.isStackEmpty()) { if (!frame.getOperandStack().isEmpty()) { System.out.println("return: " + frame.getOperandStack().popInt()); } break; } } catch (Exception e) { e.printStackTrace(); //return; } } } public static void test() { int[] a1 = new int[10]; //newarray String[] a2 = new String[10]; //anewarray int[][] a3 = new int[10][10]; //multianewarray int x = a1.length; //arraylength a1[0] = 100; //iastore int y = a1[0]; //iaload //暂时还未实现字符串的 ldc,因此下面对字符串数组的赋值无法进行; // a2[0] = "abc"; //aastore // String s = a2[0]; //aaload } } ================================================ FILE: Java/src/test/TestOperandStack05.java ================================================ package test; import runtimedata.OperandStack; /** * @author zachaxy * @date 17/12/24 */ public class TestOperandStack05 { public static void main(String[] args) { OperandStack stack = new OperandStack(10); stack.pushInt(100); stack.pushInt(-100); stack.pushLong(2997934580L); stack.pushLong(-2997934580L); stack.pushFloat(3.1415925f); stack.pushDouble(2.141592678912); System.out.println(stack.popDouble()); System.out.println(stack.popFloat()); System.out.println(stack.popLong()); System.out.println(stack.popLong()); System.out.println(stack.popInt()); System.out.println(stack.popInt()); } } ================================================ FILE: Java/src/test/TestStringPool10.java ================================================ package test; import Utils.Cmd; import classpath.ClassPath; import instructions.InstructionFactory; import instructions.base.BytecodeReader; import instructions.base.Instruction; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.*; import java.util.Scanner; /** * @author zachaxy * @date 17/12/30 */ public class TestStringPool10 { public static void main(String[] args) { System.out.println("the same as testInterpreter06!"); Scanner in = new Scanner(System.in); // java -cp /Users/zachaxy/TestClassFiles TestStringPool10 String cmdLine = in.nextLine(); Cmd cmd = new Cmd(cmdLine); ClassPath classPath = new ClassPath(cmd.getXJreOption(), cmd.getCpOption()); ZclassLoader classLoader = new ZclassLoader(classPath); Zclass testClass = classLoader.loadClass(cmd.getClazz()); Zmethod testMethod = testClass.getMethod("test", "()V"); //初始化栈帧 Zthread thread = new Zthread(); Zframe frame = thread.createFrame(testMethod); Zframe outFrame = frame; thread.pushFrame(frame); BytecodeReader reader = new BytecodeReader(); while (true) { frame = thread.getCurrentFrame(); int pc = frame.getNextPC(); thread.setPc(pc); //decode reader.reset(frame.getMethod().getCode(), pc); int opCode = reader.readUint8(); //解析指令,创建指令,然后根据不同的指令执行不同的操作 try { Instruction instruction = InstructionFactory.createInstruction(opCode); instruction.fetchOperands(reader); frame.setNextPC(reader.getPc()); instruction.execute(frame); if (frame == outFrame) { System.out.println("current instruction: " + pc + ": " + instruction.getClass().getSimpleName()); } if (thread.isStackEmpty()) { if (!frame.getOperandStack().isEmpty()) { System.out.println("return: " + frame.getOperandStack().popInt()); } break; } } catch (Exception e) { e.printStackTrace(); //return; } } Zobject ref = outFrame.getLocalVars().getRef(2); System.out.println(StringPool.realString(ref)); } public static void test() { String s1 = "hello"; String s2 = "hello";//new String("hello");不支持 new String 的方式,会报错! String s3; if (s1 == s2) { s3 = "yes"; } else { s3 = "no"; } } } ================================================ FILE: Java/src/znative/NativeMethod.java ================================================ package znative; import runtimedata.Zframe; /** * @author zachaxy * @date 17/12/31 * native native方法统一实现的接口 */ public interface NativeMethod { public void run(Zframe frame); } ================================================ FILE: Java/src/znative/RegisterCenter.java ================================================ package znative; import runtimedata.Zframe; import znative.java.lang.Nclass; import znative.java.lang.Nobject; import znative.java.lang.Nthrowable; import java.util.HashMap; /** * @author zachaxy * @date 17/12/31 * desc:native 方法注册中心,所有的 native 方法都要在注册中心进行注册 */ public class RegisterCenter { private static HashMap nativeMethods = new HashMap<>(); public static void register(String className, String methodName, String methodDescriptor, NativeMethod nativeMethod) { String key = className + "~" + methodName + "~" + methodDescriptor; nativeMethods.put(key, nativeMethod); } public static NativeMethod findNativeMethod(String className, String methodName, String methodDescriptor) { String key = className + "~" + methodName + "~" + methodDescriptor; if (nativeMethods.containsKey(key)) { return nativeMethods.get(key); } if ("()V".equals(methodDescriptor)) { if ("registerNatives".equals(methodName) || "initIDs".equals(methodName)) { //返回一个空的方法执行体 emptyNativeMethod return new NativeMethod() { @Override public void run(Zframe frame) { } }; } } return null; } //对外供 JVM 启动后的唯一接入口,JVM 启动后应该立即调用 RegisterCenter 的 init 方法 public static void init() { register("java/lang/Object", "getClass", "()Ljava/lang/Class;", new Nobject.getClass()); register("java/lang/Class", "getPrimitiveClass", "(Ljava/lang/String;)Ljava/lang/Class;", new Nclass.getPrimitiveClass()); register("java/lang/Class", "getName0", "()Ljava/lang/String;", new Nclass.getName0()); register("java/lang/Class", "desiredAssertionStatus0", "(Ljava/lang/Class;)Z", new Nclass.desiredAssertionStatus0()); register("java/lang/Class", "isArray", "()Z", new Nclass.isArray()); /* register("java/lang/Class", "isInterface", "()Z", new Nclass.isInterface()) register("java/lang/Class", "isPrimitive", "()Z", new Nclass.isPrimitive()) register("java/lang/Class", "getDeclaredFields0", "(Z)[Ljava/lang/reflect/Field;", new Nclass.getDeclaredFields0()) register("java/lang/Class", "forName0", "(Ljava/lang/String;ZLjava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/Class;", new Nclass.forName0()) register("java/lang/Class", "getDeclaredConstructors0", "(Z)[Ljava/lang/reflect/Constructor;", new Nclass.getDeclaredConstructors0()) register("java/lang/Class", "getModifiers", "()I", new Nclass.getModifiers()) register("java/lang/Class", "getSuperclass", "()Ljava/lang/Class;", new Nclass.getSuperclass()) register("java/lang/Class", "getInterfaces0", "()[Ljava/lang/Class;", new Nclass.getInterfaces0()) register("java/lang/Class", "getDeclaredMethods0", "(Z)[Ljava/lang/reflect/Method;", new Nclass.getDeclaredMethods0()) register("java/lang/Class", "getComponentType", "()Ljava/lang/Class;", new Nclass.getComponentType()) register("java/lang/Class", "isAssignableFrom", "(Ljava/lang/Class;)Z", new Nclass.isAssignableFrom()) */ register("java/lang/Throwable", "fillInStackTrace", "(I)Ljava/lang/Throwable;", new Nthrowable.fillInStackTrace()); } } ================================================ FILE: Java/src/znative/java/lang/NStackTraceElement.java ================================================ package znative.java.lang; /** * @author zachaxy * @date 18/1/3 * desc:虚拟机栈信息 */ public class NStackTraceElement { String fileName;//类所在的java文件 String className;//声明方法的类名 String methodName;//调用方法名 int lineNumber;//出现exception的行号 public NStackTraceElement(String fileName, String className, String methodName, int lineNumber) { this.fileName = fileName; this.className = className; this.methodName = methodName; this.lineNumber = lineNumber; } @Override public String toString() { return className + "." + methodName + "(" + fileName + ":" + lineNumber + ")"; } } ================================================ FILE: Java/src/znative/java/lang/Nclass.java ================================================ package znative.java.lang; import runtimedata.Zframe; import runtimedata.heap.StringPool; import runtimedata.heap.Zclass; import runtimedata.heap.ZclassLoader; import runtimedata.heap.Zobject; import znative.NativeMethod; /** * @author zachaxy * @date 18/1/2 */ public class Nclass { // static native Class getPrimitiveClass(String name); // (Ljava/lang/String;)Ljava/lang/Class; // 该方法是获取基本类型的类对象; public static class getPrimitiveClass implements NativeMethod { @Override public void run(Zframe frame) { Zobject nameObj = frame.getLocalVars().getRef(0); String name = StringPool.realString(nameObj); ZclassLoader classLoader = frame.getMethod().getClazz().getLoader(); Zobject jObject = classLoader.loadClass(name).getjObject(); frame.getOperandStack().pushRef(jObject); } } public static class getName0 implements NativeMethod { @Override public void run(Zframe frame) { Zobject self = frame.getLocalVars().getRef(0); Zclass clazz = (Zclass) self.extra; String name = clazz.getJavaName(); Zobject nameObj = StringPool.jString(clazz.getLoader(), name); frame.getOperandStack().pushRef(nameObj); } } public static class desiredAssertionStatus0 implements NativeMethod { @Override public void run(Zframe frame) { frame.getOperandStack().pushBoolean(false); } } public static class isArray implements NativeMethod { @Override public void run(Zframe frame) { Zobject self = frame.getLocalVars().getRef(0); Zclass clazz = (Zclass) self.extra; frame.getOperandStack().pushBoolean(clazz.isArray()); } } } ================================================ FILE: Java/src/znative/java/lang/Nobject.java ================================================ package znative.java.lang; import runtimedata.Zframe; import runtimedata.heap.Zobject; import znative.NativeMethod; /** * @author zachaxy * @date 18/1/2 */ public class Nobject { // static native Class getPrimitiveClass(String name); // (Ljava/lang/String;)Ljava/lang/Class; //该方法是获取非基本类型的类对象; public static class getClass implements NativeMethod { @Override public void run(Zframe frame) { // 从局部变量表中获取非静态方法的实际的第一个参数——this Zobject self = frame.getLocalVars().getRef(0); Zobject jObject = self.getClazz().getjObject(); frame.getOperandStack().pushRef(jObject); } } } ================================================ FILE: Java/src/znative/java/lang/Nthrowable.java ================================================ package znative.java.lang; import runtimedata.Zframe; import runtimedata.Zthread; import runtimedata.heap.Zclass; import runtimedata.heap.Zmethod; import runtimedata.heap.Zobject; import znative.NativeMethod; /** * @author zachaxy * @date 18/1/2 */ public class Nthrowable { //这个方法是任何Exception的父类的构造方法中,调用的本地方法; public static class fillInStackTrace implements NativeMethod { @Override public void run(Zframe frame) { // throw创建的Exception实例; Zobject self = frame.getLocalVars().getRef(0); //将上面创建的Exception放到当前frame的操作数栈 frame.getOperandStack().pushRef(self); // Java 虚拟机栈信息 self.extra = createStackTraceElements(self, frame.getThread()); } //创建异常调用链,传入的第一个参数为throw 抛出的exception private NStackTraceElement[] createStackTraceElements(Zobject exObj, Zthread thread) { //不能直接从当前的frame开始记录,起码在栈顶的两帧正在执行fillInStackTrace(int)和fillInStackTrace()方法 //同时在这两帧的下面几帧正在执行Exception的构造方法,所以也需要跳过;具体跳过几帧,则由下面的distanceToObject方法来计算 int skip = distanceToObject(exObj.getClazz()) + 2; //拿栈帧,应该是拿前面的部分吧;怎么拿后面的部分?不是先入栈的在数组的前面吗? //问题出在GetFrames这个方法上,该方法使用stack的方式从栈顶逐渐拿的数据 //注意:本地变量表和操作数栈的底层是数组;而栈帧的底层是单向链表,不是数组!!! Zframe[] frames = thread.getFrames(); NStackTraceElement[] stes = new NStackTraceElement[frames.length - skip]; for (int i = skip; i < frames.length; i++) { stes[i - skip] = createStackTraceElement(frames[i]); } return stes; } private int distanceToObject(Zclass exClazz) { int distance = 0; //通过计算其继承层级来计算需要执行几个构造方法; for (Zclass c = exClazz.getSuperClass(); c != null; c = c.getSuperClass()) { distance++; } return distance; } //根据每一帧,拿到对应的消息; private NStackTraceElement createStackTraceElement(Zframe frame) { Zmethod method = frame.getMethod(); Zclass clazz = method.getClazz(); return new NStackTraceElement(clazz.getSourceFile(), clazz.getJavaName(), method.getName(), method.getLineNumber(frame.getNextPC() - 1)); } } } ================================================ FILE: README.md ================================================ 本项目是用 Java 实现了一个简易版本的 Java 虚拟机 ,重点在于了解 Java 虚拟机内部的工作原理。开发过程中的具体细节及所遇到的问题,都记录在我的博客[手写JVM系列](https://zachaxy.github.io/tags/JVM/)中。