2.6.2 如何阅读规范
指令码是Java虚拟机规范中很重要的一部分,为了帮助读者以后更容易读懂规范,本节将介绍如何阅读其中和指令码相关的内容,首先我们要知道:
·规范第6章(The Java Virtual Machine Instruction Set)详细介绍了每个指令码的格式、所带参数、功能及使用场景。
·规范第7章(Opcode Mnemonics by Opcode)列出了指令码的取值和对应的助记符。
如果要了解具体指令的含义和用法,就必须钻研规范第6章。下面将以两个具体例子来看看规范是如何说明一个指令的格式和用法的。
2.6.2.1 invokevirtual指令
图2-13 invokevirtual指令的解释
在规范中,该指令的格式用法如图2-13所示。
图2-13里关于指令格式的介绍可分为左右两个部分。
·左边是指令格式,描述了该指令的字节码值以及紧跟其后的参数(如果该指令有参数的话)。对invokevirtual来说,该指令后面需要两个字节的参数。在规范中,每条指令的“描述(Description)”一节对这些参数的作用都有详细介绍。比如图中的indexbyte1<<8|indexbyte2共同组成一个指向常量池的索引,该索引对应的常量项是Methodref。Methodref描述了这个函数的信息(属于哪个类,以及该函数的Method Descriptor等),解析这个信息可得到函数调用时需要多少个参数。如此,JVM才能决定右边的操作数栈中有多少项(参数的个数由Methodref决定)需要在这次invokevirtual时用到。
·右边是操作数栈的变化情况。规范中,“操作数栈”这一部分描述的就是该指令执行前后操作数栈的变化情况。大多数指令执行的时候,JVM需要预先准备好操作数栈,里边存储了该指令需要的信息。invokevirtul对应的操作数栈内容为图2-13的右图所示。其中,第一行表示该指令执行前,操作数栈里应该放什么内容,"objectref,[arg1,[arg2...]]→"中的箭头符号表示栈顶的增长方向,也就是栈顶在最右边,栈底在最左边。arg2(如果有)位于栈顶,objectref位于arg1之下。第二行表示该指令执行后对操作数栈的影响。如果是"..."号,则表明该指令执行完后对栈没有影响。
提示 指令码除了可以表示在code数组里紧随其后的内容是参数外,大部分情况下还需要结合操作数栈里的内容。也就是说,指令码的参数来源有两种:
(1)紧跟其后的内容可以是参数。
(2)操作数栈里的内容也是参数。
我们再来看一个指令。
2.6.2.2 dup_x1指令
dup_x1指令针对的是操作数栈,其功能是:
·复制一份复制栈顶元素。
·将新复制的值插入操作数栈,但是位置不在栈顶,而是离当前栈顶元素之后的两个位置。
图2-14展示了dup_x1的指令解释:
图2-14 dup_x1指令的解释