字節(jié)碼與數(shù)據(jù)類(lèi)型
在Java虛擬機(jī)的指令集中霎俩,大多數(shù)的指令都包含了其操作所對(duì)應(yīng)的數(shù)據(jù)類(lèi)型信息哀军。
加載和存儲(chǔ)指令
加載和存儲(chǔ)指令用于將數(shù)據(jù)在幀棧中的局部變量表和操作數(shù)棧之間來(lái)回傳輸。這些指令包括如下內(nèi)容:
1:將一個(gè)局部變量加載到操作棧:iload打却、iload_<n>杉适、lload、lload_<n>柳击、fload猿推、fload_<n>、dload捌肴、dload_<n>蹬叭、aload、aload_<n>状知。
2:將一個(gè)數(shù)值從操作數(shù)棧存儲(chǔ)到局部變量表:istore秽五、istore_<n>、lstore试幽、lstore_<n>筝蚕、fstore、fstore_<n>铺坞、dstore起宽、dstore_<n>、astore济榨、astore_<n>坯沪;
3:將一個(gè)常量加載到操作數(shù)棧:bipush、sipush擒滑、ldc腐晾、ldc_w、ldc2_w丐一、aconst_null藻糖、iconst_ml、iconst_<i>库车、lconst_<l>巨柒、fconst_<f>、dconst_<d>柠衍;
4:擴(kuò)充局部變量表的訪問(wèn)索引指令:wide洋满。
存儲(chǔ)數(shù)據(jù)的操作數(shù)棧和局部變量表主要就是由加載和存儲(chǔ)指令進(jìn)行操作,除此之外珍坊,還有少量指令牺勾,如訪問(wèn)對(duì)象的字段或數(shù)組元素的指令也會(huì)向操作數(shù)棧傳輸數(shù)據(jù)。
注意:上面類(lèi)似這樣的格式:iload_<n>:代表了iload_0阵漏、iload_1驻民、iload_2和iload_3這幾條指令
運(yùn)算指令
運(yùn)算或算數(shù)指令用于對(duì)兩個(gè)操作數(shù)棧上的值進(jìn)行某種特定運(yùn)算,并把結(jié)果重新存入到操作棧頂履怯。大體上算數(shù)指令可以分為兩種:對(duì)整型數(shù)據(jù)進(jìn)行運(yùn)算的指令和對(duì)浮點(diǎn)型數(shù)據(jù)進(jìn)行運(yùn)算的指令川无,無(wú)論哪種算數(shù)指令,都使用Java虛擬機(jī)的數(shù)據(jù)類(lèi)型虑乖,由于沒(méi)有直接支持byte懦趋、short、char和boolean類(lèi)型的算術(shù)指令疹味,對(duì)于這類(lèi)數(shù)據(jù)的運(yùn)算仅叫,應(yīng)使用操作int類(lèi)型的指令代替。整數(shù)和浮點(diǎn)數(shù)的算數(shù)指令在溢出和被除零的時(shí)候也有各自不相同的行為表現(xiàn)糙捺。所有的算術(shù)指令如下:
- 加法指令: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疏之、lshl殿雪、fshl、dshl锋爪;
- 按位或指令:ior丙曙、lor;
- 按位與指令:iand其骄、land亏镰;
- 按位異或指令:ixor、lxor拯爽;
- 局部變量自增指令:iinc索抓;
- 比較指令:dcmpg、dcmpl毯炮、fcmpg逼肯、fcmpl、lcmp桃煎。
類(lèi)型轉(zhuǎn)換指令
類(lèi)型轉(zhuǎn)換指令可以將兩種不同的數(shù)值類(lèi)型的進(jìn)行相互轉(zhuǎn)換篮幢,這些轉(zhuǎn)換操作一般用于實(shí)現(xiàn)用戶代碼中的顯示類(lèi)型轉(zhuǎn)換操作或者用來(lái)處理字節(jié)碼指令集中數(shù)據(jù)類(lèi)型相關(guān)指令無(wú)法與數(shù)據(jù)類(lèi)型一一對(duì)應(yīng)的問(wèn)題。
JVM直接支持(即轉(zhuǎn)換時(shí)無(wú)需顯示的轉(zhuǎn)換指令)以下數(shù)值類(lèi)型的寬化類(lèi)型轉(zhuǎn)換(Widening Numberic Conversions为迈,即小范圍類(lèi)型向大范圍類(lèi)型的安全轉(zhuǎn)換):
int類(lèi)型到long三椿、float缺菌、或者double類(lèi)型;
long類(lèi)型到float搜锰、double類(lèi)型伴郁;
float類(lèi)型到double類(lèi)型。
相對(duì)的纽乱,處理窄化類(lèi)型轉(zhuǎn)換(Narrowing Numberic Conversions)時(shí) 蛾绎,必須顯示地使用轉(zhuǎn)換指令來(lái)完成昆箕,這些轉(zhuǎn)換指令包括:i2b鸦列、i2c、i2s鹏倘、l2i薯嗤、f2i、f2l纤泵、d2i骆姐、d2l、d2f捏题。窄化類(lèi)型轉(zhuǎn)換可能導(dǎo)致轉(zhuǎn)換結(jié)果產(chǎn)生不同的正負(fù)號(hào)玻褪、不同的數(shù)量級(jí)情況、轉(zhuǎn)換過(guò)程很可能導(dǎo)致數(shù)值的精確度丟失公荧。
注意:數(shù)值類(lèi)型的窄化處理永遠(yuǎn)不可能導(dǎo)致虛擬機(jī)拋出運(yùn)行時(shí)異常带射。
對(duì)象創(chuàng)建與訪問(wèn)指令
雖然類(lèi)實(shí)例和數(shù)組都是對(duì)象,但JVM對(duì)類(lèi)實(shí)例和數(shù)組的創(chuàng)建與操作采用了不同的字節(jié)碼指令循狰。對(duì)象創(chuàng)建后窟社,就可以通過(guò)對(duì)象訪問(wèn)指令獲取對(duì)象實(shí)例或者數(shù)組中的字段或者數(shù)組元素,這些指令如下:
1绪钥,創(chuàng)建類(lèi)實(shí)例的指令:new灿里;
2,創(chuàng)建數(shù)組的指令:newarray程腹、anewarray匣吊、multianewarray;
3寸潦,訪問(wèn)類(lèi)字段(static字段荐绝,或者成為類(lèi)變量)和實(shí)例字段(非static字段,或者稱(chēng)為實(shí)例變量)的指令:getfield倔既、putfield善已、getstatic、putstatic池户;
4咏雌,把一個(gè)數(shù)組元素加載到操作數(shù)棧的指令:baload凡怎、caload、saload赊抖、iaload统倒、laload、faload氛雪、daload房匆、aaload;
5报亩,將一個(gè)操作數(shù)棧的值存儲(chǔ)到數(shù)組元素中的指令:bastore浴鸿、castore、sastore弦追、iastore岳链、fastore、dastore劲件、aastore掸哑;
6,取數(shù)組長(zhǎng)度的指令:arraylength零远;
7苗分,檢查類(lèi)實(shí)例類(lèi)型的指令:instanceof、checkcast牵辣。
操作數(shù)棧管理指令
如同操作一個(gè)普通數(shù)據(jù)結(jié)構(gòu)中的堆棧那樣摔癣,JVM直接提供了一些用于直接操作操作數(shù)棧的指令,包括:
1服猪,將操作數(shù)棧的棧頂一個(gè)或兩個(gè)元素出棧:pop供填、pop2;
2罢猪,復(fù)制棧頂一個(gè)或兩個(gè)數(shù)值并將復(fù)制值或雙份的復(fù)制值重新壓入棧頂:dup近她、dup2、dup_x1膳帕、dup2_x1粘捎、dup_x2、dup2_x2危彩;
3攒磨,將棧最頂端的兩個(gè)數(shù)值互換:swap。
控制轉(zhuǎn)移指令
控制轉(zhuǎn)移指令可以讓JVM有條件或者無(wú)條件地從指定的位置指令而不是控制轉(zhuǎn)移指令的下一條指令繼續(xù)執(zhí)行程序汤徽,從概念模型上理解娩缰,可以認(rèn)為控制轉(zhuǎn)移指令就是在有條件或者無(wú)條件地修改PC寄存器的值≮烁控制轉(zhuǎn)移指令如下:
條件分支:ifeq拼坎、iflt浮毯、ifle、ifne泰鸡、ifgt债蓝、ifge、ifnull盛龄、ifnonnull饰迹、if_icmpeq、if_icmpne余舶、if_icmplt啊鸭、if_icmpgt、if_icmple欧芽、if_icmpge莉掂、if_acmpeq和if_acmpne葛圃;
復(fù)合條件分支:tableswitch千扔、lookupswitch;
無(wú)條件分支:goto库正、goto_w曲楚、jsr、jsr_w褥符、ret龙誊;
在JVM中有專(zhuān)門(mén)的指令集用來(lái)處理int(boolean型、byte型喷楣、char型和short型的條件分支比較也都用int型趟大,對(duì)于float型、double型的條件分支比較操作則會(huì)先執(zhí)行相應(yīng)類(lèi)型的比較運(yùn)算指令铣焊,它會(huì)返回一個(gè)整型值到操作數(shù)棧中逊朽,然后按int型執(zhí)行)和reference類(lèi)型的條件分支比較操作,為了可以無(wú)需明顯標(biāo)識(shí)一個(gè)實(shí)體值是否為null曲伊,也有專(zhuān)門(mén)的指令來(lái)檢測(cè)null值叽讳。
方法調(diào)用和返回指令
方法調(diào)用指令舉例:
invokevirtual指令用于調(diào)用對(duì)象的實(shí)例方法,根據(jù)對(duì)象的實(shí)際類(lèi)型進(jìn)行分派(虛方法分派)坟募,這也是java語(yǔ)言最常見(jiàn)的方法分派方式岛蚤;
invokeinterface指令用于調(diào)用接口方法,它會(huì)在運(yùn)行時(shí)搜索一個(gè)實(shí)現(xiàn)了這個(gè)接口方法的對(duì)象懈糯,找出適合的方法進(jìn)行調(diào)用涤妒;
invokespecial指令用于調(diào)用一些需要特殊處理的實(shí)例方法,包括實(shí)例初始化方法赚哗,私有方法和父類(lèi)方法她紫;
invokestatic指令用于調(diào)用類(lèi)方法(static方法)铁坎;
invokedynamic指令用于在運(yùn)行時(shí)動(dòng)態(tài)解析出調(diào)用點(diǎn)限定符所引用的方法并執(zhí)行該方法,前面4條調(diào)用指令的分派邏輯都固話在JVM內(nèi)部犁苏,而invokedynamic指令的分派邏輯是由用戶所設(shè)定的引導(dǎo)方法決定的硬萍。
方法調(diào)用指令與數(shù)據(jù)類(lèi)型無(wú)關(guān),而方法返回指令是根據(jù)返回值的類(lèi)型區(qū)分的围详,包括ireturn(當(dāng)返回值是boolean朴乖、byte、char助赞、short和int類(lèi)型使用)买羞、lreturn、freturn雹食、dreturn和areturn畜普,另外還有一條return指令供聲明為void的方法、實(shí)例初始化方法以及類(lèi)和接口的類(lèi)初始化方法使用群叶。
異常處理指令
在Java程序中顯示拋出異常的操作(throw語(yǔ)句)都有athrow指令來(lái)實(shí)現(xiàn)吃挑,除了用throw語(yǔ)句顯示拋出異常的情況之外,JVM規(guī)范還規(guī)定了許多運(yùn)行時(shí)異常會(huì)在其他Java虛擬機(jī)指令檢測(cè)到異常時(shí)自動(dòng)拋出街立。而在Java虛擬機(jī)之中舶衬,處理異常不是由字節(jié)碼指令來(lái)實(shí)現(xiàn)的,而是采用異常表來(lái)完成的赎离。
同步指令
JVM可以支持方法級(jí)的同步和方法內(nèi)部一段指令序列的同步逛犹,這兩種同步都使用管程(Monitor)來(lái)支持的。五:公有設(shè)計(jì)和私有實(shí)現(xiàn)
JVM規(guī)范描繪了JVM應(yīng)有的共同程序存儲(chǔ)格式:Class文件格式以及字節(jié)碼指令集梁剔。
理解公有設(shè)計(jì)和私有實(shí)現(xiàn)之間的分界線是很有必要的虽画,JVM實(shí)現(xiàn)必須能夠讀取Class文件并精確實(shí)現(xiàn)包含在其中的JVM代碼的語(yǔ)義。按照虛擬機(jī)規(guī)范一成不變地逐字實(shí)現(xiàn)其中的要求內(nèi)容是一種途徑荣病;但是也可以在滿足JVM規(guī)范要求的情況下對(duì)具體實(shí)現(xiàn)做出修改和優(yōu)化也是可以的码撰,并且JVM規(guī)范明確鼓勵(lì)這么做。
虛擬機(jī)實(shí)現(xiàn)者可以使用這種伸縮性來(lái)讓虛擬機(jī)實(shí)現(xiàn)更高的性能众雷、更低的內(nèi)存消耗或者更好的可移植性灸拍,選擇哪種特性取決于JVM實(shí)現(xiàn)的目標(biāo)和關(guān)注點(diǎn)。虛擬機(jī)實(shí)現(xiàn)主要有以下兩種方式:
- 將輸入的虛擬機(jī)代碼在加載或執(zhí)行時(shí)翻譯成另外一種虛擬機(jī)的指令集砾省;
- 將輸入的虛擬機(jī)代碼在加載或執(zhí)行時(shí)翻譯成宿主機(jī)CPU的本地指令集鸡岗。
精確定義的虛擬機(jī)和目標(biāo)文件格式不應(yīng)當(dāng)對(duì)虛擬機(jī)實(shí)現(xiàn)者創(chuàng)造性產(chǎn)生太多的限制,Java虛擬機(jī)應(yīng)被設(shè)計(jì)成可以允許有眾多不同的實(shí)現(xiàn)编兄,并且各種實(shí)現(xiàn)可以在保持兼容性的同時(shí)提供不同的轩性、新的、有趣的解決方案狠鸳。