2011-01-19 68 views
1

我需要在正常執行之前使用本機方法進行簡單的靜態調用。因爲這些方法是本地的,所以我必須使用"setNativePrefix" feature並用原始方法簽名將原生方法與中間調用一起包裝。爲什麼這個簡單的Java字節碼會導致StackOverflow錯誤?

了我認爲是一個簡單的字節碼的變化來完成這個後,我得到的權利之前,儘管堆棧基本上是空的包裝方法被執行的StackOverflowError。這是我的測試課程:

public class SimpleTest { 
    public static void main(String[] args) throws IOException { 
     Perf.getPerf().highResCounter(); 
    } 
} 

通常,該程序在控制檯上不會產生任何內容。但是,在執行本機方法$ wrapper $ highResCounter()之前,我的插入的字節碼會執行println()。這可以在相關的逆足類的字節碼可以看到儀表後:

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()被執行,但引發StackOverflowError第一 invokevirtual調用之後的地方:

this is an instrumented println call 
Exception in thread "main" java.lang.StackOverflowError 
    at com.foo.SimpleTest.main(SimpleTest.java:17) 

什麼導致這個的StackOverflowError?我該如何解決它?

+0

你對我們有完整的SimpleTest.java?你有沒有用調試器?也許你沒有運行你認爲你正在運行的東西。 (讓我想起了一個bug幾年前,我搜索小時,直到我意識到,我的類路徑指着舊的分類文件:) – 2011-01-19 17:09:34

+0

這是階級的整體,減去import語句和包裝標識。沒有靜態初始化器或任何東西。 – nahsra 2011-01-19 19:21:15

+0

它也發生在任何本地方法上:像StrictMath.sin()。我認爲這與Perf沒有任何關係。 – nahsra 2011-01-25 12:41:42

回答

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

1

你highResCounter方法自稱:

public long highResCounter() { 
    [...] 
    invokevirtual long Perf.$wrapped$highResCounter() 

你有更多的代碼,你可以告訴我們找出原因?

+0

它不是自己調用。它調用本地方法$ wrapped $ highResCounter。非本地版本僅供我在與本地版本交付責任之前撥打電話。 – nahsra 2011-01-19 03:21:03

0

顯示本機的功能,它也可以是其右側自己的問題。 iirc StackOverFlowError被困,所以即使是JNI C代碼也可能導致它。

相關問題