1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dexgen.dex.code;
18 
19 import com.android.dexgen.rop.code.Insn;
20 import com.android.dexgen.rop.code.RegOps;
21 import com.android.dexgen.rop.code.RegisterSpec;
22 import com.android.dexgen.rop.code.Rop;
23 import com.android.dexgen.rop.code.Rops;
24 import com.android.dexgen.rop.code.ThrowingCstInsn;
25 import com.android.dexgen.rop.cst.Constant;
26 import com.android.dexgen.rop.cst.CstFieldRef;
27 import com.android.dexgen.rop.cst.CstString;
28 import com.android.dexgen.rop.cst.CstType;
29 import com.android.dexgen.rop.type.Type;
30 
31 import java.util.HashMap;
32 
33 /**
34  * Translator from rop-level {@link Insn} instances to corresponding
35  * {@link Dop} instances.
36  */
37 public final class RopToDop {
38     /** {@code non-null;} map from all the common rops to dalvik opcodes */
39     private static final HashMap<Rop, Dop> MAP;
40 
41     /**
42      * This class is uninstantiable.
43      */
RopToDop()44     private RopToDop() {
45         // This space intentionally left blank.
46     }
47 
48     static {
49         /*
50          * Note: The choices made here are to pick the optimistically
51          * smallest Dalvik opcode, and leave it to later processing to
52          * pessimize.
53          */
54         MAP = new HashMap<Rop, Dop>(400);
MAP.put(Rops.NOP, Dops.NOP)55         MAP.put(Rops.NOP,               Dops.NOP);
MAP.put(Rops.MOVE_INT, Dops.MOVE)56         MAP.put(Rops.MOVE_INT,          Dops.MOVE);
MAP.put(Rops.MOVE_LONG, Dops.MOVE_WIDE)57         MAP.put(Rops.MOVE_LONG,         Dops.MOVE_WIDE);
MAP.put(Rops.MOVE_FLOAT, Dops.MOVE)58         MAP.put(Rops.MOVE_FLOAT,        Dops.MOVE);
MAP.put(Rops.MOVE_DOUBLE, Dops.MOVE_WIDE)59         MAP.put(Rops.MOVE_DOUBLE,       Dops.MOVE_WIDE);
MAP.put(Rops.MOVE_OBJECT, Dops.MOVE_OBJECT)60         MAP.put(Rops.MOVE_OBJECT,       Dops.MOVE_OBJECT);
MAP.put(Rops.MOVE_PARAM_INT, Dops.MOVE)61         MAP.put(Rops.MOVE_PARAM_INT,    Dops.MOVE);
MAP.put(Rops.MOVE_PARAM_LONG, Dops.MOVE_WIDE)62         MAP.put(Rops.MOVE_PARAM_LONG,   Dops.MOVE_WIDE);
MAP.put(Rops.MOVE_PARAM_FLOAT, Dops.MOVE)63         MAP.put(Rops.MOVE_PARAM_FLOAT,  Dops.MOVE);
MAP.put(Rops.MOVE_PARAM_DOUBLE, Dops.MOVE_WIDE)64         MAP.put(Rops.MOVE_PARAM_DOUBLE, Dops.MOVE_WIDE);
MAP.put(Rops.MOVE_PARAM_OBJECT, Dops.MOVE_OBJECT)65         MAP.put(Rops.MOVE_PARAM_OBJECT, Dops.MOVE_OBJECT);
66 
67         /*
68          * Note: No entry for MOVE_EXCEPTION, since it varies by
69          * exception type. (That is, there is no unique instance to
70          * add to the map.)
71          */
72 
MAP.put(Rops.CONST_INT, Dops.CONST_4)73         MAP.put(Rops.CONST_INT,         Dops.CONST_4);
MAP.put(Rops.CONST_LONG, Dops.CONST_WIDE_16)74         MAP.put(Rops.CONST_LONG,        Dops.CONST_WIDE_16);
MAP.put(Rops.CONST_FLOAT, Dops.CONST_4)75         MAP.put(Rops.CONST_FLOAT,       Dops.CONST_4);
MAP.put(Rops.CONST_DOUBLE, Dops.CONST_WIDE_16)76         MAP.put(Rops.CONST_DOUBLE,      Dops.CONST_WIDE_16);
77 
78         /*
79          * Note: No entry for CONST_OBJECT, since it needs to turn
80          * into either CONST_STRING or CONST_CLASS.
81          */
82 
83         /*
84          * TODO: I think the only case of this is for null, and
85          * const/4 should cover that.
86          */
MAP.put(Rops.CONST_OBJECT_NOTHROW, Dops.CONST_4)87         MAP.put(Rops.CONST_OBJECT_NOTHROW, Dops.CONST_4);
88 
MAP.put(Rops.GOTO, Dops.GOTO)89         MAP.put(Rops.GOTO,                 Dops.GOTO);
MAP.put(Rops.IF_EQZ_INT, Dops.IF_EQZ)90         MAP.put(Rops.IF_EQZ_INT,           Dops.IF_EQZ);
MAP.put(Rops.IF_NEZ_INT, Dops.IF_NEZ)91         MAP.put(Rops.IF_NEZ_INT,           Dops.IF_NEZ);
MAP.put(Rops.IF_LTZ_INT, Dops.IF_LTZ)92         MAP.put(Rops.IF_LTZ_INT,           Dops.IF_LTZ);
MAP.put(Rops.IF_GEZ_INT, Dops.IF_GEZ)93         MAP.put(Rops.IF_GEZ_INT,           Dops.IF_GEZ);
MAP.put(Rops.IF_LEZ_INT, Dops.IF_LEZ)94         MAP.put(Rops.IF_LEZ_INT,           Dops.IF_LEZ);
MAP.put(Rops.IF_GTZ_INT, Dops.IF_GTZ)95         MAP.put(Rops.IF_GTZ_INT,           Dops.IF_GTZ);
MAP.put(Rops.IF_EQZ_OBJECT, Dops.IF_EQZ)96         MAP.put(Rops.IF_EQZ_OBJECT,        Dops.IF_EQZ);
MAP.put(Rops.IF_NEZ_OBJECT, Dops.IF_NEZ)97         MAP.put(Rops.IF_NEZ_OBJECT,        Dops.IF_NEZ);
MAP.put(Rops.IF_EQ_INT, Dops.IF_EQ)98         MAP.put(Rops.IF_EQ_INT,            Dops.IF_EQ);
MAP.put(Rops.IF_NE_INT, Dops.IF_NE)99         MAP.put(Rops.IF_NE_INT,            Dops.IF_NE);
MAP.put(Rops.IF_LT_INT, Dops.IF_LT)100         MAP.put(Rops.IF_LT_INT,            Dops.IF_LT);
MAP.put(Rops.IF_GE_INT, Dops.IF_GE)101         MAP.put(Rops.IF_GE_INT,            Dops.IF_GE);
MAP.put(Rops.IF_LE_INT, Dops.IF_LE)102         MAP.put(Rops.IF_LE_INT,            Dops.IF_LE);
MAP.put(Rops.IF_GT_INT, Dops.IF_GT)103         MAP.put(Rops.IF_GT_INT,            Dops.IF_GT);
MAP.put(Rops.IF_EQ_OBJECT, Dops.IF_EQ)104         MAP.put(Rops.IF_EQ_OBJECT,         Dops.IF_EQ);
MAP.put(Rops.IF_NE_OBJECT, Dops.IF_NE)105         MAP.put(Rops.IF_NE_OBJECT,         Dops.IF_NE);
MAP.put(Rops.SWITCH, Dops.SPARSE_SWITCH)106         MAP.put(Rops.SWITCH,               Dops.SPARSE_SWITCH);
MAP.put(Rops.ADD_INT, Dops.ADD_INT_2ADDR)107         MAP.put(Rops.ADD_INT,              Dops.ADD_INT_2ADDR);
MAP.put(Rops.ADD_LONG, Dops.ADD_LONG_2ADDR)108         MAP.put(Rops.ADD_LONG,             Dops.ADD_LONG_2ADDR);
MAP.put(Rops.ADD_FLOAT, Dops.ADD_FLOAT_2ADDR)109         MAP.put(Rops.ADD_FLOAT,            Dops.ADD_FLOAT_2ADDR);
MAP.put(Rops.ADD_DOUBLE, Dops.ADD_DOUBLE_2ADDR)110         MAP.put(Rops.ADD_DOUBLE,           Dops.ADD_DOUBLE_2ADDR);
MAP.put(Rops.SUB_INT, Dops.SUB_INT_2ADDR)111         MAP.put(Rops.SUB_INT,              Dops.SUB_INT_2ADDR);
MAP.put(Rops.SUB_LONG, Dops.SUB_LONG_2ADDR)112         MAP.put(Rops.SUB_LONG,             Dops.SUB_LONG_2ADDR);
MAP.put(Rops.SUB_FLOAT, Dops.SUB_FLOAT_2ADDR)113         MAP.put(Rops.SUB_FLOAT,            Dops.SUB_FLOAT_2ADDR);
MAP.put(Rops.SUB_DOUBLE, Dops.SUB_DOUBLE_2ADDR)114         MAP.put(Rops.SUB_DOUBLE,           Dops.SUB_DOUBLE_2ADDR);
MAP.put(Rops.MUL_INT, Dops.MUL_INT_2ADDR)115         MAP.put(Rops.MUL_INT,              Dops.MUL_INT_2ADDR);
MAP.put(Rops.MUL_LONG, Dops.MUL_LONG_2ADDR)116         MAP.put(Rops.MUL_LONG,             Dops.MUL_LONG_2ADDR);
MAP.put(Rops.MUL_FLOAT, Dops.MUL_FLOAT_2ADDR)117         MAP.put(Rops.MUL_FLOAT,            Dops.MUL_FLOAT_2ADDR);
MAP.put(Rops.MUL_DOUBLE, Dops.MUL_DOUBLE_2ADDR)118         MAP.put(Rops.MUL_DOUBLE,           Dops.MUL_DOUBLE_2ADDR);
MAP.put(Rops.DIV_INT, Dops.DIV_INT_2ADDR)119         MAP.put(Rops.DIV_INT,              Dops.DIV_INT_2ADDR);
MAP.put(Rops.DIV_LONG, Dops.DIV_LONG_2ADDR)120         MAP.put(Rops.DIV_LONG,             Dops.DIV_LONG_2ADDR);
MAP.put(Rops.DIV_FLOAT, Dops.DIV_FLOAT_2ADDR)121         MAP.put(Rops.DIV_FLOAT,            Dops.DIV_FLOAT_2ADDR);
MAP.put(Rops.DIV_DOUBLE, Dops.DIV_DOUBLE_2ADDR)122         MAP.put(Rops.DIV_DOUBLE,           Dops.DIV_DOUBLE_2ADDR);
MAP.put(Rops.REM_INT, Dops.REM_INT_2ADDR)123         MAP.put(Rops.REM_INT,              Dops.REM_INT_2ADDR);
MAP.put(Rops.REM_LONG, Dops.REM_LONG_2ADDR)124         MAP.put(Rops.REM_LONG,             Dops.REM_LONG_2ADDR);
MAP.put(Rops.REM_FLOAT, Dops.REM_FLOAT_2ADDR)125         MAP.put(Rops.REM_FLOAT,            Dops.REM_FLOAT_2ADDR);
MAP.put(Rops.REM_DOUBLE, Dops.REM_DOUBLE_2ADDR)126         MAP.put(Rops.REM_DOUBLE,           Dops.REM_DOUBLE_2ADDR);
MAP.put(Rops.NEG_INT, Dops.NEG_INT)127         MAP.put(Rops.NEG_INT,              Dops.NEG_INT);
MAP.put(Rops.NEG_LONG, Dops.NEG_LONG)128         MAP.put(Rops.NEG_LONG,             Dops.NEG_LONG);
MAP.put(Rops.NEG_FLOAT, Dops.NEG_FLOAT)129         MAP.put(Rops.NEG_FLOAT,            Dops.NEG_FLOAT);
MAP.put(Rops.NEG_DOUBLE, Dops.NEG_DOUBLE)130         MAP.put(Rops.NEG_DOUBLE,           Dops.NEG_DOUBLE);
MAP.put(Rops.AND_INT, Dops.AND_INT_2ADDR)131         MAP.put(Rops.AND_INT,              Dops.AND_INT_2ADDR);
MAP.put(Rops.AND_LONG, Dops.AND_LONG_2ADDR)132         MAP.put(Rops.AND_LONG,             Dops.AND_LONG_2ADDR);
MAP.put(Rops.OR_INT, Dops.OR_INT_2ADDR)133         MAP.put(Rops.OR_INT,               Dops.OR_INT_2ADDR);
MAP.put(Rops.OR_LONG, Dops.OR_LONG_2ADDR)134         MAP.put(Rops.OR_LONG,              Dops.OR_LONG_2ADDR);
MAP.put(Rops.XOR_INT, Dops.XOR_INT_2ADDR)135         MAP.put(Rops.XOR_INT,              Dops.XOR_INT_2ADDR);
MAP.put(Rops.XOR_LONG, Dops.XOR_LONG_2ADDR)136         MAP.put(Rops.XOR_LONG,             Dops.XOR_LONG_2ADDR);
MAP.put(Rops.SHL_INT, Dops.SHL_INT_2ADDR)137         MAP.put(Rops.SHL_INT,              Dops.SHL_INT_2ADDR);
MAP.put(Rops.SHL_LONG, Dops.SHL_LONG_2ADDR)138         MAP.put(Rops.SHL_LONG,             Dops.SHL_LONG_2ADDR);
MAP.put(Rops.SHR_INT, Dops.SHR_INT_2ADDR)139         MAP.put(Rops.SHR_INT,              Dops.SHR_INT_2ADDR);
MAP.put(Rops.SHR_LONG, Dops.SHR_LONG_2ADDR)140         MAP.put(Rops.SHR_LONG,             Dops.SHR_LONG_2ADDR);
MAP.put(Rops.USHR_INT, Dops.USHR_INT_2ADDR)141         MAP.put(Rops.USHR_INT,             Dops.USHR_INT_2ADDR);
MAP.put(Rops.USHR_LONG, Dops.USHR_LONG_2ADDR)142         MAP.put(Rops.USHR_LONG,            Dops.USHR_LONG_2ADDR);
MAP.put(Rops.NOT_INT, Dops.NOT_INT)143         MAP.put(Rops.NOT_INT,              Dops.NOT_INT);
MAP.put(Rops.NOT_LONG, Dops.NOT_LONG)144         MAP.put(Rops.NOT_LONG,             Dops.NOT_LONG);
145 
MAP.put(Rops.ADD_CONST_INT, Dops.ADD_INT_LIT8)146         MAP.put(Rops.ADD_CONST_INT,        Dops.ADD_INT_LIT8);
147         // Note: No dalvik ops for other types of add_const.
148 
149         /*
150          * Note: No dalvik ops for any type of sub_const; there's a
151          * *reverse* sub (constant - reg) for ints, though, but that
152          * should end up getting handled at optimization time.
153          */
154 
MAP.put(Rops.MUL_CONST_INT, Dops.MUL_INT_LIT8)155         MAP.put(Rops.MUL_CONST_INT,        Dops.MUL_INT_LIT8);
156         // Note: No dalvik ops for other types of mul_const.
157 
MAP.put(Rops.DIV_CONST_INT, Dops.DIV_INT_LIT8)158         MAP.put(Rops.DIV_CONST_INT,        Dops.DIV_INT_LIT8);
159         // Note: No dalvik ops for other types of div_const.
160 
MAP.put(Rops.REM_CONST_INT, Dops.REM_INT_LIT8)161         MAP.put(Rops.REM_CONST_INT,        Dops.REM_INT_LIT8);
162         // Note: No dalvik ops for other types of rem_const.
163 
MAP.put(Rops.AND_CONST_INT, Dops.AND_INT_LIT8)164         MAP.put(Rops.AND_CONST_INT,        Dops.AND_INT_LIT8);
165         // Note: No dalvik op for and_const_long.
166 
MAP.put(Rops.OR_CONST_INT, Dops.OR_INT_LIT8)167         MAP.put(Rops.OR_CONST_INT,         Dops.OR_INT_LIT8);
168         // Note: No dalvik op for or_const_long.
169 
MAP.put(Rops.XOR_CONST_INT, Dops.XOR_INT_LIT8)170         MAP.put(Rops.XOR_CONST_INT,        Dops.XOR_INT_LIT8);
171         // Note: No dalvik op for xor_const_long.
172 
MAP.put(Rops.SHL_CONST_INT, Dops.SHL_INT_LIT8)173         MAP.put(Rops.SHL_CONST_INT,        Dops.SHL_INT_LIT8);
174         // Note: No dalvik op for shl_const_long.
175 
MAP.put(Rops.SHR_CONST_INT, Dops.SHR_INT_LIT8)176         MAP.put(Rops.SHR_CONST_INT,        Dops.SHR_INT_LIT8);
177         // Note: No dalvik op for shr_const_long.
178 
MAP.put(Rops.USHR_CONST_INT, Dops.USHR_INT_LIT8)179         MAP.put(Rops.USHR_CONST_INT,       Dops.USHR_INT_LIT8);
180         // Note: No dalvik op for shr_const_long.
181 
MAP.put(Rops.CMPL_LONG, Dops.CMP_LONG)182         MAP.put(Rops.CMPL_LONG,            Dops.CMP_LONG);
MAP.put(Rops.CMPL_FLOAT, Dops.CMPL_FLOAT)183         MAP.put(Rops.CMPL_FLOAT,           Dops.CMPL_FLOAT);
MAP.put(Rops.CMPL_DOUBLE, Dops.CMPL_DOUBLE)184         MAP.put(Rops.CMPL_DOUBLE,          Dops.CMPL_DOUBLE);
MAP.put(Rops.CMPG_FLOAT, Dops.CMPG_FLOAT)185         MAP.put(Rops.CMPG_FLOAT,           Dops.CMPG_FLOAT);
MAP.put(Rops.CMPG_DOUBLE, Dops.CMPG_DOUBLE)186         MAP.put(Rops.CMPG_DOUBLE,          Dops.CMPG_DOUBLE);
MAP.put(Rops.CONV_L2I, Dops.LONG_TO_INT)187         MAP.put(Rops.CONV_L2I,             Dops.LONG_TO_INT);
MAP.put(Rops.CONV_F2I, Dops.FLOAT_TO_INT)188         MAP.put(Rops.CONV_F2I,             Dops.FLOAT_TO_INT);
MAP.put(Rops.CONV_D2I, Dops.DOUBLE_TO_INT)189         MAP.put(Rops.CONV_D2I,             Dops.DOUBLE_TO_INT);
MAP.put(Rops.CONV_I2L, Dops.INT_TO_LONG)190         MAP.put(Rops.CONV_I2L,             Dops.INT_TO_LONG);
MAP.put(Rops.CONV_F2L, Dops.FLOAT_TO_LONG)191         MAP.put(Rops.CONV_F2L,             Dops.FLOAT_TO_LONG);
MAP.put(Rops.CONV_D2L, Dops.DOUBLE_TO_LONG)192         MAP.put(Rops.CONV_D2L,             Dops.DOUBLE_TO_LONG);
MAP.put(Rops.CONV_I2F, Dops.INT_TO_FLOAT)193         MAP.put(Rops.CONV_I2F,             Dops.INT_TO_FLOAT);
MAP.put(Rops.CONV_L2F, Dops.LONG_TO_FLOAT)194         MAP.put(Rops.CONV_L2F,             Dops.LONG_TO_FLOAT);
MAP.put(Rops.CONV_D2F, Dops.DOUBLE_TO_FLOAT)195         MAP.put(Rops.CONV_D2F,             Dops.DOUBLE_TO_FLOAT);
MAP.put(Rops.CONV_I2D, Dops.INT_TO_DOUBLE)196         MAP.put(Rops.CONV_I2D,             Dops.INT_TO_DOUBLE);
MAP.put(Rops.CONV_L2D, Dops.LONG_TO_DOUBLE)197         MAP.put(Rops.CONV_L2D,             Dops.LONG_TO_DOUBLE);
MAP.put(Rops.CONV_F2D, Dops.FLOAT_TO_DOUBLE)198         MAP.put(Rops.CONV_F2D,             Dops.FLOAT_TO_DOUBLE);
MAP.put(Rops.TO_BYTE, Dops.INT_TO_BYTE)199         MAP.put(Rops.TO_BYTE,              Dops.INT_TO_BYTE);
MAP.put(Rops.TO_CHAR, Dops.INT_TO_CHAR)200         MAP.put(Rops.TO_CHAR,              Dops.INT_TO_CHAR);
MAP.put(Rops.TO_SHORT, Dops.INT_TO_SHORT)201         MAP.put(Rops.TO_SHORT,             Dops.INT_TO_SHORT);
MAP.put(Rops.RETURN_VOID, Dops.RETURN_VOID)202         MAP.put(Rops.RETURN_VOID,          Dops.RETURN_VOID);
MAP.put(Rops.RETURN_INT, Dops.RETURN)203         MAP.put(Rops.RETURN_INT,           Dops.RETURN);
MAP.put(Rops.RETURN_LONG, Dops.RETURN_WIDE)204         MAP.put(Rops.RETURN_LONG,          Dops.RETURN_WIDE);
MAP.put(Rops.RETURN_FLOAT, Dops.RETURN)205         MAP.put(Rops.RETURN_FLOAT,         Dops.RETURN);
MAP.put(Rops.RETURN_DOUBLE, Dops.RETURN_WIDE)206         MAP.put(Rops.RETURN_DOUBLE,        Dops.RETURN_WIDE);
MAP.put(Rops.RETURN_OBJECT, Dops.RETURN_OBJECT)207         MAP.put(Rops.RETURN_OBJECT,        Dops.RETURN_OBJECT);
MAP.put(Rops.ARRAY_LENGTH, Dops.ARRAY_LENGTH)208         MAP.put(Rops.ARRAY_LENGTH,         Dops.ARRAY_LENGTH);
MAP.put(Rops.THROW, Dops.THROW)209         MAP.put(Rops.THROW,                Dops.THROW);
MAP.put(Rops.MONITOR_ENTER, Dops.MONITOR_ENTER)210         MAP.put(Rops.MONITOR_ENTER,        Dops.MONITOR_ENTER);
MAP.put(Rops.MONITOR_EXIT, Dops.MONITOR_EXIT)211         MAP.put(Rops.MONITOR_EXIT,         Dops.MONITOR_EXIT);
MAP.put(Rops.AGET_INT, Dops.AGET)212         MAP.put(Rops.AGET_INT,             Dops.AGET);
MAP.put(Rops.AGET_LONG, Dops.AGET_WIDE)213         MAP.put(Rops.AGET_LONG,            Dops.AGET_WIDE);
MAP.put(Rops.AGET_FLOAT, Dops.AGET)214         MAP.put(Rops.AGET_FLOAT,           Dops.AGET);
MAP.put(Rops.AGET_DOUBLE, Dops.AGET_WIDE)215         MAP.put(Rops.AGET_DOUBLE,          Dops.AGET_WIDE);
MAP.put(Rops.AGET_OBJECT, Dops.AGET_OBJECT)216         MAP.put(Rops.AGET_OBJECT,          Dops.AGET_OBJECT);
MAP.put(Rops.AGET_BOOLEAN, Dops.AGET_BOOLEAN)217         MAP.put(Rops.AGET_BOOLEAN,         Dops.AGET_BOOLEAN);
MAP.put(Rops.AGET_BYTE, Dops.AGET_BYTE)218         MAP.put(Rops.AGET_BYTE,            Dops.AGET_BYTE);
MAP.put(Rops.AGET_CHAR, Dops.AGET_CHAR)219         MAP.put(Rops.AGET_CHAR,            Dops.AGET_CHAR);
MAP.put(Rops.AGET_SHORT, Dops.AGET_SHORT)220         MAP.put(Rops.AGET_SHORT,           Dops.AGET_SHORT);
MAP.put(Rops.APUT_INT, Dops.APUT)221         MAP.put(Rops.APUT_INT,             Dops.APUT);
MAP.put(Rops.APUT_LONG, Dops.APUT_WIDE)222         MAP.put(Rops.APUT_LONG,            Dops.APUT_WIDE);
MAP.put(Rops.APUT_FLOAT, Dops.APUT)223         MAP.put(Rops.APUT_FLOAT,           Dops.APUT);
MAP.put(Rops.APUT_DOUBLE, Dops.APUT_WIDE)224         MAP.put(Rops.APUT_DOUBLE,          Dops.APUT_WIDE);
MAP.put(Rops.APUT_OBJECT, Dops.APUT_OBJECT)225         MAP.put(Rops.APUT_OBJECT,          Dops.APUT_OBJECT);
MAP.put(Rops.APUT_BOOLEAN, Dops.APUT_BOOLEAN)226         MAP.put(Rops.APUT_BOOLEAN,         Dops.APUT_BOOLEAN);
MAP.put(Rops.APUT_BYTE, Dops.APUT_BYTE)227         MAP.put(Rops.APUT_BYTE,            Dops.APUT_BYTE);
MAP.put(Rops.APUT_CHAR, Dops.APUT_CHAR)228         MAP.put(Rops.APUT_CHAR,            Dops.APUT_CHAR);
MAP.put(Rops.APUT_SHORT, Dops.APUT_SHORT)229         MAP.put(Rops.APUT_SHORT,           Dops.APUT_SHORT);
MAP.put(Rops.NEW_INSTANCE, Dops.NEW_INSTANCE)230         MAP.put(Rops.NEW_INSTANCE,         Dops.NEW_INSTANCE);
MAP.put(Rops.CHECK_CAST, Dops.CHECK_CAST)231         MAP.put(Rops.CHECK_CAST,           Dops.CHECK_CAST);
MAP.put(Rops.INSTANCE_OF, Dops.INSTANCE_OF)232         MAP.put(Rops.INSTANCE_OF,          Dops.INSTANCE_OF);
233 
MAP.put(Rops.GET_FIELD_LONG, Dops.IGET_WIDE)234         MAP.put(Rops.GET_FIELD_LONG,       Dops.IGET_WIDE);
MAP.put(Rops.GET_FIELD_FLOAT, Dops.IGET)235         MAP.put(Rops.GET_FIELD_FLOAT,      Dops.IGET);
MAP.put(Rops.GET_FIELD_DOUBLE, Dops.IGET_WIDE)236         MAP.put(Rops.GET_FIELD_DOUBLE,     Dops.IGET_WIDE);
MAP.put(Rops.GET_FIELD_OBJECT, Dops.IGET_OBJECT)237         MAP.put(Rops.GET_FIELD_OBJECT,     Dops.IGET_OBJECT);
238         /*
239          * Note: No map entries for get_field_* for non-long integral types,
240          * since they need to be handled specially (see dopFor() below).
241          */
242 
MAP.put(Rops.GET_STATIC_LONG, Dops.SGET_WIDE)243         MAP.put(Rops.GET_STATIC_LONG,      Dops.SGET_WIDE);
MAP.put(Rops.GET_STATIC_FLOAT, Dops.SGET)244         MAP.put(Rops.GET_STATIC_FLOAT,     Dops.SGET);
MAP.put(Rops.GET_STATIC_DOUBLE, Dops.SGET_WIDE)245         MAP.put(Rops.GET_STATIC_DOUBLE,    Dops.SGET_WIDE);
MAP.put(Rops.GET_STATIC_OBJECT, Dops.SGET_OBJECT)246         MAP.put(Rops.GET_STATIC_OBJECT,    Dops.SGET_OBJECT);
247         /*
248          * Note: No map entries for get_static* for non-long integral types,
249          * since they need to be handled specially (see dopFor() below).
250          */
251 
MAP.put(Rops.PUT_FIELD_LONG, Dops.IPUT_WIDE)252         MAP.put(Rops.PUT_FIELD_LONG,       Dops.IPUT_WIDE);
MAP.put(Rops.PUT_FIELD_FLOAT, Dops.IPUT)253         MAP.put(Rops.PUT_FIELD_FLOAT,      Dops.IPUT);
MAP.put(Rops.PUT_FIELD_DOUBLE, Dops.IPUT_WIDE)254         MAP.put(Rops.PUT_FIELD_DOUBLE,     Dops.IPUT_WIDE);
MAP.put(Rops.PUT_FIELD_OBJECT, Dops.IPUT_OBJECT)255         MAP.put(Rops.PUT_FIELD_OBJECT,     Dops.IPUT_OBJECT);
256         /*
257          * Note: No map entries for put_field_* for non-long integral types,
258          * since they need to be handled specially (see dopFor() below).
259          */
260 
MAP.put(Rops.PUT_STATIC_LONG, Dops.SPUT_WIDE)261         MAP.put(Rops.PUT_STATIC_LONG,      Dops.SPUT_WIDE);
MAP.put(Rops.PUT_STATIC_FLOAT, Dops.SPUT)262         MAP.put(Rops.PUT_STATIC_FLOAT,     Dops.SPUT);
MAP.put(Rops.PUT_STATIC_DOUBLE, Dops.SPUT_WIDE)263         MAP.put(Rops.PUT_STATIC_DOUBLE,    Dops.SPUT_WIDE);
MAP.put(Rops.PUT_STATIC_OBJECT, Dops.SPUT_OBJECT)264         MAP.put(Rops.PUT_STATIC_OBJECT,    Dops.SPUT_OBJECT);
265         /*
266          * Note: No map entries for put_static* for non-long integral types,
267          * since they need to be handled specially (see dopFor() below).
268          */
269 
270         /*
271          * Note: No map entries for invoke*, new_array, and
272          * filled_new_array, since they need to be handled specially
273          * (see dopFor() below).
274          */
275     }
276 
277     /**
278      * Returns the dalvik opcode appropriate for the given register-based
279      * instruction.
280      *
281      * @param insn {@code non-null;} the original instruction
282      * @return the corresponding dalvik opcode; one of the constants in
283      * {@link Dops}
284      */
dopFor(Insn insn)285     public static Dop dopFor(Insn insn) {
286         Rop rop = insn.getOpcode();
287 
288         /*
289          * First, just try looking up the rop in the MAP of easy
290          * cases.
291          */
292         Dop result = MAP.get(rop);
293         if (result != null) {
294             return result;
295         }
296 
297         /*
298          * There was no easy case for the rop, so look up the opcode, and
299          * do something special for each:
300          *
301          * The move_exception, new_array, filled_new_array, and
302          * invoke* opcodes won't be found in MAP, since they'll each
303          * have different source and/or result register types / lists.
304          *
305          * The get* and put* opcodes for (non-long) integral types
306          * aren't in the map, since the type signatures aren't
307          * sufficient to distinguish between the types (the salient
308          * source or result will always be just "int").
309          *
310          * And const instruction need to distinguish between strings and
311          * classes.
312          */
313 
314         switch (rop.getOpcode()) {
315             case RegOps.MOVE_EXCEPTION:   return Dops.MOVE_EXCEPTION;
316             case RegOps.INVOKE_STATIC:    return Dops.INVOKE_STATIC;
317             case RegOps.INVOKE_VIRTUAL:   return Dops.INVOKE_VIRTUAL;
318             case RegOps.INVOKE_SUPER:     return Dops.INVOKE_SUPER;
319             case RegOps.INVOKE_DIRECT:    return Dops.INVOKE_DIRECT;
320             case RegOps.INVOKE_INTERFACE: return Dops.INVOKE_INTERFACE;
321             case RegOps.NEW_ARRAY:        return Dops.NEW_ARRAY;
322             case RegOps.FILLED_NEW_ARRAY: return Dops.FILLED_NEW_ARRAY;
323             case RegOps.FILL_ARRAY_DATA:  return Dops.FILL_ARRAY_DATA;
324             case RegOps.MOVE_RESULT: {
325                 RegisterSpec resultReg = insn.getResult();
326 
327                 if (resultReg == null) {
328                     return Dops.NOP;
329                 } else {
330                     switch (resultReg.getBasicType()) {
331                         case Type.BT_INT:
332                         case Type.BT_FLOAT:
333                         case Type.BT_BOOLEAN:
334                         case Type.BT_BYTE:
335                         case Type.BT_CHAR:
336                         case Type.BT_SHORT:
337                             return Dops.MOVE_RESULT;
338                         case Type.BT_LONG:
339                         case Type.BT_DOUBLE:
340                             return Dops.MOVE_RESULT_WIDE;
341                         case Type.BT_OBJECT:
342                             return Dops.MOVE_RESULT_OBJECT;
343                         default: {
344                             throw new RuntimeException("Unexpected basic type");
345                         }
346                     }
347                 }
348             }
349 
350             case RegOps.GET_FIELD: {
351                 CstFieldRef ref =
352                     (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
353                 int basicType = ref.getBasicType();
354                 switch (basicType) {
355                     case Type.BT_BOOLEAN: return Dops.IGET_BOOLEAN;
356                     case Type.BT_BYTE:    return Dops.IGET_BYTE;
357                     case Type.BT_CHAR:    return Dops.IGET_CHAR;
358                     case Type.BT_SHORT:   return Dops.IGET_SHORT;
359                     case Type.BT_INT:     return Dops.IGET;
360                 }
361                 break;
362             }
363             case RegOps.PUT_FIELD: {
364                 CstFieldRef ref =
365                     (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
366                 int basicType = ref.getBasicType();
367                 switch (basicType) {
368                     case Type.BT_BOOLEAN: return Dops.IPUT_BOOLEAN;
369                     case Type.BT_BYTE:    return Dops.IPUT_BYTE;
370                     case Type.BT_CHAR:    return Dops.IPUT_CHAR;
371                     case Type.BT_SHORT:   return Dops.IPUT_SHORT;
372                     case Type.BT_INT:     return Dops.IPUT;
373                 }
374                 break;
375             }
376             case RegOps.GET_STATIC: {
377                 CstFieldRef ref =
378                     (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
379                 int basicType = ref.getBasicType();
380                 switch (basicType) {
381                     case Type.BT_BOOLEAN: return Dops.SGET_BOOLEAN;
382                     case Type.BT_BYTE:    return Dops.SGET_BYTE;
383                     case Type.BT_CHAR:    return Dops.SGET_CHAR;
384                     case Type.BT_SHORT:   return Dops.SGET_SHORT;
385                     case Type.BT_INT:     return Dops.SGET;
386                 }
387                 break;
388             }
389             case RegOps.PUT_STATIC: {
390                 CstFieldRef ref =
391                     (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
392                 int basicType = ref.getBasicType();
393                 switch (basicType) {
394                     case Type.BT_BOOLEAN: return Dops.SPUT_BOOLEAN;
395                     case Type.BT_BYTE:    return Dops.SPUT_BYTE;
396                     case Type.BT_CHAR:    return Dops.SPUT_CHAR;
397                     case Type.BT_SHORT:   return Dops.SPUT_SHORT;
398                     case Type.BT_INT:     return Dops.SPUT;
399                 }
400                 break;
401             }
402             case RegOps.CONST: {
403                 Constant cst = ((ThrowingCstInsn) insn).getConstant();
404                 if (cst instanceof CstType) {
405                     return Dops.CONST_CLASS;
406                 } else if (cst instanceof CstString) {
407                     return Dops.CONST_STRING;
408                 }
409                 break;
410             }
411         }
412 
413         throw new RuntimeException("unknown rop: " + rop);
414     }
415 }
416