Home | History | Annotate | Download | only in code
      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      */
     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);
     55         MAP.put(Rops.NOP,               Dops.NOP);
     56         MAP.put(Rops.MOVE_INT,          Dops.MOVE);
     57         MAP.put(Rops.MOVE_LONG,         Dops.MOVE_WIDE);
     58         MAP.put(Rops.MOVE_FLOAT,        Dops.MOVE);
     59         MAP.put(Rops.MOVE_DOUBLE,       Dops.MOVE_WIDE);
     60         MAP.put(Rops.MOVE_OBJECT,       Dops.MOVE_OBJECT);
     61         MAP.put(Rops.MOVE_PARAM_INT,    Dops.MOVE);
     62         MAP.put(Rops.MOVE_PARAM_LONG,   Dops.MOVE_WIDE);
     63         MAP.put(Rops.MOVE_PARAM_FLOAT,  Dops.MOVE);
     64         MAP.put(Rops.MOVE_PARAM_DOUBLE, Dops.MOVE_WIDE);
     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 
     73         MAP.put(Rops.CONST_INT,         Dops.CONST_4);
     74         MAP.put(Rops.CONST_LONG,        Dops.CONST_WIDE_16);
     75         MAP.put(Rops.CONST_FLOAT,       Dops.CONST_4);
     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          */
     87         MAP.put(Rops.CONST_OBJECT_NOTHROW, Dops.CONST_4);
     88 
     89         MAP.put(Rops.GOTO,                 Dops.GOTO);
     90         MAP.put(Rops.IF_EQZ_INT,           Dops.IF_EQZ);
     91         MAP.put(Rops.IF_NEZ_INT,           Dops.IF_NEZ);
     92         MAP.put(Rops.IF_LTZ_INT,           Dops.IF_LTZ);
     93         MAP.put(Rops.IF_GEZ_INT,           Dops.IF_GEZ);
     94         MAP.put(Rops.IF_LEZ_INT,           Dops.IF_LEZ);
     95         MAP.put(Rops.IF_GTZ_INT,           Dops.IF_GTZ);
     96         MAP.put(Rops.IF_EQZ_OBJECT,        Dops.IF_EQZ);
     97         MAP.put(Rops.IF_NEZ_OBJECT,        Dops.IF_NEZ);
     98         MAP.put(Rops.IF_EQ_INT,            Dops.IF_EQ);
     99         MAP.put(Rops.IF_NE_INT,            Dops.IF_NE);
    100         MAP.put(Rops.IF_LT_INT,            Dops.IF_LT);
    101         MAP.put(Rops.IF_GE_INT,            Dops.IF_GE);
    102         MAP.put(Rops.IF_LE_INT,            Dops.IF_LE);
    103         MAP.put(Rops.IF_GT_INT,            Dops.IF_GT);
    104         MAP.put(Rops.IF_EQ_OBJECT,         Dops.IF_EQ);
    105         MAP.put(Rops.IF_NE_OBJECT,         Dops.IF_NE);
    106         MAP.put(Rops.SWITCH,               Dops.SPARSE_SWITCH);
    107         MAP.put(Rops.ADD_INT,              Dops.ADD_INT_2ADDR);
    108         MAP.put(Rops.ADD_LONG,             Dops.ADD_LONG_2ADDR);
    109         MAP.put(Rops.ADD_FLOAT,            Dops.ADD_FLOAT_2ADDR);
    110         MAP.put(Rops.ADD_DOUBLE,           Dops.ADD_DOUBLE_2ADDR);
    111         MAP.put(Rops.SUB_INT,              Dops.SUB_INT_2ADDR);
    112         MAP.put(Rops.SUB_LONG,             Dops.SUB_LONG_2ADDR);
    113         MAP.put(Rops.SUB_FLOAT,            Dops.SUB_FLOAT_2ADDR);
    114         MAP.put(Rops.SUB_DOUBLE,           Dops.SUB_DOUBLE_2ADDR);
    115         MAP.put(Rops.MUL_INT,              Dops.MUL_INT_2ADDR);
    116         MAP.put(Rops.MUL_LONG,             Dops.MUL_LONG_2ADDR);
    117         MAP.put(Rops.MUL_FLOAT,            Dops.MUL_FLOAT_2ADDR);
    118         MAP.put(Rops.MUL_DOUBLE,           Dops.MUL_DOUBLE_2ADDR);
    119         MAP.put(Rops.DIV_INT,              Dops.DIV_INT_2ADDR);
    120         MAP.put(Rops.DIV_LONG,             Dops.DIV_LONG_2ADDR);
    121         MAP.put(Rops.DIV_FLOAT,            Dops.DIV_FLOAT_2ADDR);
    122         MAP.put(Rops.DIV_DOUBLE,           Dops.DIV_DOUBLE_2ADDR);
    123         MAP.put(Rops.REM_INT,              Dops.REM_INT_2ADDR);
    124         MAP.put(Rops.REM_LONG,             Dops.REM_LONG_2ADDR);
    125         MAP.put(Rops.REM_FLOAT,            Dops.REM_FLOAT_2ADDR);
    126         MAP.put(Rops.REM_DOUBLE,           Dops.REM_DOUBLE_2ADDR);
    127         MAP.put(Rops.NEG_INT,              Dops.NEG_INT);
    128         MAP.put(Rops.NEG_LONG,             Dops.NEG_LONG);
    129         MAP.put(Rops.NEG_FLOAT,            Dops.NEG_FLOAT);
    130         MAP.put(Rops.NEG_DOUBLE,           Dops.NEG_DOUBLE);
    131         MAP.put(Rops.AND_INT,              Dops.AND_INT_2ADDR);
    132         MAP.put(Rops.AND_LONG,             Dops.AND_LONG_2ADDR);
    133         MAP.put(Rops.OR_INT,               Dops.OR_INT_2ADDR);
    134         MAP.put(Rops.OR_LONG,              Dops.OR_LONG_2ADDR);
    135         MAP.put(Rops.XOR_INT,              Dops.XOR_INT_2ADDR);
    136         MAP.put(Rops.XOR_LONG,             Dops.XOR_LONG_2ADDR);
    137         MAP.put(Rops.SHL_INT,              Dops.SHL_INT_2ADDR);
    138         MAP.put(Rops.SHL_LONG,             Dops.SHL_LONG_2ADDR);
    139         MAP.put(Rops.SHR_INT,              Dops.SHR_INT_2ADDR);
    140         MAP.put(Rops.SHR_LONG,             Dops.SHR_LONG_2ADDR);
    141         MAP.put(Rops.USHR_INT,             Dops.USHR_INT_2ADDR);
    142         MAP.put(Rops.USHR_LONG,            Dops.USHR_LONG_2ADDR);
    143         MAP.put(Rops.NOT_INT,              Dops.NOT_INT);
    144         MAP.put(Rops.NOT_LONG,             Dops.NOT_LONG);
    145 
    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 
    155         MAP.put(Rops.MUL_CONST_INT,        Dops.MUL_INT_LIT8);
    156         // Note: No dalvik ops for other types of mul_const.
    157 
    158         MAP.put(Rops.DIV_CONST_INT,        Dops.DIV_INT_LIT8);
    159         // Note: No dalvik ops for other types of div_const.
    160 
    161         MAP.put(Rops.REM_CONST_INT,        Dops.REM_INT_LIT8);
    162         // Note: No dalvik ops for other types of rem_const.
    163 
    164         MAP.put(Rops.AND_CONST_INT,        Dops.AND_INT_LIT8);
    165         // Note: No dalvik op for and_const_long.
    166 
    167         MAP.put(Rops.OR_CONST_INT,         Dops.OR_INT_LIT8);
    168         // Note: No dalvik op for or_const_long.
    169 
    170         MAP.put(Rops.XOR_CONST_INT,        Dops.XOR_INT_LIT8);
    171         // Note: No dalvik op for xor_const_long.
    172 
    173         MAP.put(Rops.SHL_CONST_INT,        Dops.SHL_INT_LIT8);
    174         // Note: No dalvik op for shl_const_long.
    175 
    176         MAP.put(Rops.SHR_CONST_INT,        Dops.SHR_INT_LIT8);
    177         // Note: No dalvik op for shr_const_long.
    178 
    179         MAP.put(Rops.USHR_CONST_INT,       Dops.USHR_INT_LIT8);
    180         // Note: No dalvik op for shr_const_long.
    181 
    182         MAP.put(Rops.CMPL_LONG,            Dops.CMP_LONG);
    183         MAP.put(Rops.CMPL_FLOAT,           Dops.CMPL_FLOAT);
    184         MAP.put(Rops.CMPL_DOUBLE,          Dops.CMPL_DOUBLE);
    185         MAP.put(Rops.CMPG_FLOAT,           Dops.CMPG_FLOAT);
    186         MAP.put(Rops.CMPG_DOUBLE,          Dops.CMPG_DOUBLE);
    187         MAP.put(Rops.CONV_L2I,             Dops.LONG_TO_INT);
    188         MAP.put(Rops.CONV_F2I,             Dops.FLOAT_TO_INT);
    189         MAP.put(Rops.CONV_D2I,             Dops.DOUBLE_TO_INT);
    190         MAP.put(Rops.CONV_I2L,             Dops.INT_TO_LONG);
    191         MAP.put(Rops.CONV_F2L,             Dops.FLOAT_TO_LONG);
    192         MAP.put(Rops.CONV_D2L,             Dops.DOUBLE_TO_LONG);
    193         MAP.put(Rops.CONV_I2F,             Dops.INT_TO_FLOAT);
    194         MAP.put(Rops.CONV_L2F,             Dops.LONG_TO_FLOAT);
    195         MAP.put(Rops.CONV_D2F,             Dops.DOUBLE_TO_FLOAT);
    196         MAP.put(Rops.CONV_I2D,             Dops.INT_TO_DOUBLE);
    197         MAP.put(Rops.CONV_L2D,             Dops.LONG_TO_DOUBLE);
    198         MAP.put(Rops.CONV_F2D,             Dops.FLOAT_TO_DOUBLE);
    199         MAP.put(Rops.TO_BYTE,              Dops.INT_TO_BYTE);
    200         MAP.put(Rops.TO_CHAR,              Dops.INT_TO_CHAR);
    201         MAP.put(Rops.TO_SHORT,             Dops.INT_TO_SHORT);
    202         MAP.put(Rops.RETURN_VOID,          Dops.RETURN_VOID);
    203         MAP.put(Rops.RETURN_INT,           Dops.RETURN);
    204         MAP.put(Rops.RETURN_LONG,          Dops.RETURN_WIDE);
    205         MAP.put(Rops.RETURN_FLOAT,         Dops.RETURN);
    206         MAP.put(Rops.RETURN_DOUBLE,        Dops.RETURN_WIDE);
    207         MAP.put(Rops.RETURN_OBJECT,        Dops.RETURN_OBJECT);
    208         MAP.put(Rops.ARRAY_LENGTH,         Dops.ARRAY_LENGTH);
    209         MAP.put(Rops.THROW,                Dops.THROW);
    210         MAP.put(Rops.MONITOR_ENTER,        Dops.MONITOR_ENTER);
    211         MAP.put(Rops.MONITOR_EXIT,         Dops.MONITOR_EXIT);
    212         MAP.put(Rops.AGET_INT,             Dops.AGET);
    213         MAP.put(Rops.AGET_LONG,            Dops.AGET_WIDE);
    214         MAP.put(Rops.AGET_FLOAT,           Dops.AGET);
    215         MAP.put(Rops.AGET_DOUBLE,          Dops.AGET_WIDE);
    216         MAP.put(Rops.AGET_OBJECT,          Dops.AGET_OBJECT);
    217         MAP.put(Rops.AGET_BOOLEAN,         Dops.AGET_BOOLEAN);
    218         MAP.put(Rops.AGET_BYTE,            Dops.AGET_BYTE);
    219         MAP.put(Rops.AGET_CHAR,            Dops.AGET_CHAR);
    220         MAP.put(Rops.AGET_SHORT,           Dops.AGET_SHORT);
    221         MAP.put(Rops.APUT_INT,             Dops.APUT);
    222         MAP.put(Rops.APUT_LONG,            Dops.APUT_WIDE);
    223         MAP.put(Rops.APUT_FLOAT,           Dops.APUT);
    224         MAP.put(Rops.APUT_DOUBLE,          Dops.APUT_WIDE);
    225         MAP.put(Rops.APUT_OBJECT,          Dops.APUT_OBJECT);
    226         MAP.put(Rops.APUT_BOOLEAN,         Dops.APUT_BOOLEAN);
    227         MAP.put(Rops.APUT_BYTE,            Dops.APUT_BYTE);
    228         MAP.put(Rops.APUT_CHAR,            Dops.APUT_CHAR);
    229         MAP.put(Rops.APUT_SHORT,           Dops.APUT_SHORT);
    230         MAP.put(Rops.NEW_INSTANCE,         Dops.NEW_INSTANCE);
    231         MAP.put(Rops.CHECK_CAST,           Dops.CHECK_CAST);
    232         MAP.put(Rops.INSTANCE_OF,          Dops.INSTANCE_OF);
    233 
    234         MAP.put(Rops.GET_FIELD_LONG,       Dops.IGET_WIDE);
    235         MAP.put(Rops.GET_FIELD_FLOAT,      Dops.IGET);
    236         MAP.put(Rops.GET_FIELD_DOUBLE,     Dops.IGET_WIDE);
    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 
    243         MAP.put(Rops.GET_STATIC_LONG,      Dops.SGET_WIDE);
    244         MAP.put(Rops.GET_STATIC_FLOAT,     Dops.SGET);
    245         MAP.put(Rops.GET_STATIC_DOUBLE,    Dops.SGET_WIDE);
    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 
    252         MAP.put(Rops.PUT_FIELD_LONG,       Dops.IPUT_WIDE);
    253         MAP.put(Rops.PUT_FIELD_FLOAT,      Dops.IPUT);
    254         MAP.put(Rops.PUT_FIELD_DOUBLE,     Dops.IPUT_WIDE);
    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 
    261         MAP.put(Rops.PUT_STATIC_LONG,      Dops.SPUT_WIDE);
    262         MAP.put(Rops.PUT_STATIC_FLOAT,     Dops.SPUT);
    263         MAP.put(Rops.PUT_STATIC_DOUBLE,    Dops.SPUT_WIDE);
    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      */
    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