国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

KVM的執(zhí)行引擎(下) — 指令集

2019-11-18 16:25:50
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

指令集是虛擬機(jī)中最底層也是最核心的部分,java程序中的變量賦值、函數(shù)調(diào)用等所有操作最后都要被轉(zhuǎn)化為一條條的指令來(lái)執(zhí)行。

指令集是在Java虛擬機(jī)規(guī)范中定義的,各種虛擬機(jī)實(shí)現(xiàn)要給予精確的實(shí)現(xiàn),下面就來(lái)介紹一下指令集的分類以及在KVM中是如何實(shí)現(xiàn)的。

在頭文件kvm/vmcommon/h/interPRet.h中有如下對(duì)指令集種類的定義:

Word-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid">
typedef enum {
        NOP         = 0x00,
        ACONST_NULL = 0x01,
        ICONST_M1   = 0x02,
……
        LASTBYTECODE          = 0xDF
} ByteCode ;

以及每條指令的名字:

#define BYTE_CODE_NAMES {              
    "NOP",              /*  0x00 */  
    "ACONST_NULL",      /*  0x01 */  
"ICONST_M1",        /*  0x02 */  
……
"CUSTOMCODE"            /*  0xDF */ }

Java虛擬機(jī)的指令集非常多,大概有200種左右,本篇不詳細(xì)介紹每一條指令的功能和參數(shù),只選取幾個(gè)典型的指令作為例子,介紹它們是如何實(shí)現(xiàn)的。

KVM中,所有指令的實(shí)現(xiàn)都放在kvm/vmcommon/src/bytecodes.c中,每一條指令都遵從如下的形式:


SELECT(指令號(hào))
    {Operations}
DONE(跳轉(zhuǎn)位置)

注:
#define SELECT(l1)                      case l1: {
#define SELECT2(l1, l2)                 case l1: case l2: {
#define SELECT3(l1, l2, l3)             case l1: case l2: case l3: {
#define SELECT4(l1, l2, l3, l4)         case l1: case l2: case l3: case l4: {
#define SELECT5(l1, l2, l3, l4, l5)     case l1: case l2: case l3: case l4: case l5: {
#define SELECT6(l1, l2, l3, l4, l5, l6) case l1: case l2: case l3: case l4: case l5: case l6: {
#define DONE(n)    } goto next##n;
#define DONEX      }
#define DONE_R     } goto reschedulePoint;

{operations}部分是該指令的具體實(shí)現(xiàn)。

整個(gè)bytecodes.c文件其實(shí)是一個(gè)switch分支結(jié)構(gòu)中的cases部分,這個(gè)文件中定義了所有的case。這個(gè)文件會(huì)被源文件kvm/vmcommon/src/execute.c所包含,execute.c中定義有一個(gè)方法

void SlowInterpret(ByteCode token);

它是解釋執(zhí)行Java指令的主要函數(shù),參數(shù)token就是一條指令,在本函數(shù)中會(huì)有一個(gè)switch()結(jié)構(gòu)來(lái)選擇token的執(zhí)行路徑:
void SlowInterpret(ByteCode token) {

switch (token) {

#include "bytecodes.c"

next3:  ip++;
next2:  ip++;
next1:  ip++;
next0:
reschedulePoint:
    return;
}

函數(shù)結(jié)尾處的幾個(gè)標(biāo)簽是指令完成后會(huì)跳轉(zhuǎn)到的地方。

 

依據(jù)Java虛擬機(jī)規(guī)范,虛擬機(jī)指令可以分為裝載和存儲(chǔ)指令、運(yùn)算指令、類型轉(zhuǎn)換指令、對(duì)象創(chuàng)建與操縱指令、操作數(shù)棧管理指令、控制轉(zhuǎn)移指令、方法調(diào)用和返回指令、拋出和處理異常指令、實(shí)現(xiàn)finally指令和同步指令等10類,下面從中選取幾個(gè)簡(jiǎn)單的指令來(lái)看一看它們是如何設(shè)計(jì)的:


1ICONST_0

說(shuō)明:

無(wú)參數(shù),向操作數(shù)棧中壓入int型常量0。

實(shí)現(xiàn)代碼:

SELECT(ICONST_0)       /* Push integer constant 0 onto the operand stack */
        pushStack(0);
DONE(1)
宏經(jīng)適當(dāng)展開(kāi)后為:
case ICONST_0: {
    *++GlobalState.gs_sp = 0;
} goto next1;

GlobalState.gs_sp是當(dāng)前幀內(nèi)操作數(shù)棧的指針,ICONST_0指令要做的只是把指針向后移動(dòng)一個(gè)字(注意是“字”而不是“字節(jié)”),然后給新字賦值為0;最后程序計(jì)數(shù)器ip自加1,表明沒(méi)有跳轉(zhuǎn),接著執(zhí)行下一條指令。

2DSTORE

說(shuō)明:

本指令帶有一個(gè)字節(jié)的參數(shù)offset,作用是從操作數(shù)棧中讀取一個(gè)double型的值(雙字)并存放到局部變量區(qū)中的offset和offset+1位置。

實(shí)現(xiàn)代碼:

SELECT(DSTORE)           /* Store double into local variable */
        unsigned int index = ip[1];
        lp[index+1] = popStack();
        lp[index]   = popStack();
DONE(2)
宏展開(kāi)為:
case DSTORE: {
        unsigned int index = GlobalState.gs_ip[1];
        GlobalState.gs_lp[index+1] = *GlobalState.gs_sp --;
        GlobalState.gs_lp[index]   = *GlobalState.gs_sp --;
} goto next2;

首先從程序計(jì)數(shù)器的下一個(gè)字節(jié)中取出目標(biāo)位置的偏移量index,然后從操作數(shù)棧中彈出兩個(gè)字分別作為double型數(shù)的底位和高位存入局部變量lp所指向的區(qū)域中的合適位置。

3I2L

說(shuō)明:

無(wú)參數(shù),將操作數(shù)棧中的當(dāng)前操作數(shù)由int型轉(zhuǎn)換為long型。

實(shí)現(xiàn)代碼:

SELECT(I2L)                              /* Convert integer to long */
        long value = *(long *)sp;
#if BIG_ENDIAN
        ((long *)sp)[1] = value;
        ((long *)sp)[0] = value >> 31;
#elif LITTLE_ENDIAN  !COMPILER_SUPPORTS_LONG
        ((long *)sp)[1] = value >> 31;
#else
        SET_LONG(sp, value);
#endif
        getSP()++;
DONE(1)

由于long比int表示的范圍大,所以在擴(kuò)展時(shí)多出來(lái)的高位只是用于符號(hào)擴(kuò)展。先從操作數(shù)棧中取出int型整數(shù)并把它作為一個(gè)long型,如果定義了宏BIG_ENDIAN,說(shuō)明操作數(shù)棧中的存儲(chǔ)規(guī)則是高字節(jié)在前,這時(shí)要把value的值向后移一個(gè)字作為低字來(lái)用,高字用于作符號(hào)擴(kuò)展;如果操作數(shù)棧中是低位在前的話,原位置中的字不用動(dòng),只要把下一個(gè)字作符號(hào)擴(kuò)展即可。最近,由于當(dāng)前操作數(shù)由一個(gè)字變?yōu)閮蓚€(gè)字,所以sp要自加1。

4LMUL

說(shuō)明:

無(wú)參數(shù);從棧中彈出兩個(gè)long型數(shù),相乘,然后將所得long型結(jié)果壓回棧。

實(shí)現(xiàn)代碼:


SELECT(LMUL)                             /* Mul long */
        long64 rvalue = GET_LONG(sp - 1);
        long64 lvalue = GET_LONG(sp - 3);
        SET_LONG(sp - 3, ll_mul(lvalue, rvalue));
        getSP() -= 2;
DONE(1)

 

先從操作數(shù)棧中分別取出兩個(gè)雙字長(zhǎng)的長(zhǎng)整型數(shù),使用ll_mul()宏把它們相乘(這個(gè)宏的實(shí)現(xiàn)是依賴于操作系統(tǒng)的),然后再把相乘的結(jié)果寫(xiě)入棧中。整個(gè)操作從棧中彈出了四個(gè)字而壓入兩個(gè),在過(guò)程中指針sp都沒(méi)有變過(guò),所以最后要把sp向前移兩個(gè)字。

 

以下作為例子的都是一些簡(jiǎn)單的指令,但并不是所有指令都這樣簡(jiǎn)單,像對(duì)象操作、異常處理和方法調(diào)用幾類指令都十分的復(fù)雜,本篇只是演示指令的原理,所以不介紹太復(fù)雜的指令。

進(jìn)入討論組討論。

(出處:http://m.survivalescaperooms.com)



發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 苏尼特右旗| 霞浦县| 梁山县| 万年县| 田东县| 建瓯市| 兴义市| 青川县| 肥城市| 巧家县| 井陉县| 泸西县| 阳东县| 嘉兴市| 太原市| 怀化市| 民权县| 青冈县| 平山县| 乌拉特后旗| 永胜县| 丽水市| 河西区| 交城县| 宝山区| 海原县| 佛坪县| 吉木乃县| 盱眙县| 和林格尔县| 奈曼旗| 通城县| 舒兰市| 莆田市| 临泽县| 深圳市| 清水县| 荆门市| 荆州市| 泰顺县| 贡觉县|