Mercurial > hg > icedrobot > daneel
changeset 77:a5ab6534a6a6
Add try/catch and move_exception support.
Refactor in Rewriter fixStackAfterMethodCall to fixStackAfterMethodCallOrAnExceptionHandler.
author | forax |
---|---|
date | Fri, 25 Mar 2011 09:20:08 +0100 |
parents | f25015b8ff8b |
children | 6ea46c928791 |
files | src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java |
diffstat | 1 files changed, 59 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Thu Mar 24 19:05:37 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Fri Mar 25 09:20:08 2011 +0100 @@ -42,8 +42,11 @@ import static org.icedrobot.daneel.rewriter.Register.*; import static org.icedrobot.daneel.rewriter.Registers.*; +import java.util.Collections; import java.util.HashMap; +import java.util.IdentityHashMap; import java.util.Map; +import java.util.Set; import org.icedrobot.daneel.dex.DexAnnotationVisitor; import org.icedrobot.daneel.dex.DexClassVisitor; @@ -155,14 +158,18 @@ final String desc; private Interpreter interpreter; - private int returnRegisterType; // type of the register used to stored - // the return value - private int locals; // number of local variables - private int parameters; // number of parameters + private int returnRegisterType; // type of the register used to stored + // the return value + private boolean exceptionOnTop; // true if an exception is on top of the stack + private int locals; // number of local variables + private int parameters; // number of parameters // map DEX jump label to ASM label private final HashMap<Label, org.objectweb.asm.Label> labelMap = new HashMap<Label, org.objectweb.asm.Label>(); + // set which contains all labels which is the start of an exception handler + private final Set<Label> exceptionHandlerSet = + Collections.newSetFromMap(new IdentityHashMap<Label, Boolean>()); public MethodRewriter(MethodVisitor mv, String desc) { this.mv = new PatchMethodVisitor(mv); @@ -259,16 +266,20 @@ } /** This method must be called before each instruction unless the instruction - * is a MOVE_RESULT*. - * It checks if the last instruction was an invoke and corrects the stack - * if the current instruction is not a MOVE_RESULT*. + * is a MOVE_RESULT* or a MOVE_EXCEPTION. + * It checks if the last instruction was an invoke or the start of an exception handler + * and corrects the stack. */ - private void fixStackAfterAMethodCall() { + private void fixStackAfterAMethodCallOrAnExceptionHandler() { int returnRegisterType = this.returnRegisterType; if (returnRegisterType != VOID_TYPE) { mv.visitInsn((returnRegisterType == LONG_TYPE || returnRegisterType == DOUBLE_TYPE)? POP2: POP); this.returnRegisterType = VOID_TYPE; } + if (exceptionOnTop) { + mv.visitInsn(POP); + exceptionOnTop = false; + } } private void visitNotInstr(int type) { @@ -320,7 +331,7 @@ @Override public void visitInstr(Opcode opcode) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); if (opcode == Opcode.RETURN_VOID) { mv.visitInsn(RETURN); interpreter.setDead(); @@ -336,7 +347,7 @@ @Override public void visitInstrField(Opcode opcode, int vsrcOrDest, int vref, String owner, String name, String desc) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vsrcOrDest = registerToSlot(vsrcOrDest); vref = registerToSlot(vref); owner = TypeUtil.convertDescToInternal(owner); @@ -375,7 +386,7 @@ @Override public void visitInstrConstString(Opcode opcode, int vdest, String value) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vdest = registerToSlot(vdest); mv.visitLdcInsn(value); mv.visitVarInsn(ASTORE, vdest); @@ -384,7 +395,7 @@ @Override public void visitInstrClass(Opcode opcode, int vsrcOrDest, String typeDesc) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vsrcOrDest = registerToSlot(vsrcOrDest); switch(opcode) { case CONST_CLASS: @@ -414,7 +425,7 @@ @Override public void visitInstrMethod(Opcode opcode, int num, int va, int vpacked, String owner, String name, String desc) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); Opcode erasedRangeOpcode; int[] registers; if (opcode.compareTo(Opcode.INVOKE_VIRTUAL_RANGE) >= 0) { // *_range @@ -485,7 +496,7 @@ @Override public void visitInstrConstU32(Opcode opcode, int vdest, final int value) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); final int sdest = registerToSlot(vdest); mv.setPatchMode(); mv.visitLdcInsn(value); @@ -513,7 +524,7 @@ @Override public void visitInstrConstU64(Opcode opcode, int vdest, final long value) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); final int sdest = registerToSlot(vdest); mv.setPatchMode(); mv.visitLdcInsn(value); @@ -540,7 +551,7 @@ case RETURN: case RETURN_WIDE: case RETURN_OBJECT: { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); int type = getReturnTypeFromMethodDescriptor(desc); mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), srcOrDst); interpreter.load(srcOrDst, type); @@ -555,13 +566,19 @@ mv.visitVarInsn( Register.getJavaOpcode(returnRegisterType, ISTORE), srcOrDst); + interpreter.store(srcOrDst, returnRegisterType); returnRegisterType = VOID_TYPE; } break; } - case MOVE_EXCEPTION: - throw new UnsupportedOperationException("NYI " + opcode); + case MOVE_EXCEPTION: { + mv.visitVarInsn(ASTORE, srcOrDst); + interpreter.store(srcOrDst, OBJECT_TYPE); + exceptionOnTop = false; + break; + } default: //MONITOR_ENTER, MONITOR_EXIT, THROW. + fixStackAfterAMethodCallOrAnExceptionHandler(); mv.visitVarInsn(ALOAD, srcOrDst); interpreter.load(srcOrDst, OBJECT_TYPE); mv.visitInsn(toJavaOpcode[opcode.ordinal()]); @@ -570,7 +587,7 @@ @Override public void visitInstrUnaryOp(Opcode opcode, int dest, int src) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); final int vdest = registerToSlot(dest); final int vsrc = registerToSlot(src); int srcType = INT_TYPE, dstType; @@ -666,7 +683,7 @@ @Override public void visitInstrBinOp(Opcode opcode, int vdest, int vsrc1, int vsrc2) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vdest = registerToSlot(vdest); vsrc1 = registerToSlot(vsrc1); vsrc2 = registerToSlot(vsrc2); @@ -721,7 +738,7 @@ @Override public void visitInstrBinOpAndLiteral(Opcode opcode, int vdest, int vsrc, int value) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vdest = registerToSlot(vdest); vsrc = registerToSlot(vsrc); boolean rsub = opcode == Opcode.RSUB_INT_LIT16 @@ -741,6 +758,9 @@ @Override public void visitLabel(Label label) { + fixStackAfterAMethodCallOrAnExceptionHandler(); + exceptionOnTop = exceptionHandlerSet.contains(label); + Register[] registers = interpreter.getJoinPoint(label); if (registers != null) { // target of an already seen jump interpreter.merge(registers); @@ -752,7 +772,7 @@ @Override public void visitInstrGoto(Opcode opcode, Label label) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); Register[] registers = interpreter.getJoinPoint(label); if (registers != null) { // backward goto interpreter.merge(registers); @@ -766,7 +786,7 @@ @Override public void visitInstrIfTestZ(Opcode opcode, int vsrc, Label label) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vsrc = registerToSlot(vsrc); mv.visitVarInsn(ILOAD, vsrc); interpreter.load(vsrc, INT_TYPE); @@ -785,7 +805,7 @@ @Override public void visitInstrNewArray(Opcode opcode, int vdest, int vsize, String typeDesc) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vdest = registerToSlot(vdest); vsize = registerToSlot(vsize); mv.visitVarInsn(ILOAD, vsize); @@ -798,7 +818,7 @@ @Override public void visitInstrArray(Opcode opcode, int vsrcOrDest, int varray, int vindex) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vsrcOrDest = registerToSlot(vsrcOrDest); varray = registerToSlot(varray); vindex = registerToSlot(vindex); @@ -829,7 +849,7 @@ @Override public void visitInstrInstanceof(Opcode opcode, int vdest, int vsrc, String type) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vdest = registerToSlot(vdest); vsrc = registerToSlot(vsrc); mv.visitVarInsn(ALOAD, vsrc); @@ -843,7 +863,7 @@ @Override public void visitInstrIfTest(Opcode opcode, int vsrc1, int vsrc2, Label label) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vsrc1 = registerToSlot(vsrc1); vsrc2 = registerToSlot(vsrc2); org.objectweb.asm.Label asmLabel = getASMLabel(label); @@ -873,13 +893,22 @@ } } + @Override + public void visitTryCatch(Label start, Label end, Label handler, String type) { + exceptionHandlerSet.add(handler); + type = (type == null)? null: TypeUtil.convertDescToInternal(type); + mv.visitTryCatchBlock(getASMLabel(start), getASMLabel(end), + getASMLabel(handler), + type); + } + // unimplemented @Override public void visitInstrFillArrayData(Opcode opcode, int vsrc, Object arrayData) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vsrc = registerToSlot(vsrc); throw new UnsupportedOperationException("NYI " + opcode); } @@ -887,7 +916,7 @@ @Override public void visitInstrFilledNewArray(Opcode opcode, int num, int va, int vpacked, String type) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); // don't forget to use registerToSlot throw new UnsupportedOperationException("NYI " + opcode); } @@ -895,17 +924,12 @@ @Override public void visitInstrSwitch(Opcode opcode, int vsrc, Map<Integer, Label> labels) { - fixStackAfterAMethodCall(); + fixStackAfterAMethodCallOrAnExceptionHandler(); vsrc = registerToSlot(vsrc); throw new UnsupportedOperationException("NYI " + opcode); } @Override - public void visitTryCatch(Label start, Label end, Label handler, String type) { - throw new UnsupportedOperationException("NYI"); - } - - @Override public void visitEnd() { mv.visitMaxs(-1, -1); mv.visitEnd();