KVM 解釋器採用 巨型 switch 分派 + 巨型 C 文件包含 架構,將 200+ 字節碼指令實現集中在 bytecodes.c,由 execute.c 的 SlowInterpret() 統一入口分派。本文解析指令實現框架、宏展開機制,並以 4 條典型指令為例展示棧操作、局部變量、類型轉換、算術運算的底層邏輯。
typedef enum {
NOP = 0x00, ACONST_NULL = 0x01, ICONST_M1 = 0x02,
// ... 200+ 指令
LASTBYTECODE = 0xDF
} ByteCode;
#define BYTE_CODE_NAMES { "NOP", "ACONST_NULL", "ICONST_M1", ..., "CUSTOMCODE" }
每條指令遵循統一宏模板:
SELECT(ICONST_0) // 展開為: case ICONST_0: {
pushStack(0); // 具體操作
DONE(1) // 展開為: } goto next1;
#define SELECT(l1) case l1: {
#define SELECT2(l1,l2) case l1: case l2: {
#define DONE(n) } goto next##n; // n = 指令長度(字節數)
#define DONE_R } goto reschedulePoint; // 線程讓權點
void SlowInterpret(ByteCode token) {
// ... 取指令、解碼參數 ...
switch (token) {
#include "bytecodes.c" // 直接包含展開所有 case
}
// 指令長度跳轉標簽
next3: ip += 3; // 3 字節指令 (如帶 2 字節參數)
next2: ip += 2;
next1: ip += 1; // 1 字節指令
next0: ;
reschedulePoint: return; // 讓出 CPU (Green Threads 調度點)
}
SELECT(ICONST_0) // Push int constant 0
*++GlobalState.gs_sp = 0; // sp 遞增後賦值
DONE(1)
gs_sp:當前幀操作數棧頂指針 (按字/word 寻址)next1
SELECT(DSTORE) // Store double into local variable
unsigned int index = ip[1]; // 參數在指令流第 2 字節
lp[index+1] = *gs_sp--; // 彈出低 32 位
lp[index] = *gs_sp--; // 彈出高 32 位
DONE(2) // 指令長 2 字節
lp:局部變量表基址
SELECT(I2L) // Convert int to long
long value = *(long*)sp; // 取棧頂 int (按長整型讀取)
#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); // 編譯器內置 long 支持
#endif
getSP()++; // 棧頂指針 +1 (佔用雙字)
DONE(1)
SELECT(LMUL) // Multiply long
long64 rvalue = GET_LONG(sp - 1); // 取操作數 2 (棧次頂)
long64 lvalue = GET_LONG(sp - 3); // 取操作數 1 (棧第 3 項)
SET_LONG(sp - 3, ll_mul(lvalue, rvalue)); // 結果寫回操作數 1 位置
getSP() -= 2; // 彈出 4 字壓入 2 字 → sp -2
DONE(1)
long64 平台相關 64 位類型,ll_mul 為平台相關乘法宏 (可能內聯彙編)sp| 類別 | 代表指令 | 複雜度 | 備註 |
|---|---|---|---|
| 常量/局部變量 | ICONST_, ILOAD, ISTORE | 低 | 純棧/局部變量指針運算 |
| 算術/邏輯 | IADD, ISUB, IMUL, IAND | 低 | 彈出運算壓入,定點數直接 CPU 指令 |
| 類型轉換 | I2L, I2D, L2I, D2F | 中 | 位模式重組、符號擴展、精度截斷 |
| 對象操作 | NEW, NEWARRAY, GETFIELD, INVOKEVIRTUAL | 高 | 堆分配、GC 協作、方法查找、參數搬移 |
| 控制流 | IFEQ, GOTO, TABLESWITCH | 中 | 修改 ip、查表跳轉 |
| 異常/同步 | ATHROW, MONITORENTER | 高 | 棧幀展開、鎖計數、線程狀態機 |