Sve*_*ven 8 java jvm bytecode bytecode-manipulation jvm-bytecode
我有两个示例类文件,一个来自示例Java应用程序,另一个来自示例C app(使用LLJVM编译为字节码).
看看他们的输出,我可以通过javap -c -p看到,为了初始化(静态)字段,Java应用程序显示以下块:
static {};
Code:
0: sipush 1339
3: putstatic #7 //Field SRV_ID
etc
Run Code Online (Sandbox Code Playgroud)
<clinit>如果我理解的话,基本上就是这个方法.或者由我正在使用的VM检测到.
然而,C-app有这个:
public {};
Code:
0: sipush 1339
3: putstatic #7 //Field SRV_ID
etc
Run Code Online (Sandbox Code Playgroud)
这是什么?我的VM没有检测到它.
示例类文件.第一个来自Java应用程序打印消息并等待20秒,重复.第二个是大致相同的C应用程序.
http://www.fast-files.com/getfile.aspx?file=156962
http://www.fast-files.com/getfile.aspx?file=156961
这样做的道歉 - 我不会立即知道如何附加文件或有效地显示.class文件.
这似乎是一个javap没有考虑的非标准声明.通常,static初始化程序被编译为名为<clinit>具有static修饰符的字节码方法.显然,javap只需打印修饰符的人类可读形式并省略<clinit>名称即可解码它们.
在这里,它遇到了一个名为<clinit>并具有public修饰符(无static修饰符)的方法,并且只是像往常一样,打印修饰符并省略<clinit>名称.
LLJVM生成的代码似乎依赖于一个古老的怪异:
在
class版本号为51.0或更高版本的文件中,该方法必须另外设置其ACC_STATIC标志(第4.6节),以便成为类或接口初始化方法.此要求是在Java SE 7中引入的.在版本号为50.0或更低版本的类文件中,名为
<clinit>void且不带参数的方法被认为是类或接口初始化方法,无论其ACC_STATIC标志的设置如何.
对我来说,真正令人惊讶的是,在以前的版本中,ACC_STATIC修饰符并未强制执行,我认为没有任何理由可以利用这种奇怪性.类初始化器(static {}在Java中声明)应该具有ACC_STATIC标志并且我甚至无法想象省略ACC_STATIC标志的假定语义似乎是很自然的.它意味着应该发生两个奇怪的事情之一,a)尽管没有ACC_STATIC标志(如果有的话被调用),或者b)使用必须已经"神奇地"创建的实例调用它,它在没有实例的情况下被调用. .
该规范指出下列任何非标准<clinit>方法:
命名其他方法
<clinit>在class文件中都没有结果.它们不是类或接口初始化方法.它们不能被任何Java虚拟机指令调用,并且永远不会被Java虚拟机本身调用.