changeset 95:2a82664dd5cd

Untyped U32 are considered as int by if-eqz/if-nez/if-eq/if-ne. - visitInstrTest/visitInstrTestZ know consider U32 as itself. - Patchable.union should use doPatch instead of patch - join-point processing is refactored in one method: createOrMergeJoinPoint
author forax
date Mon, 28 Mar 2011 16:06:48 +0200
parents cb75377db25b
children 27565952c952
files src/main/java/org/icedrobot/daneel/rewriter/DalvikToJVMEncoder.java src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java src/main/java/org/icedrobot/daneel/rewriter/Patchable.java
diffstat 3 files changed, 141 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/rewriter/DalvikToJVMEncoder.java	Mon Mar 28 16:01:16 2011 +0200
+++ b/src/main/java/org/icedrobot/daneel/rewriter/DalvikToJVMEncoder.java	Mon Mar 28 16:06:48 2011 +0200
@@ -175,8 +175,6 @@
                 Opcode.GOTO,      Opcodes.GOTO,
                 GOTO_16,          Opcodes.GOTO,
                 
-                IF_EQZ,           IFEQ,
-                IF_NEZ,           IFNE,
                 IF_LTZ,           IFLT,
                 IF_GEZ,           IFGE,
                 IF_GTZ,           IFGT,
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Mon Mar 28 16:01:16 2011 +0200
+++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Mon Mar 28 16:06:48 2011 +0200
@@ -65,6 +65,8 @@
 import org.objectweb.asm.Type;
 import org.objectweb.asm.tree.AbstractInsnNode;
 import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LabelNode;
 import org.objectweb.asm.tree.LdcInsnNode;
 import org.objectweb.asm.tree.VarInsnNode;
 
@@ -286,6 +288,15 @@
             }
         }
         
+        private void createOrMergeJoinPoint(Label label) {
+            Register[] registers = interpreter.getJoinPoint(label);
+            if (registers != null) { // backward jump
+                interpreter.merge(registers);
+            } else {  // forward jump
+                interpreter.cloneJoinPoint(label);    
+            }
+        }
+        
         private void visitNotInstr(int type) {
             org.objectweb.asm.Label falsePart = new org.objectweb.asm.Label();
             org.objectweb.asm.Label endPart = new org.objectweb.asm.Label();
@@ -583,6 +594,7 @@
                 mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), srcOrDst);
                 interpreter.load(srcOrDst, type);
                 mv.visitInsn(Register.getJavaOpcode(type, IRETURN));
+                interpreter.setDead();
                 break;
             }
             case MOVE_RESULT:
@@ -609,6 +621,9 @@
                 mv.visitVarInsn(ALOAD, srcOrDst);
                 interpreter.load(srcOrDst, OBJECT_TYPE);
                 mv.visitInsn(toJavaOpcode[opcode.ordinal()]);
+                if (opcode == Opcode.THROW) {
+                    interpreter.setDead();
+                }
             }
         }
         
@@ -794,45 +809,144 @@
             fixStackAfterAMethodCallOrAnExceptionHandler();
             exceptionOnTop = exceptionHandlerSet.contains(label);
             
-            Register[] registers = interpreter.getJoinPoint(label);   
-            if (registers != null) { // target of an already seen jump
-                interpreter.merge(registers);
-            } else {  // perhaps a control flow join point, save state
-                interpreter.cloneJoinPoint(label);
-            }
+            createOrMergeJoinPoint(label);
             mv.visitLabel(getASMLabel(label));
         }
         
         @Override
         public void visitInstrGoto(Opcode opcode, Label label) {
             fixStackAfterAMethodCallOrAnExceptionHandler();
-            Register[] registers = interpreter.getJoinPoint(label);
-            if (registers != null) { // backward goto
-                interpreter.merge(registers);
-            } else {  // forward goto
-                interpreter.cloneJoinPoint(label);    
-            }
+            createOrMergeJoinPoint(label);
             
             mv.visitJumpInsn(GOTO, getASMLabel(label));
             interpreter.setDead();
         }
         
         @Override
-        public void visitInstrIfTestZ(Opcode opcode, int vsrc, Label label) {
+        public void visitInstrIfTestZ(final Opcode opcode, int vsrc, Label label) {
             fixStackAfterAMethodCallOrAnExceptionHandler();
-            vsrc = registerToSlot(vsrc);
-            mv.visitVarInsn(ILOAD, vsrc);
-            interpreter.load(vsrc, INT_TYPE);
-            
-            Register[] registers = interpreter.getJoinPoint(label);
-            if (registers != null) { // backward jump
-                interpreter.merge(registers);
-            } else {  // forward jump
-                interpreter.cloneJoinPoint(label);    
+            final int ssrc = registerToSlot(vsrc);
+
+            int type, javaOpcode;
+            final org.objectweb.asm.Label asmLabel = getASMLabel(label);
+            if (opcode == Opcode.IF_EQZ || opcode == Opcode.IF_NEZ) {
+                final Register register = interpreter.getRegister(ssrc);
+                int srcType = register.getType();
+                if (srcType == U32_TYPE) {
+                    mv.visitVarInsn(ILOAD, ssrc);
+                    final AbstractInsnNode iload = mv.getLastInsnNode();
+                    javaOpcode = (opcode == Opcode.IF_EQZ)? IFEQ: IFNE;
+                    mv.visitJumpInsn(javaOpcode, asmLabel);
+                    final AbstractInsnNode jump = mv.getLastInsnNode();
+                    
+                    interpreter.storeUntypedType(ssrc, U32_TYPE, new Patchable() {
+                        @Override
+                        protected void patch(int registerType) {
+                            register.getPatchable().doPatch(registerType);
+                            if (registerType == OBJECT_TYPE || Register.isArray(registerType)) {
+                                mv.patch(iload, new VarInsnNode(ALOAD, ssrc));
+                                int javaOpcode = (opcode == Opcode.IF_EQZ)? IFNULL: IFNONNULL;
+                                mv.patch(jump, new JumpInsnNode(javaOpcode, new LabelNode(asmLabel)));
+                                return;
+                            }
+                        }
+                    });
+                    
+                    createOrMergeJoinPoint(label);
+                    return;
+                }  
+
+                if (srcType == OBJECT_TYPE || Register.isArray(srcType)) {
+                    type = OBJECT_TYPE;
+                    javaOpcode = (opcode == Opcode.IF_EQZ)? IFNULL: IFNONNULL;
+                } else { // a numeric type convertible to an int
+                    type = INT_TYPE;
+                    javaOpcode = (opcode == Opcode.IF_EQZ)? IFEQ: IFNE;
+                }
+            } else {   // IF_LTZ, IF_GEZ, IF_GTZ, IF_LEZ
+                type = INT_TYPE;
+                javaOpcode = toJavaOpcode[opcode.ordinal()];
             }
             
-            org.objectweb.asm.Label asmLabel = getASMLabel(label);
-            mv.visitJumpInsn(toJavaOpcode[opcode.ordinal()], asmLabel);
+            mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), ssrc);
+            interpreter.load(ssrc, type);
+            mv.visitJumpInsn(javaOpcode, asmLabel);
+            
+            createOrMergeJoinPoint(label);
+        }
+        
+        @Override
+        public void visitInstrIfTest(final Opcode opcode, int vvsrc1, int vvsrc2,
+                Label label) {
+            fixStackAfterAMethodCallOrAnExceptionHandler();
+            final int vsrc1 = registerToSlot(vvsrc1);
+            final int vsrc2 = registerToSlot(vvsrc2);
+            
+            int type, javaOpcode;
+            final org.objectweb.asm.Label asmLabel = getASMLabel(label);
+            if (opcode == Opcode.IF_EQ || opcode == Opcode.IF_NE) {
+                final Register register1 = interpreter.getRegister(vsrc1);
+                int src1Type = register1.getType();
+                final Register register2 = interpreter.getRegister(vsrc2);
+                int src2Type = register2.getType();
+                
+                if (src1Type == U32_TYPE && src2Type == U32_TYPE) {
+                    mv.visitVarInsn(ILOAD, vsrc1);
+                    final AbstractInsnNode iload1 = mv.getLastInsnNode();
+                    mv.visitVarInsn(ILOAD, vsrc2);
+                    final AbstractInsnNode iload2 = mv.getLastInsnNode();
+                    javaOpcode = (opcode == Opcode.IF_EQ)? IF_ICMPEQ: IF_ICMPNE;
+                    mv.visitJumpInsn(javaOpcode, asmLabel);
+                    final AbstractInsnNode jump = mv.getLastInsnNode();
+                    
+                    final Patchable patchableUnion = (register1 == register2)? register1.getPatchable():
+                        Patchable.union(register1.getPatchable(), register2.getPatchable());
+                    
+                    Patchable patchable = new Patchable() {
+                        @Override
+                        protected void patch(int registerType) {
+                            patchableUnion.doPatch(registerType);
+                            if (registerType == OBJECT_TYPE || Register.isArray(registerType)) {
+                                mv.patch(iload1, new VarInsnNode(ALOAD, vsrc1));
+                                mv.patch(iload2, new VarInsnNode(ALOAD, vsrc2));
+                                int javaOpcode = (opcode == Opcode.IF_EQ)? IF_ACMPEQ: IF_ACMPNE;
+                                mv.patch(jump, new JumpInsnNode(javaOpcode, new LabelNode(asmLabel)));
+                                return;
+                            }
+                        }
+                    };
+                    interpreter.storeUntypedType(vsrc1, U32_TYPE, patchable);
+                    if (vsrc1 != vsrc2) {
+                        interpreter.storeUntypedType(vsrc2, U32_TYPE, patchable);
+                    }
+                    
+                    createOrMergeJoinPoint(label);
+                    return;
+                }  
+                
+                if (src1Type == OBJECT_TYPE || src2Type == OBJECT_TYPE
+                        || Register.isArray(src1Type)
+                        || Register.isArray(src2Type)) {
+                    type = OBJECT_TYPE;
+                    javaOpcode = (opcode == Opcode.IF_EQ) ? IF_ACMPEQ
+                            : IF_ACMPNE;
+                } else { // a numeric type convertible to an int
+                    type = INT_TYPE;
+                    javaOpcode = (opcode == Opcode.IF_EQ) ? IF_ICMPEQ
+                            : IF_ICMPNE;
+                }
+            } else { // IF_LT, IF_GE, IF_GT, IF_LE
+                type = INT_TYPE;
+                javaOpcode = toJavaOpcode[opcode.ordinal()];
+            }
+            
+            mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc1);
+            interpreter.load(vsrc1, type);
+            mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc2);
+            interpreter.load(vsrc2, type);
+            mv.visitJumpInsn(javaOpcode, asmLabel);
+            
+            createOrMergeJoinPoint(label);
         }
         
         @Override
@@ -903,39 +1017,6 @@
         }
         
         @Override
-        public void visitInstrIfTest(Opcode opcode, int vsrc1, int vsrc2,
-                Label label) {
-            fixStackAfterAMethodCallOrAnExceptionHandler();
-            vsrc1 = registerToSlot(vsrc1);
-            vsrc2 = registerToSlot(vsrc2);
-            org.objectweb.asm.Label asmLabel = getASMLabel(label);
-            if (opcode == Opcode.IF_EQ || opcode == Opcode.IF_NE) {
-                int src1Type = interpreter.getRegister(vsrc1).getType();
-                int src2Type = interpreter.getRegister(vsrc2).getType();
-                int javaOpcode;
-                int type;
-                if (src1Type == INT_TYPE || src2Type == INT_TYPE) {
-                    type = INT_TYPE;
-                    javaOpcode = (opcode == Opcode.IF_EQ)? IF_ICMPEQ: IF_ICMPNE;
-                } else { // OBJECT_TYPE or array
-                    type = OBJECT_TYPE;
-                    javaOpcode = (opcode == Opcode.IF_EQ)? IF_ACMPEQ: IF_ACMPNE;
-                }
-                mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc1);
-                interpreter.load(vsrc1, OBJECT_TYPE);
-                mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc2);
-                interpreter.load(vsrc2, OBJECT_TYPE);
-                mv.visitJumpInsn(javaOpcode, asmLabel);
-            } else {   // IF_LT, IF_GE, IF_GT, IF_LE
-                mv.visitVarInsn(ILOAD, vsrc1);
-                interpreter.load(vsrc1, INT_TYPE);
-                mv.visitVarInsn(ILOAD, vsrc2);
-                interpreter.load(vsrc2, INT_TYPE);
-                mv.visitJumpInsn(toJavaOpcode[opcode.ordinal()], asmLabel);
-            }
-        }
-        
-        @Override
         public void visitTryCatch(Label start, Label end, Label handler, String type) {
             exceptionHandlerSet.add(handler);
             type = (type == null)? null: TypeUtil.convertDescToInternal(type);
@@ -1013,7 +1094,7 @@
     
     static final int[] toJavaOpcode;
     static { // this string is generated using DalvikToJVMEncoder
-        String text = "AA@@@@@@@@@@@@@@@@@@@@@@@@@@LB@@@@@@@@@@@@@@@@@@@@@@@@@@@@MCMDMAMBLOLLLM@@@@@@LPKHKHKH@@@@JFJGJHJIJE@@@@KBKCKDKEJJJKJLJMJNJO@@@@@@@@@@@@@@@@DCDDDDDEDF@@@@FDFEFEFFFG@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@HE@@HF@@HGHHIFIGIHIIIJIKILIMINIOIPJAJBJCJDGAGEGIGMHAGAIAICHIHKHMGBGFGJGNHBHPIBIDHJHLHNGCGGGKGOHCGDGHGLGPHDGAGEGIGMHAHOIAICHIHKHMGBGFGJGNHBHPIBIDHJHLHNGCGGGKGOHCGDGHGLGPHDGAGEGIGMHAGAIAICGAGEGIGMHAHOIAICHIHKHM@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
+        String text = "AA@@@@@@@@@@@@@@@@@@@@@@@@@@LB@@@@@@@@@@@@@@@@@@@@@@@@@@@@MCMDMAMBLOLLLM@@@@@@LPKHKHKH@@@@JFJGJHJIJE@@@@KBKCKDKE@@@@JLJMJNJO@@@@@@@@@@@@@@@@DCDDDDDEDF@@@@FDFEFEFFFG@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@HE@@HF@@HGHHIFIGIHIIIJIKILIMINIOIPJAJBJCJDGAGEGIGMHAGAIAICHIHKHMGBGFGJGNHBHPIBIDHJHLHNGCGGGKGOHCGDGHGLGPHDGAGEGIGMHAHOIAICHIHKHMGBGFGJGNHBHPIBIDHJHLHNGCGGGKGOHCGDGHGLGPHDGAGEGIGMHAGAIAICGAGEGIGMHAHOIAICHIHKHM@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
         int[] array = new int[256];
         int length = text.length();
         for (int i = 0; i < length; i += 2) {
--- a/src/main/java/org/icedrobot/daneel/rewriter/Patchable.java	Mon Mar 28 16:01:16 2011 +0200
+++ b/src/main/java/org/icedrobot/daneel/rewriter/Patchable.java	Mon Mar 28 16:06:48 2011 +0200
@@ -59,8 +59,8 @@
         return new Patchable() {
             @Override
             protected void patch(int registerType) {
-                patchable1.patch(registerType);
-                patchable2.patch(registerType);
+                patchable1.doPatch(registerType);
+                patchable2.doPatch(registerType);
             }
         };
     }