私は既に存在するクラスのASMを使用して簡単なゲッターメソッドを生成しました。BadローカルStackMapTable
mv = cn.visitMethod(access, // public method
"get_" + f.name, // name
"()Ljava/lang/String;", // descriptor
null, // signature (null means not generic)
null); // exceptions (array of strings
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitFieldInsn(Opcodes.GETFIELD, cn.name, f.name, f.desc);
mv.visitInsn(Opcodes.ARETURN);
mv.visitMaxs(0, 0);
次に、クラスを生成しました。
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(cw);
ここで、私はcw.toByteArray()でクラスにアクセスできます。 問題は、私は、負荷にStackMapTableが適切ではないので、私はエラーを取得するクラスをしようとすると、(それは私がClassWriter.COMPUTE_FRAMESを使用している、あるべき?)である
エラー
Exception in thread "main" java.lang.VerifyError: Bad local variable type
Exception Details:
Location:
a.get_c()Ljava/lang/String; @0: aload_0
Reason:
Type top (current frame, locals[0]) is not assignable to reference type
Current Frame:
bci: @0
flags: { }
locals: { }
stack: { }
Bytecode:
0x0000000: 2ab4 0012 b0
後これはCheckClassAdapterを追加して、何が間違っているかを確認します。
CheckClassAdapter ca = new CheckClassAdapter(cw, false); //Check data flow
ClassReader cr = new ClassReader(cw.toByteArray());
ca.verify(cr, new GenericClassLoader(), true, new PrintWriter(new PrintStream(System.out)));
出力は次のとおりです。
org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 0: Expected an object reference, but found .
at org.objectweb.asm.tree.analysis.Analyzer.analyze(Unknown Source)
at org.objectweb.asm.util.CheckClassAdapter.verify(Unknown Source)
at me.ffy00.ClassGenerator2.generateSkeleton(ClassGenerator2.java:85)
at me.ffy00.Test.main(Test.java:25)
Caused by: org.objectweb.asm.tree.analysis.AnalyzerException: Expected an object reference, but found .
at org.objectweb.asm.tree.analysis.BasicVerifier.copyOperation(Unknown Source)
at org.objectweb.asm.tree.analysis.BasicVerifier.copyOperation(Unknown Source)
at org.objectweb.asm.tree.analysis.Frame.execute(Unknown Source)
... 4 more
get_c()Ljava/lang/String;
00000 . : : ALOAD 0
00001 ? : GETFIELD a.c : Ljava/lang/String;
00002 ? : ARETURN
私のメソッドget_c()を見ればわかりますか?いくつかのオペコード(多分最初のオペコードが理解されていないため?)
00000 . : : ALOAD 0
00001 ? : GETFIELD a.c : Ljava/lang/String;
00002 ? : ARETURN
に私は本当に今、それが何を意味するかんが、それははずのように方法は見えません。私は簡単なゲッタークラスをコンパイルし、このメソッドはこのように見えます。
00000 Getter : : ALOAD 0
00001 Getter : Getter : GETFIELD me/ffy00/Getter.a : Ljava/lang/String;
00002 Getter : String : ARETURN
私はすでにStackMapTableはまだ実装されていなかったので、50にクラスのバージョンを設定しようとしましたが、何も変更する表示されません。私はClassNodeのバージョン変数を50に設定しました。 このようにしてください。
cn.version = 50;
そして、このクラスはjavapで次のようになります。
public class a
minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_SUPER
はまた、スタックサイズとローカル番号を含め、私は私の方法を得ることができてjavap使用が、方法はStackMapTableを持っていない(はい、私は-v使用している、StackMapTableは、他の方法で表示されます)。
static java.lang.String get_c();
descriptor:()Ljava/lang/String;
flags: ACC_STATIC
Code:
stack=1, locals=1, args_size=0
0: aload_0
1: getfield #18 // Field c:Ljava/lang/String;
4: areturn
私の変数は次のようになります。
private static final java.lang.String c;
descriptor: Ljava/lang/String;
flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL
いくつかは、方法を修正するために必要なことを指摘できますか。 StackMapTableをASMで修正する方法に関する有益な情報が見つかりませんでした。
あなたのコメントは、 'access'は' public method'ですが、 'javap'はあなたのメソッドがdefault-visibility(別名パッケージ)_and static_だと考えています。非静的メソッドだけがarg0に 'this'を取得します。 –
はい、ありがとうございます。私はそれを完全に忘れてしまった。メソッド本体は、静的ゲッターでは異なる必要があります。 – FFY00