JVM解释器(不是JIT编译器)实际上做什么?
请注意,我的问题是关于JVM解释器的,而不是关于JIT编译器的。JIT编译器将java字节码转换为本机代码。因此,这必须意味着JVM中的解释器不会将字节码转换为机器码。因此问题就来了:从本质上讲,口译员做什么?如果有人能帮我回答这个问题,用一个简单的字节码示例,相当于1+1=2,即解释器在执行这个加法操作时做了什么?(我的隐含问题是,如果解释器不翻译为机器代码,那么哪个CPU执行添加操作,那么该操作是如何执行的?实际执行什么机器代码来支持该添加操作?表达式JVM解释器(不是JIT编译器)实际上做什么?,jvm,interpreter,Jvm,Interpreter,请注意,我的问题是关于JVM解释器的,而不是关于JIT编译器的。JIT编译器将java字节码转换为本机代码。因此,这必须意味着JVM中的解释器不会将字节码转换为机器码。因此问题就来了:从本质上讲,口译员做什么?如果有人能帮我回答这个问题,用一个简单的字节码示例,相当于1+1=2,即解释器在执行这个加法操作时做了什么?(我的隐含问题是,如果解释器不翻译为机器代码,那么哪个CPU执行添加操作,那么该操作是如何执行的?实际执行什么机器代码来支持该添加操作?表达式1+1将编译为以下字节码: iconst
1+1
将编译为以下字节码:
iconst_1
iconst_1
add
(实际上,它将编译成iconst_2
,因为Java编译器执行常量折叠,但为了回答这个问题,我们忽略它。)
因此,为了确切地了解解释器对这些指令做了什么,我们应该看看。有关代码< > COSTRY1和<代码> Audio/Cuff>开始,分别,所以让我们看一下:
定义OPC常量(操作码、常量类型、值)\
案例(操作码):\
设置_STACK_35;##const_type(值,0)\
更新PC和TOS并继续(1,1);
OPC常量n(_iconst_m1,INT,-1);
OPC常数(_iconst_0,INT,0);
OPC常量(_iconst_1,INT,1);
//继续计算其他几个常数
//...
#定义OPC_INT_二进制文件(opcname、opname、test)\
案例(_i###opcname):\
如果(test&(STACK_INT(-1)==0)){\
VM_JAVA_错误(vmSymbols::JAVA_lang_算术异常()\
“/按零”,注_div0Check _trap)\
} \
设置堆栈INT(VMint###opname)(堆栈INT(-2)\
堆栈_INT(-1))\
-2); \
更新PC和TOS并继续(1,-1)\
//对于long而不是int也一样
OPC_INT_二进制(add,add,0);
//其他操作员
整个过程都在一个switch语句中,该语句检查当前指令的操作码
如果我们扩展宏魔法,用一个极其简化的模板替换周围的代码,并做出一些简化假设(例如堆栈仅由int
s组成),我们最终会得到如下结果:
enum操作码{
_iconst_1,_iadd
};
// ...
int*stack=newint[计算最大堆栈大小();
堆栈的大小\u t top\u=0;
大小\u t程序\u计数器=0;
while(程序计数器<程序大小){
开关(操作码[程序计数器]){
案例1:
//设置堆栈INT(1,0);
堆栈[堆栈的顶部]=1;
//更新PC和TOS并继续(1,1);
程序计数器+=1;
_堆栈的顶部_+=1;
打破
个案(iadd):
//设置堆栈INT(VMintAdd(堆栈INT(-2),堆栈INT(-1)),-2);
堆栈[top\u of_stack-2]=堆栈[top\u of_stack-1]+堆栈[top\u of_stack-2];
//更新PC和TOS并继续(1,-1);
程序计数器+=1;
_堆栈的顶部_+=-1;
打破
}
因此,对于1+1
而言,操作顺序为:
stack[0]=1;
堆栈[1]=1;
堆栈[0]=堆栈[1]+堆栈[0];
而
top\u of_stack
将是1,因此我们将以一个包含值2
作为其唯一元素的堆栈结束。实际的机器代码是解释器的一部分。只需考虑一个包含switch语句的循环,每个现有字节码指令都有一个案例,在那里执行操作或调用subgrar是