changeset 81:96c63feb973c

This patch: - compute register types from method parameters - implements array_length - refactor the code that creates array to allow array of objects
author forax
date Sat, 26 Mar 2011 00:46:50 +0100
parents 817b7941153f
children 474e8b694138
files src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java src/main/java/org/icedrobot/daneel/rewriter/Interpreter.java src/main/java/org/icedrobot/daneel/rewriter/Register.java
diffstat 3 files changed, 61 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Fri Mar 25 23:59:09 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Sat Mar 26 00:46:50 2011 +0100
@@ -43,6 +43,7 @@
 import static org.icedrobot.daneel.rewriter.Registers.*;
 
 import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
@@ -60,6 +61,7 @@
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 import org.objectweb.asm.tree.AbstractInsnNode;
 import org.objectweb.asm.tree.InsnNode;
@@ -68,7 +70,7 @@
 
 public class DexRewriter implements DexClassVisitor {
     private final ClassVisitor cv;
-
+    
     /**
      * Rewrites a class from Dalvik bytecode into Java bytecode representation.
      * The source class is given by specifying its name and the DEX source it is
@@ -145,7 +147,7 @@
             return null;
         }
 
-        return new MethodRewriter(mv, desc);
+        return new MethodRewriter(mv, (access & Opcodes.ACC_STATIC) != 0, desc);
     }
 
     @Override
@@ -155,7 +157,8 @@
 
     static class MethodRewriter implements DexMethodVisitor {
         final PatchMethodVisitor mv;
-        final String desc;
+        private final boolean isStatic;
+        private final String desc;
 
         private Interpreter interpreter;
         private int returnRegisterType;   // type of the register used to stored
@@ -171,8 +174,9 @@
         private final Set<Label> exceptionHandlerSet =
             Collections.newSetFromMap(new IdentityHashMap<Label, Boolean>());
 
-        public MethodRewriter(MethodVisitor mv, String desc) {
+        public MethodRewriter(MethodVisitor mv, boolean isStatic, String desc) {
             this.mv = new PatchMethodVisitor(mv);
+            this.isStatic = isStatic;
             this.desc = desc;
             this.returnRegisterType = VOID_TYPE;
         }
@@ -326,7 +330,26 @@
             mv.visitCode();
             this.locals = registerSize - insSize;
             this.parameters = insSize;
-            interpreter = new Interpreter(registerSize);
+            
+            Register[] registers = new Register[registerSize];
+            Arrays.fill(registers, 0, registerSize, Register.UNINITIALIZED);
+            
+            Type[] parameterTypes = Type.getArgumentTypes(desc);
+            int length = parameterTypes.length;
+            int slot;
+            if (isStatic) {
+                slot = 0;
+            } else {
+                registers[0] = new Register(OBJECT_TYPE, null);
+                slot = 1;
+            }
+            for (int i = 0; i < length; i++) {
+                Type type = parameterTypes[i];
+                registers[slot] = new Register(getTypeFromASMType(type), null);
+                slot += type.getSize();
+            }
+            
+            interpreter = new Interpreter(registers);
         }
 
         @Override
@@ -641,6 +664,10 @@
                 return;
             }
             
+            case ARRAY_LENGTH:
+                srcType = OBJECT_TYPE;
+                dstType = INT_TYPE;
+                break;
             case NEG_INT: case NOT_INT:
                 dstType = INT_TYPE;
                 break;
@@ -660,7 +687,9 @@
                 dstType = BYTE_TYPE + opcode.ordinal() - Opcode.INT_TO_BYTE.ordinal();
                 break;
                 
-            default: {
+            default: { // INT_TO_LONG, INT_TO_FLOAT, INT_TO_DOUBLE, LONG_TO_INT, LONG_TO_FLOAT,
+                       // LONG_TO_DOUBLE, FLOAT_TO_INT, FLOAT_TO_LONG, DOUBLE_TO_INT,
+                       // DOUBLE_TO_LONG, DOUBLE_TO_FLOAT
                 int conversion = opcode.ordinal() - Opcode.INT_TO_LONG.ordinal();
                 int div = conversion / 3;
                 int modulo = conversion % 3;
@@ -810,9 +839,18 @@
             vsize = registerToSlot(vsize);
             mv.visitVarInsn(ILOAD, vsize);
             interpreter.load(vsize, INT_TYPE);
-            mv.visitIntInsn(NEWARRAY, getNewArrayKindFromASMType(Type.getType(typeDesc).getElementType()));
+            
+            String componentTypeDesc = typeDesc.substring(1);
+            Type asmComponentType = Type.getType(componentTypeDesc);
+            int componentType = getTypeFromASMType(asmComponentType);
+            if (Register.isArray(componentType) || componentType == OBJECT_TYPE) {
+                mv.visitTypeInsn(ANEWARRAY, asmComponentType.getInternalName());
+            } else {
+                mv.visitIntInsn(NEWARRAY, getNewArrayKindFromASMType(asmComponentType));
+            }
+            
             mv.visitVarInsn(ASTORE, vdest);
-            interpreter.store(vdest, getTypeFromASMType(Type.getType(typeDesc)));
+            interpreter.store(vdest, Register.makeArray(componentType, 1));
         }
         
         @Override
@@ -921,6 +959,7 @@
             throw new UnsupportedOperationException("NYI " + opcode);
         }
 
+        @Override
         public void visitInstrPackedSwitch(Opcode opcode, int vsrc,
                 int firstKey, Label[] targets) {
             fixStackAfterAMethodCallOrAnExceptionHandler();
--- a/src/main/java/org/icedrobot/daneel/rewriter/Interpreter.java	Fri Mar 25 23:59:09 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/rewriter/Interpreter.java	Sat Mar 26 00:46:50 2011 +0100
@@ -40,11 +40,13 @@
 import java.util.Arrays;
 import java.util.HashMap;
 
+import org.objectweb.asm.Type;
+
 /**
  * An abstract interpreter for virtual registers. It is used to infer the
  * register type information by tracking all load and store operations on them.
  */
-public class Interpreter {
+class Interpreter {
     private final Register[] registers;
     private final HashMap<Object, Register[]> joinPointMap = new HashMap<Object, Register[]>();
     private boolean isDead;
@@ -53,12 +55,10 @@
      * Creates a new abstract interpreter capable of tracking a given number of
      * virtual registers.
      * 
-     * @param maxRegisters The number of registers to handle.
+     * @param registers The array of registers to handle.
      */
-    public Interpreter(int maxRegisters) {
-        Register[] registers = new Register[maxRegisters];
-        Arrays.fill(registers, Register.UNINITIALIZED);
-        this.registers = registers;
+    Interpreter(Register[] registers) {
+       this.registers = registers;
     }
 
     /**
--- a/src/main/java/org/icedrobot/daneel/rewriter/Register.java	Fri Mar 25 23:59:09 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/rewriter/Register.java	Sat Mar 26 00:46:50 2011 +0100
@@ -211,17 +211,18 @@
         return (type & UNTYPED_MASK) != 0;
     }
     
-    /** Create the type of an array of type.
-     * @param elementType the element type of the array (which can't be an array itself)
-     * @param dimension the dimension of the array. As in Java or Dalvik, the dimension
-     *                  is limited to 255.
+    /** Create an array of type.
+     * @param componentType the component type of the array (which can be an array itself)
+     * @param dimension the dimension of the array. As in Java or Dalvik, the resulting
+     *                  array dimension is limited to 255.
      * @return the corresponding array type.
      */
-    public static int makeArray(int elementType, int dimension) {
-        if (isUntyped(elementType) || isArray(elementType)) {
+    public static int makeArray(int componentType, int dimension) {
+        if (isUntyped(componentType)) {
             throw new IllegalArgumentException("invalid type");
         }
-        return dimension << 8 | (elementType & 0xFF);
+        return ((((componentType >> 8) & 0xFF) + dimension) << 8)
+                | (componentType & 0xFF);
     }
     
     /** Returns true if the type is an array type.