Recentemente mi sono imbattuto nello sviluppo di una libreria che esegue operazioni su bytecode JVM su alcuni opcode su cui non esiste documentazione (che ho trovato), ma che sono riconosciuti dall'implementazione di riferimento JVM. Ho trovato un elenco di questi, e sono:Codici opzionali non validi nella JVM
BREAKPOINT = 202;
LDC_QUICK = 203;
LDC_W_QUICK = 204;
LDC2_W_QUICK = 205;
GETFIELD_QUICK = 206;
PUTFIELD_QUICK = 207;
GETFIELD2_QUICK = 208;
PUTFIELD2_QUICK = 209;
GETSTATIC_QUICK = 210;
PUTSTATIC_QUICK = 211;
GETSTATIC2_QUICK = 212;
PUTSTATIC2_QUICK = 213;
INVOKEVIRTUAL_QUICK = 214;
INVOKENONVIRTUAL_QUICK = 215;
INVOKESUPER_QUICK = 216;
INVOKESTATIC_QUICK = 217;
INVOKEINTERFACE_QUICK = 218;
INVOKEVIRTUALOBJECT_QUICK = 219;
NEW_QUICK = 221;
ANEWARRAY_QUICK = 222;
MULTIANEWARRAY_QUICK = 223;
CHECKCAST_QUICK = 224;
INSTANCEOF_QUICK = 225;
INVOKEVIRTUAL_QUICK_W = 226;
GETFIELD_QUICK_W = 227;
PUTFIELD_QUICK_W = 228;
IMPDEP1 = 254;
IMPDEP2 = 255;
Essi sembrano essere rimontaggi per le loro altre implementazioni, ma hanno diversi codici operativi. Dopo un lungo periodo di navigazione pagina dopo pagina attraverso Google, ho trovato una menzione degli opcode LDC*_QUICK
in this document.
Citazione da esso sul LDC_QUICK
codice operativo:
operazione Voce spinta dal pool di costanti
Forme ldc_quick = 203 (0xcb)
Stack ... ..., articolo
Descrizione L'indice è un byte senza segno che deve essere un indice valido nel pool costante della classe corrente (§3.6). La costante articolo di pool all'indice deve essere già stata risolta e deve essere una sola parola . L'elemento viene recuperato dal pool costante e spostato su stack di operandi.
Note L'opcode di questa istruzione era originariamente ldc. L'operando dell'istruzione ldc non viene modificato.
OK. Sembrava interessante, quindi ho deciso di provarlo. LDC_QUICK
sembra avere lo stesso formato di LDC
, quindi ho proceduto a modificare un codice operativo LDC
in uno LDC_QUICK
. Ciò ha comportato un fallimento, anche se la JVM ovviamente lo ha riconosciuto. Dopo aver tentato di eseguire il file modificato, la JVM si è arrestata in modo anomalo con il seguente output:
Exception in thread "main" java.lang.VerifyError: Bad instruction: cc
Exception Details:
Location:
Test.main([Ljava/lang/String;)V @9: fast_bgetfield
Reason:
Error exists in the bytecode
Bytecode:
0000000: bb00 0559 b700 064c 2bcc 07b6 0008 572b
0000010: b200 09b6 000a 5710 0ab8 000b 08b8 000c
0000020: 8860 aa00 0000 0032 0000 0001 0000 0003
0000030: 0000 001a 0000 0022 0000 002a b200 0d12
0000040: 0eb6 000f b200 0d12 10b6 000f b200 0d12
0000050: 11b6 000f bb00 1259 2bb6 0013 b700 14b8
0000060: 0015 a700 104d 2cb6 0016 b200 0d12 17b6
0000070: 000f b1
Exception Handler Table:
bci [84, 98] => handler: 101
Stackmap Table:
append_frame(@60,Object[#41])
same_frame(@68)
same_frame(@76)
same_frame(@84)
same_locals_1_stack_item_frame(@101,Object[#42])
same_frame(@114)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
at java.lang.Class.getMethod0(Unknown Source)
at java.lang.Class.getMethod(Unknown Source)
at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
L'errore sopra riportato genera messaggi misti. Ovviamente, la verifica del file di classe non è riuscita: java.lang.VerifyError: Bad instruction: cc
. Allo stesso tempo, la JVM ha riconosciuto l'opcode: @9: fast_bgetfield
. Inoltre, sembra pensare che sia un'istruzione diversa, perché fast_bgetfield
non implica una costante spinta ...
Penso che sia giusto dire che sono abbastanza confuso. Quali sono questi codici opzionali illegali? Le JVM le gestiscono? Perché sto ricevendo VerifyError
s? Deprecation? E hanno un vantaggio rispetto alle loro controparti documentate?
Qualsiasi intuizione sarebbe molto apprezzata.