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

線(xiàn)索解釋

一般來(lái)說(shuō)窜锯,當(dāng)提起解釋器的時(shí)候突倍,大部分人腦海里面浮現(xiàn)出來(lái)的模型都是:

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

    instruction = getNextInstruction();
}

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

譯碼分派

這種實(shí)現(xiàn)方式雖然簡(jiǎn)單直接腌歉,但是其本身在性能上表現(xiàn)十分糟糕。這種模式齐苛,最為影響性能的地方就在于指令分派那一步翘盖。指令分派需要線(xiàn)性遍歷每一條指令,最糟糕的情況下凹蜂,就是要遍歷整個(gè)指令集馍驯「笪#控制流的轉(zhuǎn)移也會(huì)對(duì)性能產(chǎn)生很大的影響。在現(xiàn)代處理器上汰瘫,性能提高的一個(gè)很重要因素就是指令預(yù)測(cè)狂打。然而在這種譯碼分派模式下,指令預(yù)測(cè)變得十分困難混弥。

很顯然趴乡,HotSpot并沒(méi)有采用這種模式,它采用了一種被稱(chēng)為線(xiàn)索解釋?zhuān)═hreaded interpretation)的方法蝗拿。該方法對(duì)于譯碼分派有一個(gè)十分重大的改進(jìn):它將跳轉(zhuǎn)地址直接附在了指令之后浙宜。如圖:

線(xiàn)索解釋

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

模板解釋器

模板解釋器是一個(gè)很神奇的東西,它和一般人想的解釋是有很大的區(qū)別的萤捆。按照一般的想法裙品,我們知道HotSpot是利用C++來(lái)實(shí)現(xiàn)的,那么相當(dāng)然的就是以為對(duì)于每一條字節(jié)碼指令來(lái)說(shuō)俗或,其對(duì)應(yīng)的解釋例程就是一段C++代碼市怎。這也是對(duì)的,HotSpot早期的解釋器就是這樣實(shí)現(xiàn)的辛慰,這種解釋器被稱(chēng)為字節(jié)碼解釋器区匠。

但是用C++來(lái)解釋一條字節(jié)碼指令,肯定是很低效的帅腌〕叟可以想見(jiàn)的是,每一條字節(jié)碼的執(zhí)行速客,都需要很長(zhǎng)的一段C++代碼戚篙。舉個(gè)例子,add指令的C++實(shí)現(xiàn)方法溺职,大概是先訪(fǎng)問(wèn)兩次內(nèi)存(也可以訪(fǎng)問(wèn)一次岔擂,而后在分割),將操作數(shù)從操作數(shù)棧取出來(lái)浪耘,而后使用C++的加法操作符將其相加乱灵,然后再將結(jié)果寫(xiě)進(jìn)去操作數(shù)棧。整個(gè)過(guò)程七冲,至少需要訪(fǎng)問(wèn)兩次內(nèi)存痛倚,還需要三個(gè)C++局部變量。

為了進(jìn)一步提高性能癞埠,HotSpot使用了模板解釋器状原。模板解釋器概念上十分簡(jiǎn)單聋呢,就是每一條字節(jié)碼指令都對(duì)應(yīng)一個(gè)機(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那一列被指定的生成器完成的削锰。舉例來(lái)說(shuō),在Bytecodes::_iconst_0的字節(jié)碼模板定義里面毕莱,指定的生成器叫做iconst器贩。因?yàn)闄C(jī)器碼是依賴(lài)于具體的指令集架構(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是依賴(lài)于線(xiàn)索解釋的蛹稍,也就是說(shuō),在當(dāng)前字節(jié)碼指令對(duì)應(yīng)的機(jī)器碼指令執(zhí)行完成之后部服,應(yīng)該跳轉(zhuǎn)到下一條字節(jié)碼指令對(duì)應(yīng)的第一條機(jī)器碼指令的地址上唆姐。
要理解這一點(diǎn),要先回到機(jī)器碼生成最開(kāi)始的地方:

// 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é)碼對(duì)應(yīng)的機(jī)器碼奉芦,參數(shù)_masm就是匯編生成器。
后面一句則是跳轉(zhuǎn)到了下一條字節(jié)碼指令那里剧蹂。事實(shí)上声功,HotSpot第一步的確是找到下一條字節(jié)碼指令,這是通過(guò)將存儲(chǔ)現(xiàn)在字節(jié)碼地址的寄存器的值加上指令長(zhǎng)度來(lái)實(shí)現(xiàn)的宠叼。但是HotSpot在執(zhí)行機(jī)器碼指令的時(shí)候先巴,執(zhí)行完當(dāng)前字節(jié)碼指令的最后一條機(jī)器碼指令之后,跳轉(zhuǎn)的是下一條字節(jié)碼指令對(duì)應(yīng)的第一條機(jī)器碼指令地址冒冬。也就是意味著伸蚯,在生成字節(jié)碼對(duì)應(yīng)的機(jī)器碼之后,還要再生成跳轉(zhuǎn)的機(jī)器碼指令窄驹。
我們可以繼續(xù)追溯這個(gè)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)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市龙宏,隨后出現(xiàn)的幾起案子棵逊,更是在濱河造成了極大的恐慌,老刑警劉巖银酗,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辆影,死亡現(xiàn)場(chǎng)離奇詭異徒像,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蛙讥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)锯蛀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人次慢,你說(shuō)我怎么就攤上這事旁涤。” “怎么了迫像?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵劈愚,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我闻妓,道長(zhǎng)菌羽,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任由缆,我火速辦了婚禮注祖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘犁功。我一直安慰自己氓轰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布浸卦。 她就那樣靜靜地躺著署鸡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪限嫌。 梳的紋絲不亂的頭發(fā)上靴庆,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音怒医,去河邊找鬼炉抒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛稚叹,可吹牛的內(nèi)容都是我干的焰薄。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼扒袖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼塞茅!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起季率,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤野瘦,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鞭光,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吏廉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惰许。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片席覆。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖啡省,靈堂內(nèi)的尸體忽然破棺而出娜睛,到底是詐尸還是另有隱情,我是刑警寧澤卦睹,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布畦戒,位于F島的核電站,受9級(jí)特大地震影響结序,放射性物質(zhì)發(fā)生泄漏障斋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一徐鹤、第九天 我趴在偏房一處隱蔽的房頂上張望垃环。 院中可真熱鬧,春花似錦返敬、人聲如沸遂庄。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)涛目。三九已至,卻和暖如春凛澎,著一層夾襖步出監(jiān)牢的瞬間霹肝,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工塑煎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沫换,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓最铁,卻偏偏與公主長(zhǎng)得像讯赏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子冷尉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容