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();