1

通常どおり実行する前に、単純な静的呼び出しを行うネイティブ メソッドをインストルメント化する必要があります。メソッドはネイティブであるため、「setNativePrefix」機能を使用して、元のメソッド シグネチャを使用した中間呼び出しでネイティブ メソッドをラップする必要があります。

これを達成するための単純なバイトコードの変更だと思った後、スタックが基本的に空であっても、ラッパーメソッドが実行される直前に 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 の原因は何ですか? どうすれば修正できますか?

4

3 に答える 3

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

于 2011-01-27T03:23:59.377 に答える
1

あなたの highResCounter メソッドは自分自身を呼び出しています:

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

理由を調べるために表示できるコードが他にありませんか?

于 2011-01-19T02:39:13.723 に答える
0

ネイティブ関数を表示すると、それ自体が問題になる可能性もあります。iirc StackOverFlowError はトラップされるため、JNI C コードでも発生する可能性があります。

于 2011-01-23T14:25:36.043 に答える