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 17package com.android.dx.dex.code; 18 19import com.android.dx.rop.code.Insn; 20import com.android.dx.rop.code.RegOps; 21import com.android.dx.rop.code.Rop; 22import com.android.dx.rop.code.Rops; 23import com.android.dx.rop.code.ThrowingCstInsn; 24import com.android.dx.rop.code.RegisterSpec; 25import com.android.dx.rop.cst.Constant; 26import com.android.dx.rop.cst.CstFieldRef; 27import com.android.dx.rop.cst.CstString; 28import com.android.dx.rop.cst.CstType; 29import com.android.dx.rop.type.Type; 30 31import java.util.HashMap; 32 33/** 34 * Translator from rop-level {@link Insn} instances to corresponding 35 * {@link Dop} instances. 36 */ 37public 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