我一直在调查这个错误整整三天,但仍然没有进展.我希望我能从这里得到一些提示.
我想要做的是使用ASM库将MethodNode内联到MethodHandle调用站点(#5,#17和#30).为简化起见,#5处的MethodHandle引用静态方法static Functions.isFooString(String)boolen
.
在呼叫站点,内联之前的指令就像
//Before
stack=3, locals=3, args_size=3
0: aload_0
1: getfield #15 // Field guard:Ljava/lang/invoke/MethodHandle;
4: aload_1
5: invokevirtual #29 // Method java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;)Z
8: ifeq 24
11: aload_0
12: getfield #17 // Field trueTarget:Ljava/lang/invoke/MethodHandle;
15: aload_1
16: aload_2
17: invokevirtual #31 // Method java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
20: checkcast #33 // class java/lang/String
23: areturn
24: aload_0
25: getfield #19 // Field falseTarget:Ljava/lang/invoke/MethodHandle;
28: aload_1
29: aload_2
30: invokevirtual #31 // Method java/lang/invoke/MethodHandle.invokeExact:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
33: checkcast #33 // class java/lang/String
36: …
Run Code Online (Sandbox Code Playgroud) 我最近一直在研究Java虚拟机规范(JVMS),试图更好地理解我的程序是如何工作的,但我找到了一个我不太了解的部分......
第4.7.4节描述了StackMapTable属性,在该部分中,文档详细介绍了堆栈映射帧.问题在于它有点罗嗦,我通过榜样学得最好; 不是通过阅读.
我知道第一个堆栈映射帧是从方法描述符派生的,但我不明白如何(这应该在这里解释.)另外,我不完全理解堆栈映射帧的作用.我认为它们与Java中的块类似,但看起来好像你不能在彼此内部堆栈映射帧.
无论如何,我有两个具体问题:
还有一个普遍的问题:
Java静态编译器(javac)内联一些静态最终变量,并将值直接带到常量池.请考虑以下示例.A类定义了一些常量(公共静态最终变量):
public class A {
public static final int INT_VALUE = 1000;
public static final String STRING_VALUE = "foo";
}
Run Code Online (Sandbox Code Playgroud)
B类使用以下常量:
public class B {
public static void main(String[] args) {
int i = A.INT_VALUE;
System.out.println(i);
String s = A.STRING_VALUE;
System.out.println(s);
}
}
Run Code Online (Sandbox Code Playgroud)
编译类B时,javac从类A获取这些常量的值,并在B.class中内联这些值.结果,编译时必须从A类中删除的依赖关系B从字节码中删除.这是一种相当奇特的行为,因为您在编译时正在烘焙这些常量的值.你会认为这是JIT编译器在运行时可以做的最容易的事情之一.
是否有任何方法或任何隐藏的编译器选项可以禁用javac的这种内联行为?对于后台,我们正在考虑进行字节码分析以实现依赖性目的,并且它是字节码分析无法检测编译时依赖性的少数情况之一.谢谢!
编辑:这是一个棘手的问题,因为通常我们不控制所有源(例如,定义常量的第三方库).我们有兴趣从使用常量的角度检测这些依赖关系.由于引用是从使用常量的代码中删除的,因此没有简单的方法来检测它们,缺少源代码分析.
根据我的阅读,有一个llvm程序将java字节码转换为llvm的中间形式,称为class2llvm.我的问题是,我该如何访问它.我必须安装什么前端才能访问它.
VMkit是他们的JVM实现,但我正在寻找如何使用llvm编译java源代码,而不是如何运行它.
Java版本之间是否存在不兼容性,其中针对Java版本X的Java源代码/ Java类文件将无法在版本Y(其中Y> X)下编译/运行?
"Java发布"我指的是以下版本:
家庭规则:
Python有一个标志-O
,你可以用它来执行解释器.该选项将生成"优化"字节码(写入.pyo文件),并给出两次,它将丢弃文档字符串.从Python的手册页:
-O启用基本优化.这会将已编译(字节码)文件的文件扩展名从.pyc更改为.pyo.给定两次,导致文档字符串被丢弃.
我认为这个选项的两个主要特点是:
删除所有断言语句.为了速度,这可以防止腐败的程序状态.但是,你不需要大量的断言声明才能有所作为吗?你有任何值得的代码(并且理智吗?)
剥离所有文档字符串.什么应用程序的内存使用如此关键,这是一个胜利?为什么不将所有内容都推入用C编写的模块?
这个选项有什么用?它有真实世界的价值吗?
我想用Java字节码编写一个简短的程序(也许是一个Hello World).我只想用文本编辑器编写字节码并运行它.我该怎么做?有一个例子吗?谢谢!
有三个操作码可以调用Java方法.很明显,invokeStatic仅用于静态方法调用.
据我所知,在调用构造函数和私有方法时使用了invokespecial.那么,我们是否需要在运行时区分私有和公共方法调用?可以使用相同的操作码调用invokevirtual来调用它吗?
JVM是否处理私有和公共方法定义?据我所知,在封装的开发阶段只需要公共和私有关键字?
我已经玩了一段时间Scala了,我知道traits可以作为Scala等同于接口和抽象类.如何将特征编译成Java字节码?
我发现了一些简短的解释,说明特征在可能的情况下编译完全类似于Java接口,否则与其他类接口.但是,我仍然不明白Scala如何实现类线性化,这是Java中没有的功能.
是否有一个很好的来源解释traits如何编译为Java字节码?
在下面的代码中,为什么Python不能编译f2
为相同的字节码f1
?
有理由不去吗?
>>> def f1(x):
x*100
>>> dis.dis(f1)
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (100)
6 BINARY_MULTIPLY
7 POP_TOP
8 LOAD_CONST 0 (None)
11 RETURN_VALUE
>>> def f2(x):
x*10*10
>>> dis.dis(f2)
2 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (10)
6 BINARY_MULTIPLY
7 LOAD_CONST 1 (10)
10 BINARY_MULTIPLY
11 POP_TOP
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud) bytecode ×10
java ×7
jvm ×4
python ×2
assert ×1
dependencies ×1
javac ×1
llvm ×1
optimization ×1
scala ×1
stack-frame ×1