changeset 40:aa501bc3bdd7

Implemented rewriting of const32 and range invoke. Contributed-by: Remi Forax * dexlib/DexLibDexReader.java: See above. * rewriter/DexRewriter.java: Likewise. * (newAssertionError): Throw exception explicitly in every method.
author Michael Starzinger <michi@complang.tuwien.ac.at>
date Fri, 18 Mar 2011 01:39:50 +0100
parents 3e21c5b61980
children 0dc9d18f2633
files src/main/java/org/icedrobot/daneel/dex/dexlib/DexLibDexReader.java src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java
diffstat 2 files changed, 118 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/dex/dexlib/DexLibDexReader.java	Fri Mar 18 01:07:56 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/dex/dexlib/DexLibDexReader.java	Fri Mar 18 01:39:50 2011 +0100
@@ -62,18 +62,14 @@
 import org.jf.dexlib.StringIdItem;
 import org.jf.dexlib.TypeIdItem;
 import org.jf.dexlib.TypeListItem;
+import org.jf.dexlib.Code.FiveRegisterInstruction;
 import org.jf.dexlib.Code.Instruction;
 import org.jf.dexlib.Code.InstructionWithReference;
 import org.jf.dexlib.Code.LiteralInstruction;
+import org.jf.dexlib.Code.RegisterRangeInstruction;
 import org.jf.dexlib.Code.SingleRegisterInstruction;
 import org.jf.dexlib.Code.Format.Instruction21c;
-import org.jf.dexlib.Code.Format.Instruction21h;
-import org.jf.dexlib.Code.Format.Instruction21s;
 import org.jf.dexlib.Code.Format.Instruction22c;
-import org.jf.dexlib.Code.Format.Instruction31c;
-import org.jf.dexlib.Code.Format.Instruction31i;
-import org.jf.dexlib.Code.Format.Instruction35c;
-import org.jf.dexlib.Code.Format.Instruction51l;
 import org.jf.dexlib.EncodedValue.BooleanEncodedValue;
 import org.jf.dexlib.EncodedValue.ByteEncodedValue;
 import org.jf.dexlib.EncodedValue.CharEncodedValue;
@@ -337,6 +333,13 @@
             break;
         }
 
+        case INSTR_CONST_U32: {
+            int vdest = ((SingleRegisterInstruction) instr).getRegisterA();
+            long value = ((LiteralInstruction) instr).getLiteral();
+            mv.visitInstrConstU32(opcode, vdest, (int)value);
+            break;
+        }
+        
         case INSTR_CONST_U64: {
             int vdest = ((SingleRegisterInstruction) instr).getRegisterA();
             long value = ((LiteralInstruction) instr).getLiteral();
@@ -353,16 +356,28 @@
             break;
         }
 
-        case INSTR_METHOD: { // TODO implement range !!!
-            Instruction35c i35c = (Instruction35c) instr;
-            MethodIdItem methodIdItem = (MethodIdItem) i35c.getReferencedItem();
+        case INSTR_METHOD: {
+            int va, vpacked, size;
+            if (instr instanceof RegisterRangeInstruction) {  // range
+        	RegisterRangeInstruction rangeInstr = (RegisterRangeInstruction)instr;
+        	size = rangeInstr.getRegCount();
+        	va = rangeInstr.getStartRegister();
+        	vpacked = 0;
+            } else { // packed
+        	FiveRegisterInstruction fiveInstr = (FiveRegisterInstruction)instr;
+        	size = fiveInstr.getRegCount();
+        	va = fiveInstr.getRegisterA();
+        	vpacked = fiveInstr.getRegisterG() << 12 | fiveInstr.getRegisterF() << 8
+        	| fiveInstr.getRegisterE() << 4 | fiveInstr.getRegisterD();
+            }
+            InstructionWithReference refInstr = (InstructionWithReference) instr;
+            MethodIdItem methodIdItem = (MethodIdItem) refInstr.getReferencedItem();
             String desc = methodIdItem.getPrototype().getPrototypeString();
-            int vpacked = i35c.getRegisterG() << 12 | i35c.getRegisterF() << 8
-                    | i35c.getRegisterE() << 4 | i35c.getRegisterD();
-            mv.visitInstrMethod(opcode, i35c.getRegCount(),
-                    i35c.getRegisterA(), vpacked,
+            mv.visitInstrMethod(opcode,
+        	    size, va, vpacked,
                     methodIdItem.getContainingClass().getTypeDescriptor(),
-                    methodIdItem.getMethodName().getStringValue(), desc);
+                    methodIdItem.getMethodName().getStringValue(),
+                    desc);
             break;
         }
 
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Fri Mar 18 01:07:56 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Fri Mar 18 01:39:50 2011 +0100
@@ -178,8 +178,8 @@
             return getTypeFromASMType(Type.getReturnType(descriptor));
         }
 
-        private static void throwNewAssertionError(Opcode opcode) {
-            throw new AssertionError("invalid opcode " + opcode);
+        private static AssertionError newAssertionError(Opcode opcode) {
+            return new AssertionError("Invalid opcode: " + opcode);
         }
 
         @Override
@@ -199,7 +199,7 @@
                 mv.visitInsn(NOP);
                 return;
             }
-            throwNewAssertionError(opcode);
+            throw newAssertionError(opcode);
         }
 
         @Override
@@ -235,7 +235,7 @@
                 mv.visitFieldInsn(PUTSTATIC, owner, name, desc);
                 interpreter.load(vsrcOrDest, type);
             } else {
-                throwNewAssertionError(opcode);
+                throw newAssertionError(opcode);
             }
         }
 
@@ -249,47 +249,90 @@
         @Override
         public void visitInstrMethod(Opcode opcode, int num, int va,
                 int vpacked, String owner, String name, String desc) {
-            owner = TypeUtil.convertDescToInternal(owner);
-            switch (opcode) {
-            case INVOKE_VIRTUAL:
-            case INVOKE_STATIC:
-            case INVOKE_SUPER:
-            case INVOKE_DIRECT:
-                int javaOpcode;
-                int[] registers = { getRegisterD(vpacked),
+
+            Opcode erasedRangeOpcode;
+            int[] registers;
+            if (opcode.compareTo(Opcode.INVOKE_VIRTUAL_RANGE) >= 0) { // *_range
+                registers = null;
+                erasedRangeOpcode = Opcode.getOpcode(opcode.ordinal()
+                        - INVOKE_RANGE_SHIFT);
+            } else {
+                registers = new int[] { getRegisterD(vpacked),
                         getRegisterE(vpacked), getRegisterF(vpacked),
                         getRegisterG(vpacked), va };
-                int r;
-                if (opcode == Opcode.INVOKE_STATIC) {
-                    r = 0;
-                    javaOpcode = INVOKESTATIC;
-                } else {
-                    r = 1;
-                    javaOpcode = (opcode == Opcode.INVOKE_SUPER) ? INVOKESPECIAL
-                            : (opcode == Opcode.INVOKE_DIRECT && "<init>"
-                                    .equals(name)) ? INVOKESPECIAL
-                                    : INVOKEVIRTUAL;
-                    int register = registers[0];
-                    mv.visitVarInsn(ALOAD, register);
-                    interpreter.load(register, OBJECT_TYPE);
-                }
+                erasedRangeOpcode = opcode;
+            }
+
+            int javaOpcode;
+            switch (erasedRangeOpcode) {
+            case INVOKE_STATIC:
+                javaOpcode = INVOKESTATIC;
+                break;
+            case INVOKE_SUPER:
+                javaOpcode = INVOKESPECIAL;
+                break;
+            case INVOKE_VIRTUAL:
+                javaOpcode = INVOKEVIRTUAL;
+                break;
+            case INVOKE_INTERFACE:
+                javaOpcode = INVOKEINTERFACE;
+                break;
+            case INVOKE_DIRECT:
+                javaOpcode = ("<init>".equals(name)) ? INVOKESPECIAL
+                        : INVOKEVIRTUAL;
+                break;
+            default:
+                throw newAssertionError(opcode);
+            }
+
+            // We need to load the receiver first.
+            int r;
+            if (erasedRangeOpcode != Opcode.INVOKE_STATIC) {
+                r = 1;
+                int register = (registers == null) ? va : registers[0];
+                mv.visitVarInsn(ALOAD, register);
+                interpreter.load(register, OBJECT_TYPE);
+            } else {
+                r = 0;
+            }
 
-                Type[] types = Type.getArgumentTypes(desc);
-                for (int i = 0; i < types.length; i++) {
-                    Type asmType = types[i];
-                    int type = getTypeFromASMType(asmType);
-                    int register = registers[r];
-                    mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD),
-                            register);
-                    interpreter.load(register, type);
-                    r += asmType.getSize();
+            Type[] types = Type.getArgumentTypes(desc);
+            for (Type asmType : types) {
+                int type = getTypeFromASMType(asmType);
+                int register = (registers == null) ? va + r : registers[r];
+                mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), register);
+                interpreter.load(register, type);
+                r += asmType.getSize();
+            }
+
+            owner = TypeUtil.convertDescToInternal(owner);
+            mv.visitMethodInsn(javaOpcode, owner, name, desc);
+            returnRegisterType = getReturnTypeFromMethodDescriptor(desc);
+            return;
+        }
+
+        private static final int INVOKE_RANGE_SHIFT =
+                Opcode.INVOKE_VIRTUAL_RANGE.ordinal() -
+                Opcode.INVOKE_VIRTUAL.ordinal();
+
+        @Override
+        public void visitInstrConstU32(Opcode opcode, final int vdest,
+                final int value) {
+            mv.setPatchMode();
+            mv.visitLdcInsn(value);
+            final AbstractInsnNode ldc = mv.getLastInsnNode();
+            mv.visitVarInsn(ISTORE, vdest);
+            final AbstractInsnNode istore = mv.getLastInsnNode();
+            interpreter.storeArbitraryType(vdest, U32_TYPE, new Patchable() {
+                @Override
+                protected void patch(int registerType) {
+                    if (registerType == FLOAT_TYPE) {
+                        mv.patch(ldc, new LdcInsnNode(Float
+                                .intBitsToFloat(value)));
+                        mv.patch(istore, new VarInsnNode(FSTORE, vdest));
+                    }
                 }
-                mv.visitMethodInsn(javaOpcode, owner, name, desc);
-                returnRegisterType = getReturnTypeFromMethodDescriptor(desc);
-                return;
-            default:
-                throwNewAssertionError(opcode);
-            }
+            });
         }
 
         @Override
@@ -342,11 +385,6 @@
         }
 
         @Override
-        public void visitInstrConstU32(Opcode opcode, int vdest, int value) {
-            throw new UnsupportedOperationException("NYI: " + opcode);
-        }
-
-        @Override
         public void visitInstrFillArrayData(Opcode opcode, int vsrc,
                 Object arrayData) {
             throw new UnsupportedOperationException("NYI" + opcode);
@@ -403,16 +441,14 @@
         }
 
         @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();
         }
-
-        @Override
-        public void visitTryCatch(Label start, Label end, Label handler,
-                String type) {
-            // TODO Auto-generated method stub
-
-        }
     }
 }