六乌企、Class字節(jié)碼指令解釋執(zhí)行

JVM指令主要包含了一下幾種類型:加載和存儲指令、運算指令成玫、類型轉換指令加酵、對象創(chuàng)建與訪問指令、操作數(shù)棧管理指令哭当、控制轉移指令猪腕、方法調用和返回指令、異常處理指令钦勘、同步指令等陋葡。
基于棧的解釋器執(zhí)行過程
下面看一下一個簡單的代碼片段,如下所示:

public class StackTest {
 
    public int calc() {
        int a = 100;
        int b = 200;
        int c = 300;
        return (a + b) * c;
    }
 
}

通過jclasslib工具或者javap -verbose命令彻采,可以得到calc()方法的字節(jié)碼指令腐缤。如下所示:

 0 bipush 100
 2 istore_1
 3 sipush 200
 6 istore_2
 7 sipush 300
10 istore_3
11 iload_1
12 iload_2
13 iadd
14 iload_3
15 imul
16 ireturn

下面來具體的說明一下整個方法的執(zhí)行過程:


image.png

image.png

image.png

image.png

image.png

image.png

image.png

上面的指令執(zhí)行過程只是一個概念模型捌归,JVM會對過程做一些優(yōu)化來提高性能,JVM在實際運行時可能執(zhí)行過程差距比較大岭粤,并且不同虛擬機的執(zhí)行也不盡相同惜索。

加載和存儲指令
加載和存儲指令用于數(shù)據(jù)在棧幀中的局部變量表和操作數(shù)棧之間的來回傳輸。
將一個局部變量加載到操作數(shù)棧:iload剃浇、iload_巾兆、lload、lload_虎囚、fload角塑、fload_、dload溜宽、dload吉拳、aload、aload适揉。
將一個數(shù)值從操作數(shù)棧存儲到局部變量表:istore留攒、istore_、lstore嫉嘀、lstore_炼邀、fstore、fstore_剪侮、dstore拭宁、dstore_、astore瓣俯、astore_杰标。
將一個常量加載到操作數(shù)棧:bipush、sipush彩匕、ldc腔剂、ldc_w、ldc2_w驼仪、aconst_null掸犬、iconst_ml、iconst_绪爸、lconst_湾碎、fconst_、dconst_奠货。
擴充局部變量表的訪問索引的指令:wide介褥。

運算指令
運算指令作用于操作數(shù)棧上面的2個值的特定運算,并且把結果重新存入操作數(shù)棧頂。大體上可以分為2類:對整型呻顽、浮點型數(shù)值運算雹顺。因為JVM指令集中沒有byte、short廊遍、char和boolean類型的算術運算嬉愧,所以都使用了對應的int類型的指令代替。
加法指令:iadd喉前、ladd没酣、fadd、dadd
減法指令:isub卵迂、lsub裕便、fsub、dsub
乘法指令:imul见咒、lmul偿衰、fmul、dmul
除法指令:idiv改览、ldiv下翎、fdiv、ddiv
求余指令:irem宝当、lrem视事、frem、drem
取反指令:ineg庆揩、lneg俐东、fneg、dneg
位移指令:ishl订晌、ishr虏辫、iushr、lshl锈拨、lshr乒裆、lushr
按位或指令:ior、lor
按位與指令:iand推励、land
按位異或指令:ixor、lxor
局部變量自增指令:iinc
比較指令:dcmpg肉迫、dcmpl验辞、fcmpg、fcmpl喊衫、lcmp

類型轉換指令
類型轉換指令可以將2種不同類型的數(shù)值相互轉換跌造,這些轉換一般實現(xiàn)于代碼中的顯示類型轉換,主要有以下類型:
int類型到long、float或者double類型
long類型到float壳贪、double類型
float類型到double類型
對于顯示的類型轉換陵珍,一般情況下都是窄化類型轉換(也就是丟失精度的轉化,如:long轉為int等)违施。常見的轉換指令有:i2b互纯、i2c、i2s磕蒲、l2i留潦、f2i、f2l辣往、d2i兔院、d2l、d2f等站削。

對象創(chuàng)建與訪問指令
對于普通對象和數(shù)組的創(chuàng)建坊萝,JVM分別使用了不同的指令去處理。
創(chuàng)建普通對象的指令:new
創(chuàng)建數(shù)組的指令:newarray许起、anewarray、multianewarray
訪問類變量(static類型)和實例變量(非static類型)的指令:getstatic街氢、putstatic扯键、getfield珊肃、putfield
把一個數(shù)組加載到操作數(shù)棧的指令:baload、caload伦乔、saload、iaload烈和、laload、faload招刹、daload恬试、aaload
將一個操作數(shù)棧的值存儲到數(shù)組元素中的指令:bastore疯暑、castore、sastore妇拯、iastore洗鸵、fastore、dastore仗嗦、aastore
取數(shù)組長度的指令:arraylength
檢查普通對象類型的指令:instanceof膘滨、checkcast

操作數(shù)棧管理指令
如同一個普通的堆棧一樣,JVM提供了直接操作操作數(shù)棧的指令稀拐。
將操作數(shù)棧頂?shù)?個或2個元素出棧:pop1火邓、pop2
復制棧頂1個或2個元素,并將副本的1份或者2份重新入棧:dup钩蚊、dup2贡翘、dup_x1、dup2_x1砰逻、dup_x2鸣驱、dup2_x2
將棧頂?shù)膬蓚€數(shù)值互換:swap

控制轉移指令
控制轉移指令可以讓JVM,跳轉到指定的偏移地址的字節(jié)碼執(zhí)行蝠咆。從上面的模型圖看來踊东,就是修改程序計數(shù)器的值。
分支條件:ifeq刚操、iflt闸翅、ifle、ifne菊霜、ifgt坚冀、ifge、ifnull鉴逞、ifnonnull记某、if_icmpeq、if_icmpne构捡、if_icmplt液南、if_icmpgt、if_icmple勾徽、if_icmpge滑凉、if_acmpeq、if_acmpne喘帚。
復合條件分支:tableswitch畅姊、lookupswitch
無條件分支:goto、goto_w吹由、jsr涡匀、jsr_w、ret溉知。

方法調用和返回指令
方法調用包含了以下指令。
invokevirtual指令:用于調用對象的實例方法,根據(jù)對象的實際類型分派(虛方法分派)级乍。
invokeinterface指令:用于調用接口方法舌劳,它會在運行時搜索一個實現(xiàn)這個接口的對象,找出合適的方法調用玫荣。
invokespecial指令:用于調用一些需要特殊處理的實例方法甚淡,包括初始化方法、私有方法捅厂、父類方法贯卦。
invokestatic指令:用于調用類方法(static方法)。
invokedynamic指令:用于在運行時動態(tài)解析出調用點限定符所引用的方法焙贷,并執(zhí)行。
上述的前4條指令都是固化在JVM內部的辙芍,invokedynamic的分派邏輯是由用戶所設定的引導方法決定的故硅。
方法的調用指令與數(shù)據(jù)類型無關,而方法的返回指令是根據(jù)返回值區(qū)分的往踢。包括:ireturn(當返回值是boolean徘层、byte、char山上、short英支、int)、lreturn干花、freturn、dreturn和areturn抡驼。return指令提供給:返回值為void的指令肿仑、實例方法初始化碎税、接口類方法初始化馏锡。

異常處理指令
Java程序中顯示拋出異常的操作都是由athrow指令實現(xiàn)的杯道。

同步指令
JVM可以支持方法級的同步和方法內的同步,這兩種同步結構都是由管程(Monitor)來實現(xiàn)的萎庭。
方法級的同步是隱式的齿拂,無需通過字節(jié)碼指令來控制。JVM可以從方法常量池的方法表結構中的ACC_SYNCHRONIZED訪問標志达舒,得到其是否為同步方法叹侄。
對于方法中的同步塊,JVM中使用monitorenter和monitorexit兩條指令來支持贯底。下面參見一個代碼清單:

public class SyncInstruction {
    
    void onlyMe(Object f) {
        synchronized (f) {
            System.out.println("synchronized control.");
        }
    }
 
}

對應的指令序列如下:

 0 aload_1          // 將對象f入棧
 1 dup              // 復制棧頂元素(即f的引用)
 2 astore_2         // 將棧頂元素存儲到局變量表Slot 2中
 3 monitorenter     // 以棧頂元素(f)作為鎖撒强,開始同步
 4 getstatic #2 <java/lang/System.out>      // 訪問System的靜態(tài)屬性out
 7 ldc #3 <synchronized control.>       // 將字符串常量"synchronized control."壓入操作數(shù)棧頂
 9 invokevirtual #4 <java/io/PrintStream.println>       // 調用PrintStream.println()方法
12 aload_2      // 將局部變量表Slot 2的元素(f)入棧
13 monitorexit  // 退出同步
14 goto 22 (+8) // 方法正常退出飘哨,跳轉到22行
17 astore_3     // 這里開始是異常路徑,它的偏移量記錄在異常表中浊服,如下圖所示
18 aload_2      // 將局部變量表Slot 2的元素(f)入棧
19 monitorexit  // 退出同步
20 aload_3      // 將局變量表Slot 3的元素(異常對象)入棧
21 athrow       // 把異常重新拋出給onlyMe()方法的調用者
22 return       // 方法正常返回

異常表如下所示:


image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末牙躺,一起剝皮案震驚了整個濱河市腕扶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脓恕,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件激蹲,死亡現(xiàn)場離奇詭異江掩,居然都是意外死亡环形,警方通過查閱死者的電腦和手機衙傀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門统抬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人聪建,你說我怎么就攤上這事∏嫖觯” “怎么了挥下?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵棚瘟,是天一觀的道長。 經(jīng)常有香客問我庄蹋,道長禀苦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任蔗包,我火速辦了婚禮慧邮,結果婚禮上舟陆,老公的妹妹穿的比我還像新娘秦躯。我一直安慰自己裆装,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布茎活。 她就那樣靜靜地躺著琢唾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪懒熙。 梳的紋絲不亂的頭發(fā)上普办,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機與錄音定庵,去河邊找鬼踪危。 笑死,一個胖子當著我的面吹牛畴博,可吹牛的內容都是我干的蓝仲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼亮隙,長吁一口氣:“原來是場噩夢啊……” “哼垢夹!你這毒婦竟也來了?” 一聲冷哼從身側響起促王,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蝇狼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后迅耘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡冯事,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了缓熟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡垦写,死狀恐怖梯投,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情分蓖,我是刑警寧澤尔许,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站蒸甜,受9級特大地震影響余佛,放射性物質發(fā)生泄漏。R本人自食惡果不足惜辉巡,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一红氯、第九天 我趴在偏房一處隱蔽的房頂上張望咕痛。 院中可真熱鬧喇嘱,春花似錦、人聲如沸腔丧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽衣厘。三九已至,卻和暖如春影暴,著一層夾襖步出監(jiān)牢的瞬間探赫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工妆兑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毛仪,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓谱姓,卻偏偏與公主長得像刨晴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子狈癞,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359