../mini-jvm-intro

用 Java 实现一个简单的虚拟机

Published:

jvm scratch

Learning By Doing.

最近开了个新坑, 目的是用 Java 8 实现一个简单的解释型 JVM. 目前零零散散提交了 100 多 commits. 最终的目标是 自举.
目前进度大概 60%, 基本的 ClassFile 解析, 类加载, 字节码执行, 方法调用, 对象实例化, 多态, 接口基本可用.

0x00 背景

mini-jvm 项目的目的.

  1. 这有点意思.
  2. 个人日常工作中主要使用 Java, 需要对 JVM 有一定的理解, 然而 Hotspot 源码实在是看不下去.
  3. Learning By Doing.

写此文的目的.

  1. 稍加记录, 以备日后回顾.
  2. 广而告之, 以期对 JVM 感兴趣的同学能了解到有这么一个项目.
  3. 寻道友, 希望感兴趣的同学可以联系我, 以期继续完善这个项目.

0x01

在实现的过程中, 已力保代码简单, 可读, 可测. 目前为止代码 5000 行出头, 窃以为, 对于想了解 JVM 基本原理的同学是个不错的入门项目.
在此基础上, 为了便于理解一些概念, 比如基于栈的虚拟机实现原理, 会特意实现一个边缘特性用来快速理解.

0x02 基于栈的虚拟机基本实现.

对 JVM 字节码执行引擎稍有了解的话, 应该对栈帧有所了解

栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构 栈帧随着方法调用而创建,随着方法结束而销毁,栈帧的存储空间分配在 Java 虚拟机栈中,每个栈帧拥有自己的局部变量表(Local Variables)操作数栈(Operand Stack)

如果尝试用过 javap -v classfile , method 区块亦有所体现.

下面看一个简单的例子

  
public class Hello {
  public static int return1() {
    return 1;
  }
}
  

编译并使用

  
cat <<EOF > Hello.java
public class Hello {
  public static int return1() {
    return 1;
  }
}
EOF
# 很明显, 如果 return1 方法被调用, 返回结果一定是 1 .
javac Hello.java
javap -v Hello.class
  

输出较长, 只摘抄方法部分如下

  
public static int return1();
  descriptor: ()I
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
    stack=1, locals=0, args_size=0
        0: iconst_1
        1: ireturn
  

stack=1 即此方法栈操作数栈大小为 1
locals=0 即此方法局部变量表大小为 0
args_size 即此方法参数个数为 0

  
0: iconst_1
1: ireturn
  

这即是该方法的字节码
0: iconst_1 , 表示该方法指令集 0 位置 的指令为 iconst_1 , iconst_1 的含义是 将 int 值 1 push 到操作数栈.
1: ireturn , 表示该方法指令集 1 位置 的指令为 ireturn , ireturn 的含义是, 将当前操作数栈栈顶 int 类型值弹出, 并且把当前栈帧弹出, 并将从操作数栈弹出的 int 类型值 push 到当前栈帧的操作数栈.

类似 iconst_1 这种指令, JVM 规范定义了 200 + 个.

为了方便理解. 项目实现了一个简单的类汇编语言来描述字节码,并解释执行.

  
return1 1 0 0 
0 iconst_1
1 ireturn
  

对比上方 javap -v 的输出, 去除了一些冗余信息.
下为实际截图
1574438006.png

稍复杂一点的 sum10
1574438135.png

更复杂一点的 sumN
1574438239.png

0x03 尾声

简介到此告一段落, 更多信息可往 github repo 了解.
若有兴趣参与, 务必联系我, 虚左以待.

联系方式
vx: echo "Z3V4aW5na2VfCg==" | base64 -d
mail: echo "YWRtaW5AZ3V4aW5na2UuY29tCg==" | base64 -d

项目地址
github: https://github.com/guxingke/mini-jvm