HotSpot中執(zhí)行引擎技術(shù)詳解(二)——線索解釋與模板解釋器

線索解釋

一般來說,當(dāng)提起解釋器的時候,大部分人腦海里面浮現(xiàn)出來的模型都是:

while(instruction != null){
    switch (instruction) {
        case ins1: doSomething1();
        case ins2: doSomething2();
        ...
    }

    instruction = getNextInstruction();
}

其典型特征就是,在一個主循環(huán)里面使用switch來做指令的分派。這種解釋器模式被稱為譯碼分派(decode-and-dispatch),使用switch的情況下,也被稱為“switch-and-dispatch”。

譯碼分派

這種實現(xiàn)方式雖然簡單直接,但是其本身在性能上表現(xiàn)十分糟糕。這種模式,最為影響性能的地方就在于指令分派那一步。指令分派需要線性遍歷每一條指令,最糟糕的情況下,就是要遍歷整個指令集??刂屏鞯霓D(zhuǎn)移也會對性能產(chǎn)生很大的影響。在現(xiàn)代處理器上,性能提高的一個很重要因素就是指令預(yù)測。然而在這種譯碼分派模式下,指令預(yù)測變得十分困難。

很顯然,HotSpot并沒有采用這種模式,它采用了一種被稱為線索解釋(Threaded interpretation)的方法。該方法對于譯碼分派有一個十分重大的改進(jìn):它將跳轉(zhuǎn)地址直接附在了指令之后。如圖:

線索解釋

這里的跳轉(zhuǎn)地址,在HotSpot使用模板解釋器的情況下,實際上是下一條字節(jié)碼指令對應(yīng)的機(jī)器碼所在的地址。

模板解釋器

模板解釋器是一個很神奇的東西,它和一般人想的解釋是有很大的區(qū)別的。按照一般的想法,我們知道HotSpot是利用C++來實現(xiàn)的,那么相當(dāng)然的就是以為對于每一條字節(jié)碼指令來說,其對應(yīng)的解釋例程就是一段C++代碼。這也是對的,HotSpot早期的解釋器就是這樣實現(xiàn)的,這種解釋器被稱為字節(jié)碼解釋器。

但是用C++來解釋一條字節(jié)碼指令,肯定是很低效的。可以想見的是,每一條字節(jié)碼的執(zhí)行,都需要很長的一段C++代碼。舉個例子,add指令的C++實現(xiàn)方法,大概是先訪問兩次內(nèi)存(也可以訪問一次,而后在分割),將操作數(shù)從操作數(shù)棧取出來,而后使用C++的加法操作符將其相加,然后再將結(jié)果寫進(jìn)去操作數(shù)棧。整個過程,至少需要訪問兩次內(nèi)存,還需要三個C++局部變量。

為了進(jìn)一步提高性能,HotSpot使用了模板解釋器。模板解釋器概念上十分簡單,就是每一條字節(jié)碼指令都對應(yīng)一個機(jī)器碼模板。這部分模板被放置在HotSpot的TemplateTable中:

// src/share/vm/interpreter/templateTable.cpp
void TemplateTable::initialize() {
  //其余代碼,一些變量初始化
  //                                    interpr. templates
  // Java spec bytecodes                ubcp|disp|clvm|iswd  in    out   generator             argument
  def(Bytecodes::_nop                 , ____|____|____|____, vtos, vtos, nop                 ,  _           );
  def(Bytecodes::_aconst_null         , ____|____|____|____, vtos, atos, aconst_null         ,  _           );
  def(Bytecodes::_iconst_m1           , ____|____|____|____, vtos, itos, iconst              , -1           );
  def(Bytecodes::_iconst_0            , ____|____|____|____, vtos, itos, iconst              ,  0           );
  //其余指令的定義
  // 其余代碼
}

機(jī)器碼生成是在前面代碼中的generator那一列被指定的生成器完成的。舉例來說,在Bytecodes::_iconst_0的字節(jié)碼模板定義里面,指定的生成器叫做iconst。因為機(jī)器碼是依賴于具體的指令集架構(gòu)的,所以這部分代碼放在:

// src/cpu/x86/vm/templateTable_x86_64.cpp
void TemplateTable::iconst(int value) {
  transition(vtos, itos);
  if (value == 0) {
    __ xorl(rax, rax);
  } else {
    __ movl(rax, value);
  }
}

機(jī)器碼生成

前面我們還提到,HotSpot是依賴于線索解釋的,也就是說,在當(dāng)前字節(jié)碼指令對應(yīng)的機(jī)器碼指令執(zhí)行完成之后,應(yīng)該跳轉(zhuǎn)到下一條字節(jié)碼指令對應(yīng)的第一條機(jī)器碼指令的地址上。
要理解這一點,要先回到機(jī)器碼生成最開始的地方:

// src/share/vm/interpreter/templateInterpreter.cpp
void TemplateInterpreterGenerator::generate_and_dispatch(Template* t, TosState tos_out) {
  //其余代碼
  // generate template
  t->generate(_masm);
  // advance
  if (t->does_dispatch()) {
    //...一些代碼
  } else {
    // dispatch to next bytecode
    __ dispatch_epilog(tos_out, step);
  }
}

最關(guān)鍵就是t->generate(_masm)和dispatch_epilog(tos_out, step)。第一句就是生成該字節(jié)碼對應(yīng)的機(jī)器碼,參數(shù)_masm就是匯編生成器。
后面一句則是跳轉(zhuǎn)到了下一條字節(jié)碼指令那里。事實上,HotSpot第一步的確是找到下一條字節(jié)碼指令,這是通過將存儲現(xiàn)在字節(jié)碼地址的寄存器的值加上指令長度來實現(xiàn)的。但是HotSpot在執(zhí)行機(jī)器碼指令的時候,執(zhí)行完當(dāng)前字節(jié)碼指令的最后一條機(jī)器碼指令之后,跳轉(zhuǎn)的是下一條字節(jié)碼指令對應(yīng)的第一條機(jī)器碼指令地址。也就是意味著,在生成字節(jié)碼對應(yīng)的機(jī)器碼之后,還要再生成跳轉(zhuǎn)的機(jī)器碼指令。
我們可以繼續(xù)追溯這個dispatch_epilog(tos_out, step)方法,直到:

// src/cpu/x86/vm/interp_masm_x86_64.cpp
void InterpreterMacroAssembler::dispatch_base(TosState state,
                                              address* table,
                                              bool verifyoop) {
  // ...其余代碼
  lea(rscratch1, ExternalAddress((address)table));
  jmp(Address(rscratch1, rbx, Address::times_8));
}

jmp這一句,就是生成了這條跳轉(zhuǎn)的機(jī)器碼指令。

關(guān)于模板解釋器的源碼解讀,網(wǎng)上有很多的資源,讀者可以自行去查找,我這里就不重復(fù)前人已經(jīng)做得很好的工作了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容