相信很多搞Java开发都知道, Java程序的跨平台是依靠jvm的, 那jvm既然承担了Java程序的编译,解释,执行的工作,那是不是我们可以自己手写虚拟机呢,答案是可以的 。
虚拟机我们都知道用 C++ 写的hotspot, 其实很多厂商都有自己的一套虚拟机。想IBM用的是自己的OpenJ9。所以手写虚拟机还是可以实现的。
在idea 上很容易通过jclasslib 查看到字节码指令。
我们来看一组通用指令
iconst_0 将自然数0压入操作数栈
iconst_1 将自然数1压入操作数栈
iload_0 将索引为0的局部变量表的int型数据压入操作数栈
istore_1 将操作数栈栈顶的int型数据写入索引为1的局部变量表中。
// ......
在jvm 源代码中,定义了Java语言的全部指令集,若是平时接触过字节码的话,你对上面的应该就不陌生。 Java有了这套通用的指令集, 就有一统江湖的希望了。
这些指令有200多个, 这些指令都有自己实现逻辑, 我们把这些指令搞明白了,其实对jvm操作底层的指令就一目了然, 实现自己的jvm也就水到渠成了,看着是好简单,但这些都暗藏玄机,往往涉及到底层的东西,越是难懂。
我还真佩服那些 写出 jvm 这种鬼才。从0到1 是最难的。 现在我们是站在巨人的肩膀上, 把已有的jvm hotspot 源码看明白, 再模仿写一个, 看似也没那么难。哈哈哈, 毕竟,模仿,还是比较在行的。
当然,要看懂这些指令集,还得懂 汇编。 常见的汇编指令,像什么 数据传送指令, 算术运算指令, 逻辑运算指令, 串指令, 程序转移指令。
1、数据传送指令
// 将自然数 1 传送到 eax 寄存器
mov1 1, %eax
// 将栈顶数据弹出至eax 寄存器
pop %eax
2、算术运算指令
包括算术基本四则运算、 浮点运算、 数学运算(正弦,反弦)等。
例如:
// 将自然数3 与 eax 寄存器中的数累加,并将结果存储进eax 中
add 3,%eax
// 对 ebx 寄存器的数增1
inc %ebx
3、逻辑运算指令
与、或、非、左移、右移等指令,都属于逻辑运算指令。例如
// 将 eax中的数 左移 1个二进制
sh1 %eax, 1
// 对 a1 寄存器中的数和操作数进行与操作
and a1, 00111011B
4、串指令
连续空间分配,联系空间取值,传送等,都要使用串指令。很多高级
编程语言都支持字符串运算,如果硬件没有串指令,不敢想象计算机的世界会变成什么样。
5、程序转移指令
if....else 判断、 for 循环、 while 循环、函数调用等, 都需要依靠程序转移指令,否则程序无法跳转。没有这些指令,程序不能模块化,无法被分隔成一个一个方法,更无法通过循环来解决很多重要的问题。常见的程序转移指令包括jmp 跳转、loop 循环、ret 等。
这些指令在底层都和着计算机进行打交道。 所以,不容小觑啊!