JVM解释器(不是JIT编译器)实际上做什么?

怪异的

请注意,我的问题是关于JVM解释器,而不是JIT编译器。JIT编译器将Java字节码转换为本机代码。因此,这必须意味着JVM中的解释器不会将字节码转换为机器码。因此,问题就来了:实质上,口译员做什么?如果有人可以用一个相当于1 + 1 = 2的字节码的简单示例来帮助我回答这个问题,那么,对于执行此加法操作,解释器会做什么?(我的隐性问题是,如果解释器未转换为哪个CPU随后执行ADD操作的机器代码,那么该操作如何执行?实际执行了哪些机器代码来支持该ADD操作?)

sepp2k

该表达式1+1将编译为以下字节码:

iconst_1
iconst_1
add

(实际上,iconst_2由于Java编译器执行常量折叠,因此它只能编译为,但是出于此答案的目的,我们将其忽略。)

因此,要确切了解解释器对这些指令的作用,我们应该查看其源代码对于相关的部分const_1add在启动线983线1221分别,让我们一起来看看:

#define OPC_CONST_n(opcode, const_type, value)                          \
      CASE(opcode):                                                     \
          SET_STACK_ ## const_type(value, 0);                           \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);

          OPC_CONST_n(_iconst_m1,   INT,       -1);
          OPC_CONST_n(_iconst_0,    INT,        0);
          OPC_CONST_n(_iconst_1,    INT,        1);
          // goes on for several other constants

//...
#define OPC_INT_BINARY(opcname, opname, test)                           \
      CASE(_i##opcname):                                                \
          if (test && (STACK_INT(-1) == 0)) {                           \
              VM_JAVA_ERROR(vmSymbols::java_lang_ArithmeticException(), \
                            "/ by zero", note_div0Check_trap);          \
          }                                                             \
          SET_STACK_INT(VMint##opname(STACK_INT(-2),                    \
                                      STACK_INT(-1)),                   \
                                      -2);                              \
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);                        \
          // and then the same thing for longs instead of ints

      OPC_INT_BINARY(add, Add, 0);
      // other operators

整个过程都在检查当前指令操作码的开关语句内部。

如果我们扩展宏魔术,用一个极其简化的模板替换周围的代码,并做一些简化的假设(例如仅由ints组成的堆栈),我们最终将得到如下结果:

enum OpCode {
  _iconst_1, _iadd
};

// ...
int* stack = new int[calculate_maximum_stack_size()];
size_t top_of_stack = 0;
size_t program_counter = 0;
while(program_counter < program_size) {
  switch(opcodes[program_counter]) {
    case _iconst_1:
      // SET_STACK_INT(1, 0);
      stack[top_of_stack] = 1;
      // UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      program_counter += 1;
      top_of_stack += 1;
      break;

    case _iadd:
      // SET_STACK_INT(VMintAdd(STACK_INT(-2), STACK_INT(-1)), -2);
      stack[top_of_stack - 2] = stack[top_of_stack - 1] + stack[top_of_stack - 2];
      // UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
      program_counter += 1;
      top_of_stack += -1;
      break;
}

因此对于1+1操作顺序将是:

stack[0] = 1;
stack[1] = 1;
stack[0] = stack[1] + stack[0];

并且top_of_stack将为1,因此我们将以包含该值2作为其唯一元素的堆栈结束

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

当我们声明静态变量时,编译器实际上会做什么?

JVM中的JIT编译器到底是什么?

JVM是编译器还是解释器?

实际上,为什么不同的编译器会计算int x = ++ i + ++ i;的不同值?

“条件总是假的”来自编译器的警告,条件实际上可能为真

编译器实际上是否使用我的“ omp声明simd”函数?

显示器上的像素时钟设置实际上是做什么的?

公共名称服务器实际上是做什么的?

在C ++中将指针变量链接到数组时,链接器实际上做什么?

Java的编译器和解释器(JVM)

JVM JIT编译器如何优化“重复的” Java代码?

“扩展”实际上是做什么的?

有没有办法让编译器相信 @NonNull 变量在 Kotlin 中实际上是可空的?

默认的TArray.Sort比较器实际上是做什么的,什么时候使用它?

解释“ DEBUG = myapp:* npm start”实际上在做什么

为什么犯规JIT编译器(Java)的保存结果?

即时(JIT)编译器有什么作用?

编译器在做什么,从而允许通过很少的实际比较就可以完成许多值的比较?

'tar --overwrite'实际上做什么(或不做什么)?

转换在编译器/机器级别做什么?

Qt快速编译器到底能做什么?

返回对象时编译器会做什么

为什么在JVM中没有用于提示JIT编译器的基础设施?

用python编写的装饰器实际上是什么?

编译器实际上会产生机器代码吗?

任何编译器实际上会淘汰这些副本吗?

我如何向Xubuntu解释某些驱动器实际上是内部驱动器?

Java编译器/解释器

PHP编译器/解释器