Compiler construction 基于方法的JIT编译器如何处理类字段成员

Compiler construction 基于方法的JIT编译器如何处理类字段成员,compiler-construction,compilation,bytecode,jit,bytecode-manipulation,Compiler Construction,Compilation,Bytecode,Jit,Bytecode Manipulation,即时(JIT)编译器引用在程序运行时将代码转换为本机代码的编译器。通常,它将字节码转换为Java编程语言的机器码 一般有两种JIT编译器:基于方法的JIT和基于跟踪的JIT。前者主要对运行时程序进行概要分析,只选择hot方法进行编译 我这里的问题是JIT编译器如何处理类字段成员_b引用堆上新创建的Java对象。那么,当选择“test(string)V”方法进行JIT编译时,JIT编译器如何翻译getField指令呢?在生成的本机代码和字节码之间是否有任何来回的跳转 class A{ MyO

即时(JIT)编译器引用在程序运行时将代码转换为本机代码的编译器。通常,它将字节码转换为Java编程语言的机器码

一般有两种JIT编译器:基于方法的JIT和基于跟踪的JIT。前者主要对运行时程序进行概要分析,只选择hot方法进行编译

我这里的问题是JIT编译器如何处理类字段成员_b引用堆上新创建的Java对象。那么,当选择“test(string)V”方法进行JIT编译时,JIT编译器如何翻译
getField
指令呢?在生成的本机代码和字节码之间是否有任何来回的
跳转

class A{
   MyObject _b = new MyObject(..);

   public void test(String ars){
       aload 0 
       getField A::_b MyObject
       invokvirtual MyObject sayHello (String)V
       ...
   }
}

热点虚拟机维护一组方法框架。此堆栈通常包含编译帧和解释帧,具体取决于执行代码的“热”


只要字节码程序的语义不变,对象分配可以通过JIT编译代码以任何方式执行。如果编译器可以证明从未使用过该对象,它甚至可以一起避免分配,因为这不会改变所提到的语义。

您所问的“JIT编译器如何处理类字段成员”包含两个错误的假设。首先,我们不能谈论“JIT编译器”,存在大量不同的现有JIT编译器/优化器,即使我们将自己局限于Oracle JVM的行为,我们也不能做出笼统的陈述。其次,没有单独处理单个功能,特别是像字段访问这样简单的功能

不清楚为什么您认为在执行
getfield
指令期间,编译代码和解释代码之间存在交互。无论JVM如何实现对象引用,它们都是一种值,读取字段
\u b
的值只意味着从内存中读取值。将值写入字段(即对新创建对象的引用)发生在
的构造函数内部,而不是在读取字段时。代码的状态与内存访问完全无关

当涉及到
invokvirtual
指令时,它的执行可能意味着从解释模式更改为编译代码,反之亦然。但是,同样,这与前面的
getfield
指令无关。如果目标对象引用是
aload
指令或前面的方法调用或方法内部的新分配的结果,则不会有什么不同。它只取决于被调用方法的代码状态,即
MyObject.sayHello
或子类的重写方法


因为,当编译/优化方法时,生成的代码不太可能在主流CPU上建模堆栈。生成的本机代码不会将引用推送到堆栈,而是直接向前读取字段值并将其用于后续调用。引用可能会临时存储到CPU寄存器中,但如果目标CPU能够处理此类间接寻址,则读取操作和调用也可能融合到单个指令中。还有一种可能是,
sayHello
的代码被内联,优化器的整体结果根本不会让人想起原始代码。

操作数堆栈纯粹是用于定义字节码语义的抽象。JIT没有理由实际模拟堆栈,事实上字节码是经过精心设计的,因此这是不必要的。你是说生成的本机指令和字节码指令在运行时都在JVM堆栈上吗?对于不同的方法,是的。最初关于交互的难题是编译代码如何操作堆上的Java对象。这非常清楚。当看到“invokevirtual”时,是否有编译代码和字节代码之间转换的链接?