教你用Java开发一个简单的JVM

一、前言

几年前,接到一个开发任务:用Java开发能运行Java智能合约的虚拟机。在开发Java智能合约时,只能使用智能合约SDK提供的类和一些Java常用类(8种基本数据类型包装类;String、BigInteger、BigDecimal、List、Map、Set 相关的类)。

完整的Java智能合约虚拟机比较复杂,且要保存Java智能合约状态。 这篇文章仅介绍一个简单JVM实现,支持少量字节码。 参考 Java 虚拟机规范(Java SE 8),里面写到:要正确实现 Java 虚拟机,只需能够读取class文件格式并正确执行其中指定的操作。为了简化实现,使用了 ASM解析class文件 。

二、使用ASM解析class文件

使用 ASM Tree API 解析class文件,获得一个 ClassNode 对象,里面包含 class 文件的各种信息。要运行class定义的方法,先在ClassNode中找到这个方法(MethodNode包含方法的各种信息),然后执行方法的指令集。MethodNode.instructions 是这个方法的指令集,遍历指令集,执行每个指令,只要正确执行了指令,方法就能完成运行。

教你用Java开发一个简单的JVM

三、实现JVM运行时数据区

要正确执行指令,先要了解JVM结构,参考 Java虚拟机规范第二章(JVM结构),里面介绍了JVM运行时数据区,定义了在程序执行期间使用的各种运行时数据区,如图所示:

教你用Java开发一个简单的JVM

下面简要介绍各种运行时数据区,详细信息查看 Java虚拟机规范第二章(JVM结构),根据这些信息,可以简单实现各种运行时数据区。

3.1 程序计数器

Java 虚拟机可以同时支持多个执行线程。每个线程都有自己的程序计数器。程序计数器包含当前线程正在执行的 Java 虚拟机指令的地址。

程序计数器最主要作用就是包含当前指令,程序计数器简单实现如下:

教你用Java开发一个简单的JVM

3.2 虚拟机栈

每个 Java 虚拟机线程都有一个Java 虚拟机栈。虚拟机栈存储栈帧,推入和弹出栈帧。

虚拟机栈就是一个保存栈帧的栈,实现如下:

教你用Java开发一个简单的JVM

3.2.1 栈帧

每次调用方法时都会创建一个栈帧,每个栈帧都有自己的局部变量数组和操作数栈,局部变量数组和操作数栈的大小在编译时确定。

新栈帧推入虚拟机栈,虚拟机栈的栈顶栈帧是当前正在执行的活动栈帧,称为当前栈帧,其方法称为当前方法,定义当前方法的类是当前类。 在方法返回时,当前栈帧将其方法调用的结果(如果有)传递回前一栈帧。 虚拟机栈弹出当前栈帧,前一栈帧成为当前栈帧。 栈帧包含局部变量和操作数栈,实现如下:

教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM

3.2.2 局部变量

每个栈帧都包含一个称为局部变量的变量数组。Java 虚拟机使用局部变量在方法调用时传递参数。在类方法调用中,参数从局部变量0开始。在实例方法调用中,局部变量0用于传递对象的引用,随后从局部变量1开始传递任何参数。

局部变量用来传递方法参数,实现如下:

教你用Java开发一个简单的JVM

3.2.3 操作数栈

每个栈帧都包含一个操作数栈。创建栈帧时,操作数栈为空。Java 虚拟机提供将常量、值从局部变量、字段加载到操作数栈的指令。其他 Java 虚拟机指令从操作数栈中获取操作数,对其进行操作,并将结果推回到操作数栈上。操作数栈还用于准备要传递给方法的参数和接收方法结果。

操作数栈就是保存操作数的栈,实现如下:

教你用Java开发一个简单的JVM

3.3 虚拟机栈

Java 虚拟机有一个在所有 Java 虚拟机线程之间共享的堆。堆是运行时数据区,从中分配所有类实例和数组的内存。对象的堆存储由垃圾收集器回收,对象永远不会被显式释放。

简单实现堆,不用考虑垃圾回收,就是用来保存对象实例,实现如下:

教你用Java开发一个简单的JVM

3.3.1 局部变量

对象实例是通过引用关联的,引用实现如下:

教你用Java开发一个简单的JVM

3.4 方法区

Java 虚拟机有一个在所有 Java 虚拟机线程之间共享的方法区。它存储每个类的结构,例如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括在类和实例初始化和接口初始化中使用的特殊方法。

方法区用来保存类结构,实现如下:

教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM

3.5 本地方法栈

本地方法栈是为 Java 虚拟机运行 native 方法服务的,由于很多 native 方法都是用 C 语言实现的,所以它通常又叫 C 栈。本地方法栈与虚拟机栈所发挥的作用非常相似,甚至有的虚拟机直接把本地方法栈和虚拟机栈合二为一。

四、实现JVM

前面对JVM运行时数据区做了简单实现,现在需要把这些运行时数据区关联起来,实现一个简单JVM,这个JVM不考虑线程,直接在Jvm类中关联运行时数据区。

简单JVM实现如下:

教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM

这是一个简单JVM,不会实现所有字节码,写一个示例合约,运行这个合约时,用到了哪些字节码,就实现哪些字节码。

五、示例合约

写一个示例合约:

教你用Java开发一个简单的JVM

写一个智能合约SDK提供的工具类,里面有一个native方法,需要JVM去调用真正的实现。

教你用Java开发一个简单的JVM

native方法实现

教你用Java开发一个简单的JVM
教你用Java开发一个简单的JVM

运行示例合约

教你用Java开发一个简单的JVM

六、实现字节码

运行示例合约,可以看到需要实现哪些字节码,把这些字节码都实现。多次运行、实现后,相关字节码都实现了。再次运行,就可以看到控制台输出:1024。

实现参考 Java虚拟机规范第六章(JVM指令集),下面是其中一个字节码的实现,更多字节码实现,可以看完整代码。

教你用Java开发一个简单的JVM

七、结束

这是一个简单的JVM,很多实现都很简化。可以不断丰富示例代码,然后实现更多字节码,在实现字节码过程中,就会发现以前实现的问题,多次迭代后,JVM就会更完善。

下载完整代码:
https://gitee.com/xdehuan/contract-jvm

希望以上内容能对有需要的人有所帮助

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容