基于栈的字节码解释执行引擎

声明:本文摘抄自《深入理解Java虚拟机》一书,本文完全为自我学习,请感兴趣的同学购买正版,支持原创

Java语言经常被人们定位为“解释执行”语言,在Java初生的JDK1.0时代,这种定义还比较准确的,但当主流的虚拟机中都包含了即时编译后,Class文件中的代码到底会被解释执行还是编译执行,就成了只有虚拟机自己才能准确判断的事情。再后来,Java也发展出来了直接生成本地代码的编译器[如何GCJ(GNU Compiler for the Java)],而C/C++也出现了通过解释器执行的版本(如CINT),这时候再笼统的说“解释执行”,对于整个Java语言来说就成了几乎没有任何意义的概念。

基于栈的指令集和基于寄存器的指令集

Java编译器输出的指令流,基本上是一种基于栈的指令集架构(Instruction Set Architecture,ISA),指令流中的指令大部分都是零地址指令,它们依赖操作数栈进行工作。与之相对应的另一套常用的指令集架构是基于寄存器的指令集,最典型的就是X86的地址指令集,说的通俗一下,就是现在我们主流的PC机中直接支持的指令集架构,这些指令集依赖寄存器工作。那么,基于栈的指令集和基于寄存器的指令集这两者有什么不同呢?

举个简单例子,分别使用这两种指令计算1+1的结果,基于栈的指令集会是这个样子:

iconst_1
iconst_1
iadd
istore_0

两条iconst_1指令连续把两个常量1压入栈后,iadd指令把栈顶的两个值出栈、相加,然后将结果放回栈顶,最后istore_0把栈顶的值放到局部变量表中的第0个Slot中。
如果基于寄存器的指令集,那程序可能会是这个样子:

mov eax, 1
add eax, 1

mov指令把EAX寄存器的值设置为1,然后add指令再把这个值加1,将结果就保存在EAX寄存器里面。
基于栈的指令集主要的优点就是可移植,寄存器是由硬件直接提供,程序直接依赖这些硬件寄存器则不可避免地要受到硬件的约束。例如,现在32位80x86体系的处理器中提供了8个32位的寄存器,而ARM体系的CPU则提供了16个32位的通用寄存器。如果使用栈架构的指令集,用户程序不会直接使用寄存器,就可以由虚拟机实现来自行决定把一些访问最频繁的数据(程序计数器、栈顶缓存等)放到寄存器中以获得最好的性能,这样实现起来也更加简单一些。栈架构的指令集还有一些其他的优点,如代码相对更加紧凑,编译器实现更加简单等。
栈架构指令集的只要缺点是执行速度相对来说会稍微慢一些。虽然栈架构指令集的代码非常紧凑,但是完成相同功能所需要的指令数量一般会比寄存器架构多,因为出栈、入栈操作本身就产生了相当多的操作指令数量。
更重要的是,栈实现在内存之中,频繁的栈操作意味着频繁的内存访问,相对于处理器来说,内存始终是执行速度的瓶颈。尽管虚拟机采取栈顶缓存的优化手段,把最常用的操作映射到寄存器中避免直接内存访问,但这也只能是优化措施而不是解决本质问题的方法。由于指令数量和内存访问的原因,所以导致栈架构指令集的执行速度会相对较慢。

基于栈的解释器的执行过程

public int calc() {
    int a = 100;
    int b = 200;
    int c = 300;
    return (a + b) * c;
}

以上面的代码为例,看看虚拟机是如何执行的。使用javap命令查看它的字节码指令,字节码指令如下:

  public int calc();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        100
         2: istore_1
         3: sipush        200
         6: istore_2
         7: sipush        300
        10: istore_3
        11: iload_1
        12: iload_2
        13: iadd
        14: iload_3
        15: imul
        16: ireturn
      LineNumberTable:
        line 3: 0
        line 4: 3
        line 5: 7
        line 6: 11
}

编译后的字节码指令显示这段代码需要深度为2的操作数栈和4个Slot的局部变量空间。我们通过下面几张图来了解代码执行过程中的代码、操作数栈和局部变量表的变化情况。


执行偏移地址为0的指令情况
  1. 首先执行偏移地址为0的指令,bipush指令的作用是将单个字节的整形常量值(-128~127)推入操作栈顶,跟随有一个参数,指明推送的常量值,这里是100。
  2. 执行偏移地址为2的指令,istore_1指令的作用是将操作栈顶的整形值出栈并存入局部变量表Slot中。后续4条指令都是做一样的事情,也就是在对应代码中把变量a、b、c赋值为100、200、300。
  3. 执行偏移地址为11的指令,iload_1指令的作用是将局部变量表第一个Slot中的整形值复制到操作栈顶。
  4. 执行偏移地址为12的指令,iload_2指令的执行过程与iload_1类似,把第2个Slot的整形值入栈。当前局部变量表和操作栈如下图所属:


    执行偏移地址为12的指令情况

    5.执行偏移地址为13的指令,iadd指令的作用是将操作数栈中头两个栈顶元素出栈,做整形加法,然后把结果重新入栈。在iadd指令执行完毕后,栈中原有的100和200出栈,它们的和300重新入栈。

  5. 执行偏移地址为14的指令,iload_3指令把存放在第3个局部变量Slot中的300压入操作栈中。这时操作栈中为两个整数300。下一条指令imul是将操作栈中头两个栈顶元素出栈,做整形乘法,然后把结果重新入栈,与iadd完全类似。
  6. 执行偏移地址16的指令,ireturn指令是方法返回指令之一,它将结束方法执行并将操作栈顶的整形值返回给此方法的调用者。到此为止,这段代码执行结束。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,392评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,258评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,417评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,992评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,930评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,199评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,652评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,327评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,463评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,382评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,432评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,118评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,704评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,787评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,999评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,476评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,057评论 2 341

推荐阅读更多精彩内容