案例介绍
本案例通过java代码实现jvm规范中指令集和解释器,完成后就可以开始执行1到100的加和计算。

Java虚拟机顾名思义,就是一台虚拟的机器,而字节码(bytecode)就是运行在这台虚拟机器上的机器码。我们已经知道,每一个类或者接口都会被Java编译器编译成一个class文件,类或接口的方法信息就放在class文件的method_info结构中。如果方法不是抽象的,也不是本地方法,方法的Java代码就会被编译器编译成字节码(即使方法是空的,编译器也会生成一条return语句),存在method_info结构的Code属性中。

环境准备
1、jdk 1.8.0
2、IntelliJ IDEA Community Edition 2018.3.1 x64

配置信息
1、调试配置
2.1、配置位置:Run/Debug Configurations -> program arguments
2.2、配置内容:-Xjre “C:\Program Files\Java\jdk1.8.0_161\jre” E:\itstack\git\istack-demo\itstack-demo-jvm\itstack-demo-jvm-05\target\test-classes\org\itstack\demo\test\HelloWorld

代码示例

itstack-demo-jvm-05
├── pom.xml
└── src└── main│    └── java│        └── org.itstack.demo.jvm│             ├── classfile│             │   ├── attributes   {BootstrapMethods/Code/ConstantValue...}│             │   ├── constantpool {CONSTANT_TAG_CLASS/CONSTANT_TAG_FIELDREF/CONSTANT_TAG_METHODREF...}│             │   ├── ClassFile.java│             │   ├── ClassReader.java│             │   └── MemberInfo.java   │             ├── classpath│             │   ├── impl│             │   │   ├── CompositeEntry.java│             │   │   ├── DirEntry.java │             │   │   ├── WildcardEntry.java │             │   │   └── ZipEntry.java    │             │   ├── Classpath.java│             │   └── Entry.java   │             ├── classpath│             │   ├── base│             │   ├── comparisons│             │   ├── constants│             │   ├── control│             │   ├── conversions│             │   ├── extended│             │   ├── loads│             │   ├── math│             │   │   ├── add│             │   │   ├── and│             │   │   ├── div│             │   │   ├── iinc│             │   │   ├── mul│             │   │   ├── neg│             │   │   ├── or│             │   │   ├── rem│             │   │   ├── sh│             │   │   ├── sub│             │   │   └── xor│             │   ├── stack│             │   ├── store│             │   └── Factory    │             ├── rtda│             │   ├── Frame.java│             │   ├── JvmStack.java│             │   ├── LocalVars.java│             │   ├── OperandStack.java│             │   ├── Slot.java │             │   └── Thread.java│             ├── Cmd.java│             ├── Interpret.java │             └── Main.java└── test└── java└── org.itstack.demo.test└── HelloWorld.java

Factory.java

public class Factory {public static Instruction newInstruction(byte opcode) {switch (opcode) {case 0x00:return new NOP();case 0x01:return new ACONST_NULL();case 0x02:return new ICONST_M1();case 0x03:return new ICONST_0();case 0x04:return new ICONST_1();case 0x05:return new ICONST_2();case 0x06:return new ICONST_3();case 0x07:return new ICONST_4();case 0x08:return new ICONST_5();case 0x09:return new LCONST_0();case 0x0a:return new LCONST_1();case 0x0b:return new FCONST_0();case 0x0c:return new FCONST_1();case 0x0d:return new FCONST_2();case 0x0e:return new DCONST_0();case 0x0f:return new DCONST_1();case 0x10:return new BIPUSH();case 0x11:return new SIPUSH();// case 0x12://     return &LDC{}// case 0x13://    return &LDC_W{}// case 0x14://  return &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 new ILOAD_0();case 0x1b:return new ILOAD_1();case 0x1c:return new ILOAD_2();case 0x1d:return new ILOAD_3();case 0x1e:return new LLOAD_0();case 0x1f:return new LLOAD_1();case 0x20:return new LLOAD_2();case 0x21:return new LLOAD_3();case 0x22:return new FLOAD_0();case 0x23:return new FLOAD_1();case 0x24:return new FLOAD_2();case 0x25:return new FLOAD_3();case 0x26:return new DLOAD_0();case 0x27:return new DLOAD_1();case 0x28:return new DLOAD_2();case 0x29:return new DLOAD_3();case 0x2a:return new ALOAD_0();case 0x2b:return new ALOAD_1();case 0x2c:return new ALOAD_2();case 0x2d:return new 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 saloadcase 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 new ISTORE_0();case 0x3c:return new ISTORE_1();case 0x3d:return new ISTORE_2();case 0x3e:return new ISTORE_3();case 0x3f:return new LSTORE_0();case 0x40:return new LSTORE_1();case 0x41:return new LSTORE_2();case 0x42:return new LSTORE_3();case 0x43:return new FSTORE_0();case 0x44:return new FSTORE_1();case 0x45:return new FSTORE_2();case 0x46:return new FSTORE_3();case 0x47:return new DSTORE_0();case 0x48:return new DSTORE_1();case 0x49:return new DSTORE_2();case 0x4a:return new DSTORE_3();case 0x4b:return new ASTORE_0();case 0x4c:return new ASTORE_1();case 0x4d:return new ASTORE_2();case 0x4e:return new 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 sastorecase 0x57:return new POP();case 0x58:return new POP2();case 0x59:return new DUP();case 0x5a:return new DUP_X1();case 0x5b:return new DUP_X2();case 0x5c:return new DUP2();case 0x5d:return new DUP2_X1();case 0x5e:return new DUP2_X2();case 0x5f:return new SWAP();case 0x60:return new IADD();case 0x61:return new LADD();case 0x62:return new FADD();case 0x63:return new DADD();case 0x64:return new ISUB();case 0x65:return new LSUB();case 0x66:return new FSUB();case 0x67:return new DSUB();case 0x68:return new IMUL();case 0x69:return new LMUL();case 0x6a:return new FMUL();case 0x6b:return new DMUL();case 0x6c:return new IDIV();case 0x6d:return new LDIV();case 0x6e:return new FDIV();case 0x6f:return new DDIV();case 0x70:return new IREM();case 0x71:return new LREM();case 0x72:return new FREM();case 0x73:return new DREM();case 0x74:return new INEG();case 0x75:return new LNEG();case 0x76:return new FNEG();case 0x77:return new DNEG();case 0x78:return new ISHL();case 0x79:return new LSHL();case 0x7a:return new ISHR();case 0x7b:return new LSHR();case 0x7c:return new IUSHR();case 0x7d:return new LUSHR();case 0x7e:return new IAND();case 0x7f:return new LAND();case (byte) 0x80:return new IOR();case (byte) 0x81:return new LOR();case (byte) 0x82:return new IXOR();case (byte) 0x83:return new LXOR();case (byte) 0x84:return new IINC();case (byte) 0x85:return new I2L();case (byte) 0x86:return new I2F();case (byte) 0x87:return new I2D();case (byte) 0x88:return new L2I();case (byte) 0x89:return new L2F();case (byte) 0x8a:return new L2D();case (byte) 0x8b:return new F2I();case (byte) 0x8c:return new F2L();case (byte) 0x8d:return new F2D();case (byte) 0x8e:return new D2I();case (byte) 0x8f:return new D2L();case (byte) 0x90:return new D2F();case (byte) 0x91:return new I2B();case (byte) 0x92:return new I2C();case (byte) 0x93:return new I2S();case (byte) 0x94:return new LCMP();case (byte) 0x95:return new FCMPL();case (byte) 0x96:return new FCMPG();case (byte) 0x97:return new DCMPL();case (byte) 0x98:return new DCMPG();case (byte) 0x99:return new IFEQ();case (byte) 0x9a:return new IFNE();case (byte) 0x9b:return new IFLT();case (byte) 0x9c:return new IFGE();case (byte) 0x9d:return new IFGT();case (byte) 0x9e:return new IFLE();case (byte) 0x9f:return new IF_ICMPEQ();case (byte) 0xa0:return new IF_ICMPNE();case (byte) 0xa1:return new IF_ICMPLT();case (byte) 0xa2:return new IF_ICMPGE();case (byte) 0xa3:return new IF_ICMPGT();case (byte) 0xa4:return new IF_ICMPLE();case (byte) 0xa5:return new IF_ACMPEQ();case (byte) 0xa6:return new IF_ACMPNE();case (byte) 0xa7:return new GOTO();// case 0xa8://  return &JSR{}// case 0xa9://    return &RET{}case (byte) 0xaa:return new TABLE_SWITCH();case (byte) 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 &GET_STATIC{}// case 0xb3://     return &PUT_STATIC{}// case 0xb4://     return &GET_FIELD{}// case 0xb5://  return &PUT_FIELD{}//   case 0xb6://        return &INVOKE_VIRTUAL{}// case 0xb7://     return &INVOKE_SPECIAL{}// case 0xb8://     return &INVOKE_STATIC{}// case 0xb9://  return &INVOKE_INTERFACE{}// case 0xba://   return &INVOKE_DYNAMIC{}// case 0xbb://     return &NEW{}// case 0xbc://    return &NEW_ARRAY{}// case 0xbd://  return &ANEW_ARRAY{}// case 0xbe://     return arraylength// case 0xbf://   return athrow// case 0xc0://    return &CHECK_CAST{}// case 0xc1://     return &INSTANCE_OF{}// case 0xc2://    return monitorenter// case 0xc3://  return monitorexitcase (byte) 0xc4:return new WIDE();// case 0xc5://    return &MULTI_ANEW_ARRAY{}case (byte) 0xc6:return new IFNULL();case (byte) 0xc7:return new IFNONNULL();case (byte) 0xc8:return new GOTO_W();// case 0xc9://     return &JSR_W{}// case 0xca: breakpoint// case 0xfe: impdep1// case 0xff: impdep2default:return null;}}}

Interpret.java

//指令集解释器
class Interpret {Interpret(MemberInfo m) {CodeAttribute codeAttr = m.codeAttribute();int maxLocals = codeAttr.maxLocals();int maxStack = codeAttr.maxStack();byte[] byteCode = codeAttr.data();Thread thread = new Thread();Frame frame = thread.newFrame(maxLocals, maxStack);thread.pushFrame(frame);loop(thread, byteCode);}private void loop(Thread thread, byte[] byteCode) {Frame frame = thread.popFrame();BytecodeReader reader = new BytecodeReader();while (true) {//循环int pc = frame.nextPC();thread.setPC(pc);//decodereader.reset(byteCode, pc);byte opcode = reader.readByte();Instruction inst = Factory.newInstruction(opcode);if (null == inst) {System.out.println("寄存器(指令)尚未实现 " + byteToHexString(new byte[]{opcode}));break;}inst.fetchOperands(reader);frame.setNextPC(reader.pc());System.out.println("寄存器(指令):" + byteToHexString(new byte[]{opcode}) + " -> " + inst.getClass().getSimpleName() + " => 局部变量表:" + JSON.toJSONString(frame.operandStack().getSlots()) + " 操作数栈:" + JSON.toJSONString(frame.operandStack().getSlots()));            //execinst.execute(frame);}}private static String byteToHexString(byte[] codes) {StringBuilder sb = new StringBuilder();sb.append("0x");for (byte b : codes) {int value = b & 0xFF;String strHex = Integer.toHexString(value);if (strHex.length() < 2) {strHex = "0" + strHex;}sb.append(strHex);}return sb.toString();}}

HelloWorld.java

package org.itstack.demo.test;public class HelloWorld {public static void main(String[] args) {int sum = 0;for (int i = 1; i <= 100; i++) {sum += i;}System.out.println(sum);}}

测试结果 {此时还不能输出结果,但是在操作数据栈中已经可以看到结果:5050}

"C:\Program Files\Java\jdk1.8.0_161\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2018.3.1\lib\idea_rt.jar=61887:D:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2018.3.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_161\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_161\jre\lib\rt.jar;E:\itstack\git\istack-demo\itstack-demo-jvm\itstack-demo-jvm-05\target\classes;D:\Program Files (x86)\apache-maven-2.2.1\repository\com\beust\jcommander\1.72\jcommander-1.72.jar;D:\Program Files (x86)\apache-maven-2.2.1\repository\org\projectlombok\lombok\1.18.0\lombok-1.18.0.jar;D:\Program Files (x86)\apache-maven-2.2.1\repository\com\alibaba\fastjson\1.2.40\fastjson-1.2.40.jar" org.itstack.demo.jvm.Main -Xjre "C:\Program Files\Java\jdk1.8.0_161\jre" E:\itstack\git\istack-demo\itstack-demo-jvm\itstack-demo-jvm-05\target\test-classes\org\itstack\demo\test\HelloWorld
classpath:org.itstack.demo.jvm.classpath.Classpath@4bf558aa class:E:\itstack\git\istack-demo\itstack-demo-jvm\itstack-demo-jvm-05\target\test-classes\org\itstack\demo\test\HelloWorld args:null
寄存器(指令):0x03 -> ICONST_0 => 局部变量表:[{"num":0},{"num":0}] 操作数栈:[{"num":0},{"num":0}]
寄存器(指令):0x3c -> ISTORE_1 => 局部变量表:[{"num":0},{"num":0}] 操作数栈:[{"num":0},{"num":0}]
寄存器(指令):0x04 -> ICONST_1 => 局部变量表:[{"num":0},{"num":0}] 操作数栈:[{"num":0},{"num":0}]
寄存器(指令):0x3d -> ISTORE_2 => 局部变量表:[{"num":1},{"num":0}] 操作数栈:[{"num":1},{"num":0}]
寄存器(指令):0x1c -> ILOAD_2 => 局部变量表:[{"num":1},{"num":0}] 操作数栈:[{"num":1},{"num":0}]
寄存器(指令):0x10 -> BIPUSH => 局部变量表:[{"num":1},{"num":0}] 操作数栈:[{"num":1},{"num":0}]
寄存器(指令):0xa3 -> IF_ICMPGT => 局部变量表:[{"num":1},{"num":100}] 操作数栈:[{"num":1},{"num":100}]
寄存器(指令):0x1b -> ILOAD_1 => 局部变量表:[{"num":1},{"num":100}] 操作数栈:[{"num":1},{"num":100}]
寄存器(指令):0x1c -> ILOAD_2 => 局部变量表:[{"num":0},{"num":100}] 操作数栈:[{"num":0},{"num":100}]... ...寄存器(指令):0x60 -> IADD => 局部变量表:[{"num":4950},{"num":100}] 操作数栈:[{"num":4950},{"num":100}]
寄存器(指令):0x3c -> ISTORE_1 => 局部变量表:[{"num":5050},{"num":100}] 操作数栈:[{"num":5050},{"num":100}]
寄存器(指令):0x84 -> IINC => 局部变量表:[{"num":5050},{"num":100}] 操作数栈:[{"num":5050},{"num":100}]
寄存器(指令):0xa7 -> GOTO => 局部变量表:[{"num":5050},{"num":100}] 操作数栈:[{"num":5050},{"num":100}]
寄存器(指令):0x1c -> ILOAD_2 => 局部变量表:[{"num":5050},{"num":100}] 操作数栈:[{"num":5050},{"num":100}]
寄存器(指令):0x10 -> BIPUSH => 局部变量表:[{"num":101},{"num":100}] 操作数栈:[{"num":101},{"num":100}]
寄存器(指令):0xa3 -> IF_ICMPGT => 局部变量表:[{"num":101},{"num":100}] 操作数栈:[{"num":101},{"num":100}]
寄存器(指令)尚未实现 0xb2Process finished with exit code 0

用Java实现JVM第五章《指令集和解释器》相关推荐

  1. Java核心技术卷一 -第五章:装箱和拆箱

    系列文章目录 Java核心技术卷一 -第一章:java"白皮书"的关键术语 Java核心技术卷一 -第三章:数据类型 Java核心技术卷一 -第三章:变量与常量 Java核心技术卷 ...

  2. Java核心技术卷一 -第五章:类的强制类型转换与instanceof操作符

    系列文章目录 Java核心技术卷一 -第一章:java"白皮书"的关键术语 Java核心技术卷一 -第三章:数据类型 Java核心技术卷一 -第三章:变量与常量 Java核心技术卷 ...

  3. Java核心技术卷一 -第五章:枚举类再认识

    系列文章目录 Java核心技术卷一 -第一章:java"白皮书"的关键术语 Java核心技术卷一 -第三章:数据类型 Java核心技术卷一 -第三章:变量与常量 Java核心技术卷 ...

  4. Java初级笔记-第五章

    第五章 面向对象的特点 5.1 继承 面向对象的重要特点之一就是继承.类的继承使得能够在已有的类的基础上构造新的类,新类除了具有被继承类的属性和方法外,还可以根据需要添加新的属性和方法.继承有利于代码 ...

  5. Java基础一到五章复习笔记

    目录 第一章 第二章 java语言特点 JDK和JRE 转义字符: 注释: 相对路径和绝对路径 常用dos命令 第三章 变量三要素: 加号+的使用: Java API 基本数据类型转换 强制类型转换 ...

  6. Java(第十五章)

    第十五章 一.字符串类String 1.String是一个类,位于java.lang包中 2.创建一个字符串对象的2种方式: String 变量名="值"; String 对象名= ...

  7. 【JAVA SE】第五章 数组、多维数组和Arrays类

    第五章 数组.多维数组和Arrays类 文章目录 第五章 数组.多维数组和Arrays类 一.数组 1.概述 2.声明数组变量 3.创建数组 4.For-Each 循环 二.多维数组 1.概述 2.多 ...

  8. Java学习 第十五章 成员变量和局部变量的区别 / 三大特征之一 (封装性)/构造方法 /private关键字

    第十五章 局部变量和成员变量: 1.定义位置不一样 局部变量:在方法内部定义 成员变量:在方法的外部,直接写在类当中 2.作用范围不一样 局部变量:只能在方法当中使用 成员变量:整个类都可以使用 3. ...

  9. java for循环_愉快地学Java语言:第五章 循环

    导读 本文适合Java入门,不太适合Java中高级软件工程师.本文以<Java程序设计基础篇>第10版为蓝本,采用不断提出问题,然后解答问题的方式来讲述.本篇文章只是这个系列中的一篇,如果 ...

  10. java第五章课后题_黑猴子的家:Java SE 练习题第五章

    尾部都有答案 第五章练习题(继承) (1)下列关于继承优点的叙述正确的是哪几项?(选三项) A.可以创建更为特殊的类型 B.消除重复代码 C.执行效率高 D.便于维护 (2)在子类中调用父类中被覆盖的 ...

最新文章

  1. windows计算器
  2. 管理经验之没有必要的消费:空白卡片
  3. 对研发人员很有震撼和启发的公式
  4. 历史上的今天:编程语言中null引用的十亿美元错误
  5. linux怎么远程命令,Linux远程命令
  6. 常用的前端跨域的几种方式
  7. jQuery源码研究分析学习笔记-jQuery.fn.init()(五)
  8. Python入门之软件开发目录规范
  9. 【电子书分享】决战大数据-驾驭未来商业的利器.pdf(附下载链接)
  10. 回顾 | Apache Flink x TiDB Meetup · 北京站(附 PPT 下载)
  11. 电子申请客户端(EAC)在64位系统上的兼容性问题
  12. cad的文字嵌入线条_CAD字体如何转变为线条
  13. 金蝶KIS专业版本单据导入导出工具使用说明
  14. 笔记本触摸板操作手势
  15. 涉案金额2亿多!贺金虎、刘国庆非法吸收公众存款案开庭
  16. linux iptable配置
  17. 时间序列进行分析的一些手法以及代码实现(移动平均、指数平滑、SARIMA模型、时间序列的(非)线性模型)
  18. Redis Desktop Manager 黑屏
  19. String为什么要设计成final
  20. 2年java开发工作经验

热门文章

  1. Java 数据库image型输出图片
  2. t470换屏线_thinkpad t470怎么样?thinkpad t470拆机图解全面评测
  3. Jlink软件下载和安装教程
  4. svn合并分支到主干
  5. IOUtils常用方法的使用
  6. 高斯克吕格投影,将经纬度转换为投影坐标
  7. python房价数据分析波士顿_Python编程数据科学入门 - 波士顿房价数据分析
  8. 突发!ARM中国区执行董事长兼CEO被免职
  9. 富勒wms系统里的定时器id_「案例」全面升级的康缘药业物流系统
  10. linux退出热键_LINUX常用快捷键