2012-06-30 3 views
4

저는 ASM 4를 사용하여 일부 클래스를 즉시 생성합니다. 예외 처리를위한 코드를 생성 할 때까지는 모든 것이 아주 잘 진행되었습니다. 생성 된 바이트 코드는 맨 아래에 있습니다. 여기메소드의 지역 변수 유형이 잘못되었습니다.

java.lang.VerifyError: Instruction type does not match stack map in method some.eval.ToEvaluate$0.apply()Ljava/lang/Object; at offset 44 
at java.lang.Class.getDeclaredConstructors0(Native Method) 
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2404) 
at java.lang.Class.getConstructor0(Class.java:2714) 
at java.lang.Class.newInstance0(Class.java:343) 
at java.lang.Class.newInstance(Class.java:325) 
    ... 

바이트 코드 것 :

// Compiled from com/pkg/some/Source.java (version 1.7 : 51.0, super bit) 
public class some.eval.ToEvaluate$0 extends com.pkg.lang.Lambda0 { 

    // Method descriptor #7()V 
    // Stack: 1, Locals: 1 
    public ToEvaluate$0(); 
    0 aload_0 [this] 
    1 invokespecial com.pkg.lang.Lambda0() [9] 
    4 return 
     Line numbers: 
     [pc: 0, line: 1] 
     [pc: 0, line: 2] 
     [pc: 4, line: 3] 
     Local variable table: 
     [pc: 0, pc: 5] local: this index: 0 type: new some.eval.ToEvaluate(){} 

    // Method descriptor #13()Ljava/lang/Object; 
    // Stack: 5, Locals: 3 
    public java.lang.Object apply(); 
    0 getstatic com.pkg.some.Primitives.equal : com.pkg.lang.Lambda [19] 
    3 checkcast com.pkg.lang.Lambda2 [21] 
    6 getstatic com.pkg.some.Primitives.divide : com.pkg.lang.Lambda [26] 
    9 checkcast com.pkg.lang.Lambda2 [21] 
    12 ldc2_w <Long 1> [27] 
    15 invokestatic java.lang.Long.valueOf(long) : java.lang.Long [34] 
    18 ldc2_w <Long 0> [35] 
    21 invokestatic java.lang.Long.valueOf(long) : java.lang.Long [34] 
    24 invokevirtual com.pkg.lang.Lambda2.apply(java.lang.Object, java.lang.Object) : java.lang.Object [39] 
    27 astore_1 [v1] 
    28 goto 44 
    31 astore_2 [e] 
    32 new some.lambda.ToRun$1 [41] 
    35 dup 
    36 invokespecial some.lambda.ToRun$1() [42] 
    39 aload_2 [e] 
    40 invokevirtual com.pkg.lang.Lambda1.apply(java.lang.Object) : java.lang.Object [47] 
    43 astore_1 
    44 ldc2_w <Long -1> [48] 
    47 invokestatic java.lang.Long.valueOf(long) : java.lang.Long [34] 
    50 invokevirtual com.pkg.lang.Lambda2.apply(java.lang.Object, java.lang.Object) : java.lang.Object [39] 
    53 areturn 
     Exception Table: 
     [pc: 6, pc: 28] -> 31 when : java.lang.Throwable 
     Line numbers: 
     [pc: 6, line: 50] 
     [pc: 12, line: 21] 
     [pc: 18, line: 21] 
     [pc: 31, line: 51] 
     [pc: 32, line: 52] 
     [pc: 44, line: 54] 
     [pc: 44, line: 21] 
     Local variable table: 
     [pc: 0, pc: 54] local: this index: 0 type: new some.eval.ToEvaluate(){} 
     [pc: 28, pc: 31] local: v1 index: 1 type: java.lang.Object 
     [pc: 32, pc: 44] local: e index: 2 type: java.lang.Throwable 
     [pc: 44, pc: 44] local: v2 index: 1 type: java.lang.Object 
     Stack map table: number of frames 2 
     [pc: 31, same_locals_1_stack_item, stack: {java.lang.Throwable}] 
     [pc: 44, full, stack: {com.pkg.lang.Lambda2}, locals: {some.eval.ToEvaluate$0, java.lang.Object}] 
} 
나는이에 시작하는 ASMifier을 사용

: 다음

public static Object trycatch(Object test, Lambda1 handler) { 
    Object v; 
    try { 
     v = test; 
    } catch (Throwable e) { 
     v = handler.apply(e); 
    } 
    return v; 
} 

하지만 난 그것을 수정했다 여기에 내가지고있어 오류입니다 그것을 일반적으로 만든다.

int varOffset = context.getVarOffset(); 

    Label l0 = new Label(); 
    Label l1 = new Label(); 
    Label l2 = new Label(); 
    Label l3 = new Label(); 
    Label l4 = new Label(); 
    Label l5 = new Label(); 

    // mv.visitLocalVariable("v", "Ljava/lang/Object;", null, l1, l2, 2); // 2 == varOffset + 0 
    context.push(1, new VarInfo(varOffset, "v1", l1, l2, false, "java/lang/Object")); 
    // mv.visitLocalVariable("v", "Ljava/lang/Object;", null, l3, l5, 2); // 2 == varOffset + 0 
    context.push(1, new VarInfo(varOffset, "v2", l3, l5, false, "java/lang/Object")); 
    // mv.visitLocalVariable("e", "Ljava/lang/Throwable;", null, l4, l3, 3); // 3 == varOffset+1 
    context.push(1, new VarInfo(varOffset + 1, "e", l4, l3, false, "java/lang/Throwable")); 

    mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); 
    mv.visitLabel(l0); 
    mv.visitLineNumber(50, l0); 

    args[0].visit(context, mv); // mv.visitVarInsn(ALOAD, 0); // execute block 
    mv.visitVarInsn(ASTORE, varOffset); // store v, the result 

    mv.visitLabel(l1); 
    mv.visitJumpInsn(GOTO, l3); 
    mv.visitLabel(l2); 
    mv.visitLineNumber(51, l2); 
    // mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" }); 
    mv.visitVarInsn(ASTORE, varOffset + 1); // e 
    mv.visitLabel(l4); 
    mv.visitLineNumber(52, l4); 

    args[1].visit(context, mv); // mv.visitVarInsn(ALOAD, 1); // catch block 
    mv.visitVarInsn(ALOAD, varOffset + 1); // e 

    mv.visitMethodInsn(INVOKEVIRTUAL, "com/pkg/lang/Lambda1", "apply", "(Ljava/lang/Object;)Ljava/lang/Object;"); 
    mv.visitVarInsn(ASTORE, varOffset); // store v, the result 

    mv.visitLabel(l3); 
    mv.visitLineNumber(54, l3); 
    // mv.visitFrame(F_APPEND, 1, new Object[] { "java/lang/Object" }, 0, null); 
    mv.visitVarInsn(ALOAD, varOffset); // load v, the result 
    // mv.visitInsn(ARETURN); 
    mv.visitLabel(l5); 
    // mv.visitLocalVariable("test", "Ljava/lang/Object;", null, l0, l5, 0); 
    // mv.visitLocalVariable("handler", "Lcom/pkg/lang/Lambda1;", null, l0, l5, 1); 

답변

3

나는 ASM 목록에 물어 누군가가 친절이 팁을 제공 : ". 자세한 내용을 위해 checkDataFlow 옵션으로 CheckClassAdapter을 사용해보십시오"

일부 문제 해결 방법으로 문제를 해결했습니다. 바운드 변수의 범위를 적절히 구별하지 못하고 visitLocalVariable을 사용하여 로컬 변수를 선언해야하는 것과 관련 있다고 확신합니다. 적어도 그것이 작동하지 않을 때와 작동 할 때 사이에 고정 된 것 중 하나입니다.

4

나는 당신이 말하는한다는 가정에 따라 질문에 대답 해요 : 다음은 시도/캐치 부분을 생성 년대 코드는

// mv.visitLocalVariable("v", "Ljava/lang/Object;", null, l1, l2, 2); // 2 == varOffset + 0 
context.push(1, new VarInfo(varOffset, "v1", l1, l2, false, "java/lang/Object")); 

당신이 context.pushmv.visitLocalVariable을 생성 것을 의미한다.

로컬 변수를 방문하기 전에 l1l2 라벨을 먼저 방문해야한다고 생각합니다.

는 인수로 전달 전에 레이블을 방문한 호출해야합니다 method visitor

visitTryCatchBlock의 ASM4 자바 문서를 참조하고, visitLocalVariable 및 visitLineNumber 방법은 후 인수로 전달 된 라벨을 를 호출해야합니다 방문했습니다.

위와 같지 않으면 스택 맵이 잘못 생성 될 수 있습니다. 따라서 mv.visitLabel(l5) 이후에 context.push을 맨 아래로 이동하면 올바른 스택 맵으로 코드가 생성되어야합니다.

+0

메서드의 끝에서 visitMaxs를 호출하기 직전까지는 visitLocalVariable을 호출하지 않는다는 가정을 전제로합니다. 그래서 저는 여러분이 묘사 한 것의 나머지 부분을 만족시키고 있다고 생각합니다. 미안해. 내 질문에 분명하지 않았어. – mentics