如果您嘗試指令操作碼映射到指令大小,你會得到以下沮喪表:
0 - 15 1 bytes
16 2 bytes
17 3 bytes
18 2 bytes
19 - 20 3 bytes
21 - 25 2 bytes
26 - 53 1 bytes
54 - 58 2 bytes
59 - 131 1 bytes
132 3 bytes
133 - 152 1 bytes
153 - 168 3 bytes
169 2 bytes
170 - 171 special handling
172 - 177 1 bytes
178 - 184 3 bytes
185 - 186 5 bytes
187 3 bytes
188 2 bytes
189 3 bytes
190 - 191 1 bytes
192 - 193 3 bytes
194 - 195 1 bytes
196 special handling
197 4 bytes
198 - 199 3 bytes
200 - 201 5 bytes
換句話說,沒有在指令的數值,也沒有它的位編碼沒有尺寸信息模式,但還有另一個屬性,你可以考慮某種模式:在大約200條定義的指令中,大約150條指令的大小爲一個字節,只剩下約50條指令,這些指令需要任何處理。即使這一小組指令可以進一步細分爲邏輯組,大多數取三個字節,第二大組取兩個字節。
因此通過指令衝的方法的代碼可能看起來像:
static void readByteCode(ByteBuffer bb) {
while(bb.hasRemaining()) {
switch(bb.get()&0xff) {
case BIPUSH: // one byte embedded constant
case LDC: // one byte embedded constant pool index
// follow-up: one byte embedded local variable index
case ILOAD: case LLOAD: case FLOAD: case DLOAD: case ALOAD:
case ISTORE: case LSTORE: case FSTORE: case DSTORE: case ASTORE: case RET:
case NEWARRAY: // one byte embedded array type
bb.get();
break;
case IINC: // one byte local variable index, another one for the constant
case SIPUSH: // two bytes embedded constant
case LDC_W: case LDC2_W: // two bytes embedded constant pool index
// follow-up: two bytes embedded branch offset
case IFEQ: case IFNE: case IFLT: case IFGE: case IFGT: case IFLE:
case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT: case IF_ICMPGE:
case IF_ICMPGT: case IF_ICMPLE: case IF_ACMPEQ: case IF_ACMPNE:
case GOTO: case JSR: case IFNULL: case IFNONNULL:
// follow-up: two bytes embedded constant pool index to member or type
case GETSTATIC: case PUTSTATIC: case GETFIELD: case PUTFIELD:
case INVOKEVIRTUAL: case INVOKESPECIAL: case INVOKESTATIC: case NEW:
case ANEWARRAY: case CHECKCAST: case INSTANCEOF:
bb.getShort();
break;
case MULTIANEWARRAY:// two bytes pool index, one byte dimension
bb.getShort();
bb.get();
break;
// follow-up: two bytes embedded constant pool index to member, two reserved
case INVOKEINTERFACE: case INVOKEDYNAMIC:
bb.getShort();
bb.getShort();
break;
case GOTO_W: case JSR_W:// four bytes embedded branch offset
bb.getInt();
break;
case LOOKUPSWITCH:
// special handling left as an exercise for the reader...
break;
case TABLESWITCH:
// special handling left as an exercise for the reader...
break;
case WIDE:
int widened=bb.get()&0xff;
bb.getShort(); // local variable index
if(widened==IINC) {
bb.getShort(); // constant offset value
}
break;
default: // one of the ~150 instructions taking one byte
}
}
}
我有意保持一些指令分離具有相同數目的後續字節,但具有不同的含義。畢竟,你想在某些地方插入一些實際的邏輯,我猜。
請注意,兩個switch
字節碼指令的處理被省略了,它們需要填充,其實現需要關於緩衝區內代碼對齊的知識,這是控制調用者的。所以這取決於您的具體應用。請參閱lookupswitch
和tableswitch
的文檔。
當然,處理的所有單字節指令爲default
意味着代碼不會趕上未知或無效的指令。如果你想安全,你要插入的情況下...
即使沒有模式(也有一些varadic操作碼)你想要寫一個靜態分析工具,不希望,最壞的情況下,使<< 256個操作碼的映射表。祝你好運。 – msw