changeset 62:387a3d5f9695

Implemented binary and binary-literal operations. Contributed-by: Remi Forax * rewriter/DalvikToJVMEncoder.java: Generator for lookup table string. * rewriter/DexRewriter.java (visitInstrBinOp): Implemented. * (visitInstrBinOpAndLiteral): Likewise. * (toJavaOpcode): Added lookup table with static initialization.
author Michael Starzinger <michi@complang.tuwien.ac.at>
date Tue, 22 Mar 2011 02:11:59 +0100
parents 818050257c69
children cf225eeae6ee
files src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java src/main/java/org/icedrobot/daneel/rewriter/DalvikToJVMEncoder.java src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java
diffstat 3 files changed, 323 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java	Tue Mar 22 01:20:12 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java	Tue Mar 22 02:11:59 2011 +0100
@@ -145,7 +145,7 @@
      * @param vsrc1 First source register or register pair.
      * @param vsrc2 Second source register or register pair.
      */
-    void visitInstrBinOp(Opcode opcode, int vdest, int vsrc, int vsrc2);
+    void visitInstrBinOp(Opcode opcode, int vdest, int vsrc1, int vsrc2);
 
     /**
      * Visits an instruction with a {@code 22b|22s} format id.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/org/icedrobot/daneel/rewriter/DalvikToJVMEncoder.java	Tue Mar 22 02:11:59 2011 +0100
@@ -0,0 +1,238 @@
+/*
+ * Daneel - Dalvik to Java bytecode compiler
+ * Copyright (C) 2011  IcedRobot team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file is subject to the "Classpath" exception:
+ *
+ * Linking this library statically or dynamically with other modules is
+ * making a combined work based on this library.  Thus, the terms and
+ * conditions of the GNU General Public License cover the whole
+ * combination.
+ *
+ * As a special exception, the copyright holders of this library give you
+ * permission to link this library with independent modules to produce an
+ * executable, regardless of the license terms of these independent
+ * modules, and to copy and distribute the resulting executable under terms
+ * of your choice, provided that you also meet, for each linked independent
+ * module, the terms and conditions of the license of that module.  An
+ * independent module is a module which is not derived from or based on
+ * this library.  If you modify this library, you may extend this exception
+ * to your version of the library, but you are not obligated to do so.  If
+ * you do not wish to do so, delete this exception statement from your
+ * version.
+ */
+
+package org.icedrobot.daneel.rewriter;
+
+import java.util.Arrays;
+
+import org.icedrobot.daneel.dex.Opcode;
+import org.objectweb.asm.Opcodes;
+
+import static org.icedrobot.daneel.dex.Opcode.*;
+import static org.objectweb.asm.Opcodes.*;
+
+class DalvikToJVMEncoder {
+    public static void main(String[] args) {
+        Object[] map = {
+                Opcode.NOP,       Opcodes.NOP,
+                RETURN_VOID,      Opcodes.RETURN,
+                
+                MONITOR_ENTER,    MONITORENTER,
+                MONITOR_EXIT,     MONITOREXIT,
+                THROW,            ATHROW,
+                
+                NEG_INT,          INEG,
+                NEG_LONG,         LNEG,
+                NEG_FLOAT,        FNEG,
+                NEG_DOUBLE,       DNEG,
+                INT_TO_LONG,      I2L,
+                INT_TO_FLOAT,     I2F,
+                INT_TO_DOUBLE,    I2D,
+                LONG_TO_INT,      L2I,
+                LONG_TO_FLOAT,    L2F,
+                LONG_TO_DOUBLE,   L2D,
+                FLOAT_TO_INT,     F2I,
+                FLOAT_TO_LONG,    F2L,
+                FLOAT_TO_DOUBLE,  F2D,
+                DOUBLE_TO_INT,    D2I,
+                DOUBLE_TO_LONG,   D2L,
+                DOUBLE_TO_FLOAT,  D2F,
+                INT_TO_BYTE,      I2B,
+                INT_TO_CHAR,      I2C,
+                INT_TO_SHORT,     I2S,
+                ARRAY_LENGTH,     ARRAYLENGTH,
+                
+                CMPL_FLOAT,       FCMPL,
+                CMPG_FLOAT,       FCMPG,
+                CMPL_DOUBLE,      DCMPL,
+                CMPG_DOUBLE,      DCMPG,
+                CMP_LONG,         LCMP,
+                ADD_INT,          IADD,
+                SUB_INT,          ISUB,
+                MUL_INT,          IMUL,
+                DIV_INT,          IDIV,
+                REM_INT,          IREM,
+                AND_INT,          IADD,
+                OR_INT,           IOR,
+                XOR_INT,          IXOR,
+                SHL_INT,          ISHL,
+                SHR_INT,          ISHR,
+                USHR_INT,         IUSHR,
+                ADD_LONG,         LADD,
+                SUB_LONG,         LSUB,
+                MUL_LONG,         LMUL,
+                DIV_LONG,         LDIV,
+                REM_LONG,         LREM,
+                AND_LONG,         LAND,
+                OR_LONG,          LOR,
+                XOR_LONG,         LXOR,
+                SHL_LONG,         LSHL,
+                SHR_LONG,         LSHR,
+                USHR_LONG,        LUSHR,
+                ADD_FLOAT,        FADD,
+                SUB_FLOAT,        FSUB,
+                MUL_FLOAT,        FMUL,
+                DIV_FLOAT,        FDIV,
+                REM_FLOAT,        FREM,
+                ADD_DOUBLE,       DADD,
+                SUB_DOUBLE,       DSUB,
+                MUL_DOUBLE,       DMUL,
+                DIV_DOUBLE,       DDIV,
+                REM_DOUBLE,       DREM,
+                ADD_INT_2ADDR,    IADD,
+                SUB_INT_2ADDR,    ISUB,
+                MUL_INT_2ADDR,    IMUL,
+                DIV_INT_2ADDR,    IDIV,
+                REM_INT_2ADDR,    IREM,
+                AND_INT_2ADDR,    IAND,
+                OR_INT_2ADDR,     IOR,
+                XOR_INT_2ADDR,    IXOR,
+                SHL_INT_2ADDR,    ISHL,
+                SHR_INT_2ADDR,    ISHR,
+                USHR_INT_2ADDR,   IUSHR,
+                ADD_LONG_2ADDR,   LADD,
+                SUB_LONG_2ADDR,   LSUB,
+                MUL_LONG_2ADDR,   LMUL,
+                DIV_LONG_2ADDR,   LDIV,
+                REM_LONG_2ADDR,   LREM,
+                AND_LONG_2ADDR,   LAND,
+                OR_LONG_2ADDR,    LOR,
+                XOR_LONG_2ADDR,   LXOR,
+                SHL_LONG_2ADDR,   LSHL,
+                SHR_LONG_2ADDR,   LSHR,
+                USHR_LONG_2ADDR,  LUSHR,
+                ADD_FLOAT_2ADDR,  FADD,
+                SUB_FLOAT_2ADDR,  FSUB,
+                MUL_FLOAT_2ADDR,  FMUL,
+                DIV_FLOAT_2ADDR,  FDIV,
+                REM_FLOAT_2ADDR,  FREM,
+                ADD_DOUBLE_2ADDR, DADD,
+                SUB_DOUBLE_2ADDR, DSUB,
+                MUL_DOUBLE_2ADDR, DMUL,
+                DIV_DOUBLE_2ADDR, DDIV,
+                REM_DOUBLE_2ADDR, DREM,
+                
+                ADD_INT_LIT16,    IADD,
+                RSUB_INT_LIT16,   ISUB,
+                MUL_INT_LIT16,    IMUL,
+                DIV_INT_LIT16,    IDIV,
+                REM_INT_LIT16,    IREM,
+                AND_INT_LIT16,    IADD,
+                OR_INT_LIT16,     IOR,
+                XOR_INT_LIT16,    IXOR,
+                ADD_INT_LIT8,     IADD,
+                RSUB_INT_LIT8,    ISUB,
+                MUL_INT_LIT8,     IMUL,
+                DIV_INT_LIT8,     IDIV,
+                REM_INT_LIT8,     IREM,
+                AND_INT_LIT8,     IAND,
+                OR_INT_LIT8,      IOR,
+                XOR_INT_LIT8,     IXOR,
+                SHL_INT_LIT8,     ISHL,
+                SHR_INT_LIT8,     ISHR,
+                USHR_INT_LIT8,    IUSHR,
+                
+                CHECK_CAST,       CHECKCAST,
+                NEW_INSTANCE,     NEW,
+                
+                INSTANCE_OF,      INSTANCEOF,
+                
+                GOTO_32,          Opcodes.GOTO,
+                Opcode.GOTO,      Opcodes.GOTO,
+                GOTO_16,          Opcodes.GOTO,
+                
+                IF_EQZ,           IFEQ,
+                IF_NEZ,           IFNE,
+                IF_LTZ,           IFLT,
+                IF_GEZ,           IFGE,
+                IF_GTZ,           IFGT,
+                IF_LEZ,           IFLE,
+                
+                IF_LT,            IF_ICMPLT,
+                IF_LE,            IF_ICMPLE,
+                IF_GE,            IF_ICMPGE,
+                IF_GT,            IF_ICMPGT,
+                
+                APUT_OBJECT,      AASTORE,
+                APUT_BOOLEAN,     BASTORE,
+                APUT_BYTE,        BASTORE,
+                APUT_CHAR,        CASTORE,
+                APUT_SHORT,       SASTORE,
+                AGET_OBJECT,      AALOAD,
+                AGET_BOOLEAN,     BALOAD,
+                AGET_BYTE,        BALOAD,
+                AGET_CHAR,        CALOAD,
+                AGET_SHORT,       SALOAD,
+                
+                NEW_ARRAY,        NEWARRAY,
+                
+             };
+
+        // encode
+        char[] text = new char[512];
+        Arrays.fill(text, '@');
+        for (int i = 0; i < map.length; i += 2) {
+            Opcode opcode = (Opcode) map[i];
+            int javaOpcode = (Integer) map[i + 1];
+            
+            int javaOpcode_hi = javaOpcode >> 4;
+            int javaOpcode_lo = javaOpcode & 0x0f;
+            text[2 * opcode.ordinal()] = (char) ('A' + javaOpcode_hi);
+            text[2 * opcode.ordinal() + 1] = (char) ('A' + javaOpcode_lo);
+            
+        }
+        String s = new String(text);
+        System.out.println(s);
+        
+        // decode
+        int[] toJavaOpcode = new int[256];
+        int length = s.length();
+        for(int i=0; i<length; i+=2) {
+            int index = ((s.charAt(i) - 'A' ) << 4) | (s.charAt(i + 1) - 'A');
+            toJavaOpcode[i >> 1] = index;
+        }
+        
+        // check
+        for (int i = 0; i < map.length; i += 2) {
+            Opcode opcode = (Opcode) map[i];
+            int javaOpcode = (Integer) map[i + 1];
+            if (toJavaOpcode[opcode.ordinal()] != javaOpcode) {
+                throw new AssertionError();
+            }
+        }
+    }
+}
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Tue Mar 22 01:20:12 2011 +0100
+++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java	Tue Mar 22 02:11:59 2011 +0100
@@ -531,6 +531,76 @@
         }
 
         @Override
+        public void visitInstrBinOp(Opcode opcode, int vdest, int vsrc1,
+                int vsrc2) {
+            vdest = registerToSlot(vdest);
+            vsrc1 = registerToSlot(vsrc1);
+            vsrc2 = registerToSlot(vsrc2);
+            
+            // 2 addresses -> simple address opcode
+            if (opcode.compareTo(Opcode.ADD_INT_2ADDR) >= 0 &&
+                opcode.compareTo(Opcode.REM_DOUBLE_2ADDR) <= 0) {
+                opcode = Opcode.getOpcode(opcode.ordinal() + OP_2ADDR_SHIFT);
+            }
+            
+            int type;
+            switch(opcode) {
+            case CMPL_FLOAT: case CMPG_FLOAT: case ADD_FLOAT: case SUB_FLOAT:
+            case MUL_FLOAT: case DIV_FLOAT: case REM_FLOAT:
+                type = FLOAT_TYPE;
+                break;
+            
+            case CMPL_DOUBLE: case CMPG_DOUBLE: case ADD_DOUBLE: case SUB_DOUBLE:
+            case MUL_DOUBLE:  case DIV_DOUBLE: case REM_DOUBLE:
+                type = DOUBLE_TYPE;
+                break;
+                
+            case CMP_LONG: case ADD_LONG: case SUB_LONG: case MUL_LONG:
+            case DIV_LONG: case REM_LONG: case AND_LONG: case OR_LONG:
+            case XOR_LONG: case SHL_LONG: case SHR_LONG: case USHR_LONG:
+                type = LONG_TYPE;
+                break;
+              
+            // ADD_INT, SUB_INT, MUL_INT, DIV_INT, REM_INT,
+            // AND_INT, OR_INT, XOR_INT, SHL_INT, SHR_INT, USHR_INT,
+            default: 
+                type = INT_TYPE;
+            }
+            
+            mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc1);
+            interpreter.load(vsrc1, type);
+            mv.visitVarInsn(Register.getJavaOpcode(type, ILOAD), vsrc2);
+            interpreter.load(vsrc2, type);
+            mv.visitInsn(toJavaOpcode[opcode.ordinal()]);
+            mv.visitVarInsn(Register.getJavaOpcode(type, ISTORE), vdest);
+            interpreter.store(vdest, type);
+        }
+        
+        private static final int OP_2ADDR_SHIFT =
+            Opcode.ADD_INT.ordinal() - Opcode.ADD_INT_2ADDR.ordinal();
+
+        @Override
+        public void visitInstrBinOpAndLiteral(Opcode opcode, int vdest,
+                int vsrc, int value) {
+            vdest = registerToSlot(vdest);
+            vsrc = registerToSlot(vsrc);
+            
+            boolean rsub = opcode == Opcode.RSUB_INT_LIT16
+                    || opcode == Opcode.RSUB_INT_LIT8;
+            if (rsub) {
+                mv.visitLdcInsn(value);
+            }
+            mv.visitVarInsn(ILOAD, vsrc);
+            interpreter.load(vsrc, INT_TYPE);
+            if (!rsub) {
+                mv.visitLdcInsn(value);
+            }
+            mv.visitInsn(toJavaOpcode[opcode.ordinal()]);
+            mv.visitVarInsn(ISTORE, vdest);
+            interpreter.store(vdest, INT_TYPE);
+        }
+        
+        @Override
         public void visitLabel(Label label) {
             Register[] registers = interpreter.getJoinPoint(label);   
             if (registers != null) { // target of an already seen jump
@@ -568,8 +638,7 @@
             }
             
             org.objectweb.asm.Label asmLabel = getASMLabel(label);
-            int javaOpcode = IFEQ + opcode.ordinal() - Opcode.IF_EQZ.ordinal();
-            mv.visitJumpInsn(javaOpcode, asmLabel);
+            mv.visitJumpInsn(toJavaOpcode[opcode.ordinal()], asmLabel);
         }
         
         
@@ -591,23 +660,6 @@
         }
 
         @Override
-        public void visitInstrBinOp(Opcode opcode, int vdest, int vsrc,
-                int vsrc2) {
-            vdest = registerToSlot(vdest);
-            vsrc = registerToSlot(vsrc);
-            vsrc2 = registerToSlot(vsrc2);
-            throw new UnsupportedOperationException("NYI " + opcode);
-        }
-
-        @Override
-        public void visitInstrBinOpAndLiteral(Opcode opcode, int vdest,
-                int vsrc, int value) {
-            vdest = registerToSlot(vdest);
-            vsrc = registerToSlot(vsrc);
-            throw new UnsupportedOperationException("NYI " + opcode);
-        }
-
-        @Override
         public void visitInstrFillArrayData(Opcode opcode, int vsrc,
                 Object arrayData) {
             vsrc = registerToSlot(vsrc);
@@ -654,4 +706,17 @@
             mv.visitEnd();
         }
     }
+    
+    static final int[] toJavaOpcode;
+    static { // this string is generated using DalvikToJVMEncoder
+        String text = "AA@@@@@@@@@@@@@@@@@@@@@@@@@@LB@@@@@@@@@@@@@@@@@@@@@@@@@@@@MCMDMAMBLOLLLM@@@@@@LPKHKHKH@@@@JFJGJHJIJE@@@@KBKCKDKEJJJKJLJMJNJO@@@@@@@@@@@@@@@@DCDDDDDEDF@@@@FDFEFEFFFG@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@HE@@HF@@HGHHIFIGIHIIIJIKILIMINIOIPJAJBJCJDGAGEGIGMHAGAIAICHIHKHMGBGFGJGNHBHPIBIDHJHLHNGCGGGKGOHCGDGHGLGPHDGAGEGIGMHAHOIAICHIHKHMGBGFGJGNHBHPIBIDHJHLHNGCGGGKGOHCGDGHGLGPHDGAGEGIGMHAGAIAICGAGEGIGMHAHOIAICHIHKHM@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
+        int[] array = new int[256];
+        int length = text.length();
+        for (int i = 0; i < length; i += 2) {
+            int index = ((text.charAt(i) - 'A') << 4)
+                    | (text.charAt(i + 1) - 'A');
+            array[i >> 1] = index;
+        }
+        toJavaOpcode = array;
+    }
 }