Xye*_*ene 11 java jvm bytecode opcode
我最近遇到了开发一个库,该库在JVM字节码上执行了一些操作码,在这些操作码上没有文档(我已经找到),但是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;
Run Code Online (Sandbox Code Playgroud)
它们似乎是其他实现的替代品,但具有不同的操作码.经过长时间的网页浏览后,我LDC*_QUICK在本文档中提到了操作码.
在LDC_QUICK操作码上引用它:
操作从常量池中推送项目
表格 ldc_quick = 203(0xcb)
堆栈 ......,项目
描述索引是一个无符号字节,必须是当前类的常量池的有效索引(第3.6节).索引处的常量池项必须已经解析,并且必须是一个字宽.该项从常量池中获取并推送到操作数堆栈.
注意该指令的操作码最初是ldc.不修改ldc指令的操作数.
好的.看似有趣,所以我决定尝试一下.LDC_QUICK似乎具有相同的格式LDC,所以我继续将LDC操作码更改为LDC_QUICK一个.这导致了失败,尽管JVM明显认识到了这一点.尝试运行修改后的文件后,JVM崩溃并输出以下内容:
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)
Run Code Online (Sandbox Code Playgroud)
上述错误提供了混合消息.显然,类文件验证失败:java.lang.VerifyError: Bad instruction: cc.同时,JVM识别出操作码:@9: fast_bgetfield.此外,它似乎认为它是一个不同的指令,因为fast_bgetfield并不意味着不断推动......
我认为公平地说我很困惑.这些非法操作码是什么?JVM运行它们吗?我为什么收到VerifyErrors?弃用?他们是否比他们记录的对手有优势?
任何见解将不胜感激.
jdb*_*jdb 13
Java虚拟机规范的第一版描述了Sun早期Java虚拟机实现之一使用的技术,以加速字节码的解释.在此方案中,当解析常量池条目时,引用常量池条目的操作码将被"_quick"操作码替换.当虚拟机遇到_quick指令时,它知道常量池条目已经解析,因此可以更快地执行指令.
Java虚拟机的核心指令集由200个单字节操作码组成.这200个操作码是您在类文件中看到的唯一操作码.使用"_quick"技术的虚拟机实现在内部使用另外25个单字节操作码,即"_quick"操作码.
例如,当使用_quick技术的虚拟机解析由ldc指令引用的常量池条目(操作码值0x12)时,它将使用ldc_quick指令(操作码值0xcb)替换字节码流中的ldc操作码字节.此技术是在Sun早期虚拟机中使用直接引用替换符号引用的过程的一部分.
对于某些指令,除了使用_quick操作码覆盖普通操作码之外,使用_quick技术的虚拟机会使用表示直接引用的数据覆盖指令的操作数.例如,除了用invokevirtual_quick替换invokevirtual操作码之外,虚拟机还将方法表偏移量和参数数量放入每个invokevirtual指令后面的两个操作数字节中.将方法表偏移量放在invokevirtual_quick操作码之后的字节码流中可以为虚拟机保存在已解析的常量池条目中查找偏移量所需的时间.
基本上你不能把操作码放在类文件中.只有JVM在解析操作数后才能这样做.
| 归档时间: |
|
| 查看次数: |
1699 次 |
| 最近记录: |