我需要检测本机方法,以便在正常执行之前进行简单的静态调用。因为这些方法是原生的,所以我必须使用"setNativePrefix" feature并使用原始方法签名对本机方法进行中间调用。
在我认为是一个简单的字节码更改来实现这一点之后,即使堆栈基本上是空的,我也会在执行包装器方法之前得到一个StackOverflowError。这是我的测试类:
public class SimpleTest {
public static void main(String[] args) throws IOException {
Perf.getPerf().highResCounter();
}
}
通常,该程序在控制台上不会产生任何结果。但是,我的检测字节码在执行本机方法$ wrapper $ highResCounter()之前执行println()。这可以在检测后的相关Perf类字节码中看到:
public long highResCounter() {
getstatic PrintStream System.out
ldc String Constant "this is an instrumented println"
invokevirtual void PrintStream.println(String)
aload 0
invokevirtual long Perf.$wrapped$highResCounter()
lreturn
}
public native long $wrapped$highResCounter();
我是Java字节码的新手,所以我在这里犯了一个错误。这是程序的输出,它显示println()被执行,但在第一个之后的某个地方 invokevirtual 调用抛出StackOverflowError:
this is an instrumented println call
Exception in thread "main" java.lang.StackOverflowError
at com.foo.SimpleTest.main(SimpleTest.java:17)
可能导致此StackOverflowError的原因是什么?我该如何解决?
答案 0 :(得分:1)
你的highResCounter方法正在调用自己:
public long highResCounter() {
[...]
invokevirtual long Perf.$wrapped$highResCounter()
您是否有更多代码可以向我们展示以找出原因?
答案 1 :(得分:1)
发布的代码中没有错误。问题是由MAX_STACK和MAX_LOCALS方法属性的无效值引起的,这些属性通常由编译器计算。
我正在使用的字节码库ASM让您有机会自动计算这些值,而我没有利用它。通过将ASM ClassWriter构造函数更改为以下内容,我得到无错误的代码:
int flags = ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS;
ClassWriter writer = new ClassWriter(flags);
[1] http://asm.ow2.org/asm33/javadoc/user/org/objectweb/asm/ClassWriter.html#COMPUTE_FRAMES
答案 2 :(得分:0)
显示本机功能,它本身也可能是一个问题。 iirc StackOverFlowError被捕获,因此即使是JNI C代码也可能导致它。