2015-03-14 5 views
0

Я хочу, чтобы компилировать блок Try/Catch с использованием структуры ASM из моего компилятора (это означает, что блок try, блоки обработчика и переменные являются динамическими). Это то, что мой код в настоящее время выглядит следующим образом:Java ASM Generate Catch Block

org.objectweb.asm.Label tryStart = new org.objectweb.asm.Label(); 
    org.objectweb.asm.Label tryEnd = new org.objectweb.asm.Label(); 
    org.objectweb.asm.Label endLabel = new org.objectweb.asm.Label(); 

    writer.writeLabel(tryStart); 
    if (this.action != null) 
    { 
     this.action.writeStatement(writer); 
     writer.writeJumpInsn(Opcodes.GOTO, endLabel); 
    } 
    writer.writeLabel(tryEnd); 

    for (int i = 0; i < this.catchBlockCount; i++) 
    { 
     CatchBlock block = this.catchBlocks[i]; 
     org.objectweb.asm.Label handlerLabel = new org.objectweb.asm.Label(); 
     int varIndex; 

     writer.push(block.type); 
     // Check if the block's variable is actually used 
     if (block.variable != null) 
     { 
      // If yes register a new local variable for the exception and 
      // store it. 
      varIndex = block.variable.index = writer.registerLocal(block.type); 
      writer.writeFrameLabel(handlerLabel); 
      writer.writeVarInsn(Opcodes.ASTORE, varIndex); 
      block.action.writeStatement(writer); 
      writer.removeLocals(1); 
     } 
     // Otherwise pop the exception from the stack 
     else 
     { 
      varIndex = -1; 
      writer.writeFrameLabel(handlerLabel); 
      writer.writeInsn(Opcodes.POP); 
      block.action.writeStatement(writer); 
     } 

     writer.writeTryCatchBlock(tryStart, tryEnd, handlerLabel, block.type); 
     writer.writeJumpInsn(Opcodes.GOTO, endLabel); 
    } 
    writer.writeFrameLabel(endLabel); 

Однако эта реализация порождает следующие VerifyError:.

java.lang.VerifyError: Stack map does not match the one at exception handler 20 
Exception Details: 
    Location: 
    dyvil/test/Main.main([Ljava/lang/String;)V @20: astore_1 
    Reason: 
    Type top (current frame, locals[1]) is not assignable to 'Ljava/lang/Exception;' (stack map, locals[1]) 
    Current Frame: 
    bci: @0 
    flags: { } 
    locals: { '[Ljava/lang/String;' } 
    stack: { 'java/lang/Exception' } 
    Stackmap Frame: 
    bci: @20 
    flags: { } 
    locals: { '[Ljava/lang/String;', 'Ljava/lang/Exception;' } 
    stack: { 'Ljava/lang/Exception;' } 
    Bytecode: 
    0000000: b200 1312 15b6 001b b200 1304 036c b600 
    0000010: 1ea7 0013 4cb2 0013 1224 b600 1b2b b600 
    0000020: 29a7 0003 b1       
    Exception Handler Table: 
    bci [0, 20] => handler: 20 
    Stackmap Table: 
    full_frame(@20,{Object[#32],Object[#34]},{Object[#34]}) 
    chop_frame(@36,1) 

(Обратите внимание, что методы writer начиная с writeX лишь делегаты MethodVisitor.visitXwriteFrameLabel также сообщает MethodWriter, что он должен генерировать стек стека перед записью следующей инструкции)

+0

Вы создали «ClassWriter» с параметром [ClassWriter.COMPUTE_FRAMES] (http://asm.ow2.org/asm50/javadoc/user/org/objectweb/asm/ClassWriter.html#COMPUTE_FRAMES) и версией класса 1,6+? – apangin

+0

Это именно то, чего я пытаюсь избежать, используя пользовательский метод MethodWriter по соображениям производительности. Версия класса установлена ​​в 1.8. – Clashsoft

ответ

0

Мне удалось найти lution самостоятельно, заменив эту часть:

varIndex = block.variable.index = writer.registerLocal(block.type); 
writer.writeFrameLabel(handlerLabel); 
writer.writeVarInsn(Opcodes.ASTORE, varIndex); 

С этим:

writer.writeLabel(handlerLabel); 
writer.writeFrame(); 
varIndex = block.variable.index = writer.registerLocal(block.type); 
writer.writeVarInsn(Opcodes.ASTORE, varIndex); 

В основном, стек карты кадров в ASTORE не предполагается включать в себя локальную переменную, но вместо того, чтобы локальная переменная должна после инициализации.