【转载】让你的JVM有自己的数据类型

187 阅读5分钟

哈喽,大家好,我就是明明可以靠脸吃饭,却偏偏抢大家饭碗的硬核男人子牙老师。我要励志站在Java圈最卷的位置,小姥们跟紧我,别掉队。

本篇文章是专栏《用Java带你手写JVM》的第三篇,让你的JVM有自己的数据类型。本专栏的文章都是环环相扣的,如果你还没看过前面的文章,建议先去看下,不然本篇文章有可能看不懂。文章是全网发,有的文章有的平台也不知道啥原因没给通过,完整专栏文章可在我的公众号【硬核子牙】中阅读。

Java目前有这些数据类型:boolean、byte、char、int、long、float、double、oop。关于这些数据类型我大概讲下:

  1. Java的这些数据类型是由JVM提供的,JVM主要是由C++编写的,而C++是没有布尔类型的。那Java中的布尔类型是怎么来的呢。大多数情况是通过运用C++的语法定义出来的。代码如下。这也就解释了为什么false等于0,true等于1。

  1. C++中是没有byte类型的,Java中的byte是怎么来的呢?把C++中的char当byte用。那Java中的char又是怎么来的呢?把C++中的short当char用。其实我是不太明白JVM为什么要这么设计的。所以Java中,byte占一个字节,char占两个字节。这里对于学过C语言、C++的小伙伴一定要记住。我在早期的时候就是把char当一个字节来用的。

  2. 这里面这个oop类型可能有些小伙伴不认识。oop指的是对象指针。Java中的所有对象,在JVM中都有一个对应的C++对象与之对应,这个对象就是oop对象。感兴趣的小伙伴可以私信我,看我之前讲的JVM系列视频。

  3. JVM由于受历史遗留原因影响,现在程序运行基于的虚拟机栈还是32位的。这就带来一个问题,double、long如何存储?虚拟机栈中的一个格子称为一个Slot,32位,4B。那8B就用两个Slot来存储。但是数据不是存储在一个地方不动的,它需要流通。所以就涉及到数据的合与分。是不是感觉很复杂又很兴奋得想要了解?那就继续看。

其他的数据类型实现起来都比较简单,我就不细讲了,本篇文章聚焦带大家理解JVM中double的本质及让我们自己的JVM支持double类型

课程目标

再说下本篇文章的目标,就是在我们自己的JVM上能够成功运行这段Java程序。Java代码虽然没多少,但是实现起来可没那么简单的哦。

看下对应的字节码指令。让我们自己的JVM能够运行这段程序,本质就是让我们自己的JVM能够处理这些字节码指令。

看下运行结果

实现细节

目标有了,接下来就是怎么做了。要实现上面的Java代码,这些地方都需要加代码或写代码:

  1. 常量池解析与存储
  2. 局部变量表存与取
  3. 操作数栈存与取
  4. 当参数取值

接下来详细讲解这四点。

处理常量池

看下代码中有double,生成的常量池是啥样子的,上图

double在常量池中也是分成两个格子存储的,小端模式,高位在前,地位在后。

规律找到了,字节码解析器解析常量池处的逻辑代码就好写了,如下

我在实现的时候,即解析常量池的时候,采用小端模式一次性读了8个字节,然后转成double,当成Object存储到容器中。注意这里,用Java去实现可以这样写,但是用C++实现,只能老老实实的按照字节码文件来。

特别提醒下,后面的代码是将一个double拆成两个int来支持程序运行,所以拆成两个int后的顺序,写代码的时候要注意下。这个是实现这个功能最容易绕晕的地方。建议在写代码下画如下的堆栈图理清思绪。

处理操作数栈

考虑到很多小伙伴跟我学习手写JVM都是为了后面能够更好地研究Hotspot源码,所以在真正运行的时候,我还是把一个double拆成两个int来操作的。看下JVM执行ldc2_w指令的核心代码及执行后操作数栈的情况

处理局部变量表

然后JVM执行dstore_1,这个指令的作用就是将操作数栈的值写入局部变量表,一次读两个Slot。看核心代码及执行后的堆栈情况

注意,这时候操作数栈已经空了

处理参数

最后JVM执行invokevirtual。前面的文章说过,JVM执行这个指令分两步,第一步是构建环境,第二步是执行方法的字节码指令。构建环境就涉及到取参数。看下核心代码。从操作数栈中取出两个Slot,合并成一个double。因为value1是后4个字节,value2是前4个字节,所以pushInt时些value2再value1。

至此,double的本质及,让你的JVM像Hotspot源码那样处理double,核心部分就讲完了。剩下的边边角角大家可以通过阅读我提供的手写JVM代码去细细体会。关注公众号【硬核子牙】回复【手写JVM代码】获取代码。

练习

1、让你的JVM支持基本数据类型

2、让你的JVM动起来,支持运算

3、拓展练习:让你的JVM支持long时,改为Hotspot的逻辑,通过两个slot操作,不要直接用long或8字节的byte数组

结语

我是子牙老师,下篇文章见,如果你也喜欢研究底层,欢迎关注我的公众号【硬核子牙