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.CstType;
28import com.android.dx.rop.cst.CstString;
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    /*
49     * The following comment lists each opcode that should be considered
50     * the "head" of an opcode chain, in terms of the process of fitting
51     * an instruction's arguments to an actual opcode. This list is
52     * automatically generated and may be of use in double-checking the
53     * manually-generated static initialization code for this class.
54     *
55     * TODO: Make opcode-gen produce useful code in this case instead
56     * of just a comment.
57     */
58
59    // BEGIN(first-opcodes); GENERATED AUTOMATICALLY BY opcode-gen
60    //     Opcodes.NOP
61    //     Opcodes.MOVE
62    //     Opcodes.MOVE_WIDE
63    //     Opcodes.MOVE_OBJECT
64    //     Opcodes.MOVE_RESULT
65    //     Opcodes.MOVE_RESULT_WIDE
66    //     Opcodes.MOVE_RESULT_OBJECT
67    //     Opcodes.MOVE_EXCEPTION
68    //     Opcodes.RETURN_VOID
69    //     Opcodes.RETURN
70    //     Opcodes.RETURN_WIDE
71    //     Opcodes.RETURN_OBJECT
72    //     Opcodes.CONST_4
73    //     Opcodes.CONST_WIDE_16
74    //     Opcodes.CONST_STRING
75    //     Opcodes.CONST_CLASS
76    //     Opcodes.MONITOR_ENTER
77    //     Opcodes.MONITOR_EXIT
78    //     Opcodes.CHECK_CAST
79    //     Opcodes.INSTANCE_OF
80    //     Opcodes.ARRAY_LENGTH
81    //     Opcodes.NEW_INSTANCE
82    //     Opcodes.NEW_ARRAY
83    //     Opcodes.FILLED_NEW_ARRAY
84    //     Opcodes.FILL_ARRAY_DATA
85    //     Opcodes.THROW
86    //     Opcodes.GOTO
87    //     Opcodes.PACKED_SWITCH
88    //     Opcodes.SPARSE_SWITCH
89    //     Opcodes.CMPL_FLOAT
90    //     Opcodes.CMPG_FLOAT
91    //     Opcodes.CMPL_DOUBLE
92    //     Opcodes.CMPG_DOUBLE
93    //     Opcodes.CMP_LONG
94    //     Opcodes.IF_EQ
95    //     Opcodes.IF_NE
96    //     Opcodes.IF_LT
97    //     Opcodes.IF_GE
98    //     Opcodes.IF_GT
99    //     Opcodes.IF_LE
100    //     Opcodes.IF_EQZ
101    //     Opcodes.IF_NEZ
102    //     Opcodes.IF_LTZ
103    //     Opcodes.IF_GEZ
104    //     Opcodes.IF_GTZ
105    //     Opcodes.IF_LEZ
106    //     Opcodes.AGET
107    //     Opcodes.AGET_WIDE
108    //     Opcodes.AGET_OBJECT
109    //     Opcodes.AGET_BOOLEAN
110    //     Opcodes.AGET_BYTE
111    //     Opcodes.AGET_CHAR
112    //     Opcodes.AGET_SHORT
113    //     Opcodes.APUT
114    //     Opcodes.APUT_WIDE
115    //     Opcodes.APUT_OBJECT
116    //     Opcodes.APUT_BOOLEAN
117    //     Opcodes.APUT_BYTE
118    //     Opcodes.APUT_CHAR
119    //     Opcodes.APUT_SHORT
120    //     Opcodes.IGET
121    //     Opcodes.IGET_WIDE
122    //     Opcodes.IGET_OBJECT
123    //     Opcodes.IGET_BOOLEAN
124    //     Opcodes.IGET_BYTE
125    //     Opcodes.IGET_CHAR
126    //     Opcodes.IGET_SHORT
127    //     Opcodes.IPUT
128    //     Opcodes.IPUT_WIDE
129    //     Opcodes.IPUT_OBJECT
130    //     Opcodes.IPUT_BOOLEAN
131    //     Opcodes.IPUT_BYTE
132    //     Opcodes.IPUT_CHAR
133    //     Opcodes.IPUT_SHORT
134    //     Opcodes.SGET
135    //     Opcodes.SGET_WIDE
136    //     Opcodes.SGET_OBJECT
137    //     Opcodes.SGET_BOOLEAN
138    //     Opcodes.SGET_BYTE
139    //     Opcodes.SGET_CHAR
140    //     Opcodes.SGET_SHORT
141    //     Opcodes.SPUT
142    //     Opcodes.SPUT_WIDE
143    //     Opcodes.SPUT_OBJECT
144    //     Opcodes.SPUT_BOOLEAN
145    //     Opcodes.SPUT_BYTE
146    //     Opcodes.SPUT_CHAR
147    //     Opcodes.SPUT_SHORT
148    //     Opcodes.INVOKE_VIRTUAL
149    //     Opcodes.INVOKE_SUPER
150    //     Opcodes.INVOKE_DIRECT
151    //     Opcodes.INVOKE_STATIC
152    //     Opcodes.INVOKE_INTERFACE
153    //     Opcodes.NEG_INT
154    //     Opcodes.NOT_INT
155    //     Opcodes.NEG_LONG
156    //     Opcodes.NOT_LONG
157    //     Opcodes.NEG_FLOAT
158    //     Opcodes.NEG_DOUBLE
159    //     Opcodes.INT_TO_LONG
160    //     Opcodes.INT_TO_FLOAT
161    //     Opcodes.INT_TO_DOUBLE
162    //     Opcodes.LONG_TO_INT
163    //     Opcodes.LONG_TO_FLOAT
164    //     Opcodes.LONG_TO_DOUBLE
165    //     Opcodes.FLOAT_TO_INT
166    //     Opcodes.FLOAT_TO_LONG
167    //     Opcodes.FLOAT_TO_DOUBLE
168    //     Opcodes.DOUBLE_TO_INT
169    //     Opcodes.DOUBLE_TO_LONG
170    //     Opcodes.DOUBLE_TO_FLOAT
171    //     Opcodes.INT_TO_BYTE
172    //     Opcodes.INT_TO_CHAR
173    //     Opcodes.INT_TO_SHORT
174    //     Opcodes.ADD_INT_2ADDR
175    //     Opcodes.SUB_INT_2ADDR
176    //     Opcodes.MUL_INT_2ADDR
177    //     Opcodes.DIV_INT_2ADDR
178    //     Opcodes.REM_INT_2ADDR
179    //     Opcodes.AND_INT_2ADDR
180    //     Opcodes.OR_INT_2ADDR
181    //     Opcodes.XOR_INT_2ADDR
182    //     Opcodes.SHL_INT_2ADDR
183    //     Opcodes.SHR_INT_2ADDR
184    //     Opcodes.USHR_INT_2ADDR
185    //     Opcodes.ADD_LONG_2ADDR
186    //     Opcodes.SUB_LONG_2ADDR
187    //     Opcodes.MUL_LONG_2ADDR
188    //     Opcodes.DIV_LONG_2ADDR
189    //     Opcodes.REM_LONG_2ADDR
190    //     Opcodes.AND_LONG_2ADDR
191    //     Opcodes.OR_LONG_2ADDR
192    //     Opcodes.XOR_LONG_2ADDR
193    //     Opcodes.SHL_LONG_2ADDR
194    //     Opcodes.SHR_LONG_2ADDR
195    //     Opcodes.USHR_LONG_2ADDR
196    //     Opcodes.ADD_FLOAT_2ADDR
197    //     Opcodes.SUB_FLOAT_2ADDR
198    //     Opcodes.MUL_FLOAT_2ADDR
199    //     Opcodes.DIV_FLOAT_2ADDR
200    //     Opcodes.REM_FLOAT_2ADDR
201    //     Opcodes.ADD_DOUBLE_2ADDR
202    //     Opcodes.SUB_DOUBLE_2ADDR
203    //     Opcodes.MUL_DOUBLE_2ADDR
204    //     Opcodes.DIV_DOUBLE_2ADDR
205    //     Opcodes.REM_DOUBLE_2ADDR
206    //     Opcodes.ADD_INT_LIT8
207    //     Opcodes.RSUB_INT_LIT8
208    //     Opcodes.MUL_INT_LIT8
209    //     Opcodes.DIV_INT_LIT8
210    //     Opcodes.REM_INT_LIT8
211    //     Opcodes.AND_INT_LIT8
212    //     Opcodes.OR_INT_LIT8
213    //     Opcodes.XOR_INT_LIT8
214    //     Opcodes.SHL_INT_LIT8
215    //     Opcodes.SHR_INT_LIT8
216    //     Opcodes.USHR_INT_LIT8
217    // END(first-opcodes)
218
219    static {
220        /*
221         * Note: The choices made here are to pick the optimistically
222         * smallest Dalvik opcode, and leave it to later processing to
223         * pessimize. See the automatically-generated comment above
224         * for reference.
225         */
226        MAP = new HashMap<Rop, Dop>(400);
227        MAP.put(Rops.NOP,               Dops.NOP);
228        MAP.put(Rops.MOVE_INT,          Dops.MOVE);
229        MAP.put(Rops.MOVE_LONG,         Dops.MOVE_WIDE);
230        MAP.put(Rops.MOVE_FLOAT,        Dops.MOVE);
231        MAP.put(Rops.MOVE_DOUBLE,       Dops.MOVE_WIDE);
232        MAP.put(Rops.MOVE_OBJECT,       Dops.MOVE_OBJECT);
233        MAP.put(Rops.MOVE_PARAM_INT,    Dops.MOVE);
234        MAP.put(Rops.MOVE_PARAM_LONG,   Dops.MOVE_WIDE);
235        MAP.put(Rops.MOVE_PARAM_FLOAT,  Dops.MOVE);
236        MAP.put(Rops.MOVE_PARAM_DOUBLE, Dops.MOVE_WIDE);
237        MAP.put(Rops.MOVE_PARAM_OBJECT, Dops.MOVE_OBJECT);
238
239        /*
240         * Note: No entry for MOVE_EXCEPTION, since it varies by
241         * exception type. (That is, there is no unique instance to
242         * add to the map.)
243         */
244
245        MAP.put(Rops.CONST_INT,         Dops.CONST_4);
246        MAP.put(Rops.CONST_LONG,        Dops.CONST_WIDE_16);
247        MAP.put(Rops.CONST_FLOAT,       Dops.CONST_4);
248        MAP.put(Rops.CONST_DOUBLE,      Dops.CONST_WIDE_16);
249
250        /*
251         * Note: No entry for CONST_OBJECT, since it needs to turn
252         * into either CONST_STRING or CONST_CLASS.
253         */
254
255        /*
256         * TODO: I think the only case of this is for null, and
257         * const/4 should cover that.
258         */
259        MAP.put(Rops.CONST_OBJECT_NOTHROW, Dops.CONST_4);
260
261        MAP.put(Rops.GOTO,                 Dops.GOTO);
262        MAP.put(Rops.IF_EQZ_INT,           Dops.IF_EQZ);
263        MAP.put(Rops.IF_NEZ_INT,           Dops.IF_NEZ);
264        MAP.put(Rops.IF_LTZ_INT,           Dops.IF_LTZ);
265        MAP.put(Rops.IF_GEZ_INT,           Dops.IF_GEZ);
266        MAP.put(Rops.IF_LEZ_INT,           Dops.IF_LEZ);
267        MAP.put(Rops.IF_GTZ_INT,           Dops.IF_GTZ);
268        MAP.put(Rops.IF_EQZ_OBJECT,        Dops.IF_EQZ);
269        MAP.put(Rops.IF_NEZ_OBJECT,        Dops.IF_NEZ);
270        MAP.put(Rops.IF_EQ_INT,            Dops.IF_EQ);
271        MAP.put(Rops.IF_NE_INT,            Dops.IF_NE);
272        MAP.put(Rops.IF_LT_INT,            Dops.IF_LT);
273        MAP.put(Rops.IF_GE_INT,            Dops.IF_GE);
274        MAP.put(Rops.IF_LE_INT,            Dops.IF_LE);
275        MAP.put(Rops.IF_GT_INT,            Dops.IF_GT);
276        MAP.put(Rops.IF_EQ_OBJECT,         Dops.IF_EQ);
277        MAP.put(Rops.IF_NE_OBJECT,         Dops.IF_NE);
278        MAP.put(Rops.SWITCH,               Dops.SPARSE_SWITCH);
279        MAP.put(Rops.ADD_INT,              Dops.ADD_INT_2ADDR);
280        MAP.put(Rops.ADD_LONG,             Dops.ADD_LONG_2ADDR);
281        MAP.put(Rops.ADD_FLOAT,            Dops.ADD_FLOAT_2ADDR);
282        MAP.put(Rops.ADD_DOUBLE,           Dops.ADD_DOUBLE_2ADDR);
283        MAP.put(Rops.SUB_INT,              Dops.SUB_INT_2ADDR);
284        MAP.put(Rops.SUB_LONG,             Dops.SUB_LONG_2ADDR);
285        MAP.put(Rops.SUB_FLOAT,            Dops.SUB_FLOAT_2ADDR);
286        MAP.put(Rops.SUB_DOUBLE,           Dops.SUB_DOUBLE_2ADDR);
287        MAP.put(Rops.MUL_INT,              Dops.MUL_INT_2ADDR);
288        MAP.put(Rops.MUL_LONG,             Dops.MUL_LONG_2ADDR);
289        MAP.put(Rops.MUL_FLOAT,            Dops.MUL_FLOAT_2ADDR);
290        MAP.put(Rops.MUL_DOUBLE,           Dops.MUL_DOUBLE_2ADDR);
291        MAP.put(Rops.DIV_INT,              Dops.DIV_INT_2ADDR);
292        MAP.put(Rops.DIV_LONG,             Dops.DIV_LONG_2ADDR);
293        MAP.put(Rops.DIV_FLOAT,            Dops.DIV_FLOAT_2ADDR);
294        MAP.put(Rops.DIV_DOUBLE,           Dops.DIV_DOUBLE_2ADDR);
295        MAP.put(Rops.REM_INT,              Dops.REM_INT_2ADDR);
296        MAP.put(Rops.REM_LONG,             Dops.REM_LONG_2ADDR);
297        MAP.put(Rops.REM_FLOAT,            Dops.REM_FLOAT_2ADDR);
298        MAP.put(Rops.REM_DOUBLE,           Dops.REM_DOUBLE_2ADDR);
299        MAP.put(Rops.NEG_INT,              Dops.NEG_INT);
300        MAP.put(Rops.NEG_LONG,             Dops.NEG_LONG);
301        MAP.put(Rops.NEG_FLOAT,            Dops.NEG_FLOAT);
302        MAP.put(Rops.NEG_DOUBLE,           Dops.NEG_DOUBLE);
303        MAP.put(Rops.AND_INT,              Dops.AND_INT_2ADDR);
304        MAP.put(Rops.AND_LONG,             Dops.AND_LONG_2ADDR);
305        MAP.put(Rops.OR_INT,               Dops.OR_INT_2ADDR);
306        MAP.put(Rops.OR_LONG,              Dops.OR_LONG_2ADDR);
307        MAP.put(Rops.XOR_INT,              Dops.XOR_INT_2ADDR);
308        MAP.put(Rops.XOR_LONG,             Dops.XOR_LONG_2ADDR);
309        MAP.put(Rops.SHL_INT,              Dops.SHL_INT_2ADDR);
310        MAP.put(Rops.SHL_LONG,             Dops.SHL_LONG_2ADDR);
311        MAP.put(Rops.SHR_INT,              Dops.SHR_INT_2ADDR);
312        MAP.put(Rops.SHR_LONG,             Dops.SHR_LONG_2ADDR);
313        MAP.put(Rops.USHR_INT,             Dops.USHR_INT_2ADDR);
314        MAP.put(Rops.USHR_LONG,            Dops.USHR_LONG_2ADDR);
315        MAP.put(Rops.NOT_INT,              Dops.NOT_INT);
316        MAP.put(Rops.NOT_LONG,             Dops.NOT_LONG);
317
318        MAP.put(Rops.ADD_CONST_INT,        Dops.ADD_INT_LIT8);
319        // Note: No dalvik ops for other types of add_const.
320
321        MAP.put(Rops.SUB_CONST_INT,        Dops.RSUB_INT_LIT8);
322        /*
323         * Note: No dalvik ops for any type of sub_const; instead
324         * there's a *reverse* sub (constant - reg) for ints only.
325         */
326
327        MAP.put(Rops.MUL_CONST_INT,        Dops.MUL_INT_LIT8);
328        // Note: No dalvik ops for other types of mul_const.
329
330        MAP.put(Rops.DIV_CONST_INT,        Dops.DIV_INT_LIT8);
331        // Note: No dalvik ops for other types of div_const.
332
333        MAP.put(Rops.REM_CONST_INT,        Dops.REM_INT_LIT8);
334        // Note: No dalvik ops for other types of rem_const.
335
336        MAP.put(Rops.AND_CONST_INT,        Dops.AND_INT_LIT8);
337        // Note: No dalvik op for and_const_long.
338
339        MAP.put(Rops.OR_CONST_INT,         Dops.OR_INT_LIT8);
340        // Note: No dalvik op for or_const_long.
341
342        MAP.put(Rops.XOR_CONST_INT,        Dops.XOR_INT_LIT8);
343        // Note: No dalvik op for xor_const_long.
344
345        MAP.put(Rops.SHL_CONST_INT,        Dops.SHL_INT_LIT8);
346        // Note: No dalvik op for shl_const_long.
347
348        MAP.put(Rops.SHR_CONST_INT,        Dops.SHR_INT_LIT8);
349        // Note: No dalvik op for shr_const_long.
350
351        MAP.put(Rops.USHR_CONST_INT,       Dops.USHR_INT_LIT8);
352        // Note: No dalvik op for shr_const_long.
353
354        MAP.put(Rops.CMPL_LONG,            Dops.CMP_LONG);
355        MAP.put(Rops.CMPL_FLOAT,           Dops.CMPL_FLOAT);
356        MAP.put(Rops.CMPL_DOUBLE,          Dops.CMPL_DOUBLE);
357        MAP.put(Rops.CMPG_FLOAT,           Dops.CMPG_FLOAT);
358        MAP.put(Rops.CMPG_DOUBLE,          Dops.CMPG_DOUBLE);
359        MAP.put(Rops.CONV_L2I,             Dops.LONG_TO_INT);
360        MAP.put(Rops.CONV_F2I,             Dops.FLOAT_TO_INT);
361        MAP.put(Rops.CONV_D2I,             Dops.DOUBLE_TO_INT);
362        MAP.put(Rops.CONV_I2L,             Dops.INT_TO_LONG);
363        MAP.put(Rops.CONV_F2L,             Dops.FLOAT_TO_LONG);
364        MAP.put(Rops.CONV_D2L,             Dops.DOUBLE_TO_LONG);
365        MAP.put(Rops.CONV_I2F,             Dops.INT_TO_FLOAT);
366        MAP.put(Rops.CONV_L2F,             Dops.LONG_TO_FLOAT);
367        MAP.put(Rops.CONV_D2F,             Dops.DOUBLE_TO_FLOAT);
368        MAP.put(Rops.CONV_I2D,             Dops.INT_TO_DOUBLE);
369        MAP.put(Rops.CONV_L2D,             Dops.LONG_TO_DOUBLE);
370        MAP.put(Rops.CONV_F2D,             Dops.FLOAT_TO_DOUBLE);
371        MAP.put(Rops.TO_BYTE,              Dops.INT_TO_BYTE);
372        MAP.put(Rops.TO_CHAR,              Dops.INT_TO_CHAR);
373        MAP.put(Rops.TO_SHORT,             Dops.INT_TO_SHORT);
374        MAP.put(Rops.RETURN_VOID,          Dops.RETURN_VOID);
375        MAP.put(Rops.RETURN_INT,           Dops.RETURN);
376        MAP.put(Rops.RETURN_LONG,          Dops.RETURN_WIDE);
377        MAP.put(Rops.RETURN_FLOAT,         Dops.RETURN);
378        MAP.put(Rops.RETURN_DOUBLE,        Dops.RETURN_WIDE);
379        MAP.put(Rops.RETURN_OBJECT,        Dops.RETURN_OBJECT);
380        MAP.put(Rops.ARRAY_LENGTH,         Dops.ARRAY_LENGTH);
381        MAP.put(Rops.THROW,                Dops.THROW);
382        MAP.put(Rops.MONITOR_ENTER,        Dops.MONITOR_ENTER);
383        MAP.put(Rops.MONITOR_EXIT,         Dops.MONITOR_EXIT);
384        MAP.put(Rops.AGET_INT,             Dops.AGET);
385        MAP.put(Rops.AGET_LONG,            Dops.AGET_WIDE);
386        MAP.put(Rops.AGET_FLOAT,           Dops.AGET);
387        MAP.put(Rops.AGET_DOUBLE,          Dops.AGET_WIDE);
388        MAP.put(Rops.AGET_OBJECT,          Dops.AGET_OBJECT);
389        MAP.put(Rops.AGET_BOOLEAN,         Dops.AGET_BOOLEAN);
390        MAP.put(Rops.AGET_BYTE,            Dops.AGET_BYTE);
391        MAP.put(Rops.AGET_CHAR,            Dops.AGET_CHAR);
392        MAP.put(Rops.AGET_SHORT,           Dops.AGET_SHORT);
393        MAP.put(Rops.APUT_INT,             Dops.APUT);
394        MAP.put(Rops.APUT_LONG,            Dops.APUT_WIDE);
395        MAP.put(Rops.APUT_FLOAT,           Dops.APUT);
396        MAP.put(Rops.APUT_DOUBLE,          Dops.APUT_WIDE);
397        MAP.put(Rops.APUT_OBJECT,          Dops.APUT_OBJECT);
398        MAP.put(Rops.APUT_BOOLEAN,         Dops.APUT_BOOLEAN);
399        MAP.put(Rops.APUT_BYTE,            Dops.APUT_BYTE);
400        MAP.put(Rops.APUT_CHAR,            Dops.APUT_CHAR);
401        MAP.put(Rops.APUT_SHORT,           Dops.APUT_SHORT);
402        MAP.put(Rops.NEW_INSTANCE,         Dops.NEW_INSTANCE);
403        MAP.put(Rops.CHECK_CAST,           Dops.CHECK_CAST);
404        MAP.put(Rops.INSTANCE_OF,          Dops.INSTANCE_OF);
405
406        MAP.put(Rops.GET_FIELD_LONG,       Dops.IGET_WIDE);
407        MAP.put(Rops.GET_FIELD_FLOAT,      Dops.IGET);
408        MAP.put(Rops.GET_FIELD_DOUBLE,     Dops.IGET_WIDE);
409        MAP.put(Rops.GET_FIELD_OBJECT,     Dops.IGET_OBJECT);
410        /*
411         * Note: No map entries for get_field_* for non-long integral types,
412         * since they need to be handled specially (see dopFor() below).
413         */
414
415        MAP.put(Rops.GET_STATIC_LONG,      Dops.SGET_WIDE);
416        MAP.put(Rops.GET_STATIC_FLOAT,     Dops.SGET);
417        MAP.put(Rops.GET_STATIC_DOUBLE,    Dops.SGET_WIDE);
418        MAP.put(Rops.GET_STATIC_OBJECT,    Dops.SGET_OBJECT);
419        /*
420         * Note: No map entries for get_static* for non-long integral types,
421         * since they need to be handled specially (see dopFor() below).
422         */
423
424        MAP.put(Rops.PUT_FIELD_LONG,       Dops.IPUT_WIDE);
425        MAP.put(Rops.PUT_FIELD_FLOAT,      Dops.IPUT);
426        MAP.put(Rops.PUT_FIELD_DOUBLE,     Dops.IPUT_WIDE);
427        MAP.put(Rops.PUT_FIELD_OBJECT,     Dops.IPUT_OBJECT);
428        /*
429         * Note: No map entries for put_field_* for non-long integral types,
430         * since they need to be handled specially (see dopFor() below).
431         */
432
433        MAP.put(Rops.PUT_STATIC_LONG,      Dops.SPUT_WIDE);
434        MAP.put(Rops.PUT_STATIC_FLOAT,     Dops.SPUT);
435        MAP.put(Rops.PUT_STATIC_DOUBLE,    Dops.SPUT_WIDE);
436        MAP.put(Rops.PUT_STATIC_OBJECT,    Dops.SPUT_OBJECT);
437        /*
438         * Note: No map entries for put_static* for non-long integral types,
439         * since they need to be handled specially (see dopFor() below).
440         */
441
442        /*
443         * Note: No map entries for invoke*, new_array, and
444         * filled_new_array, since they need to be handled specially
445         * (see dopFor() below).
446         */
447    }
448
449    /**
450     * Returns the dalvik opcode appropriate for the given register-based
451     * instruction.
452     *
453     * @param insn {@code non-null;} the original instruction
454     * @return the corresponding dalvik opcode; one of the constants in
455     * {@link Dops}
456     */
457    public static Dop dopFor(Insn insn) {
458        Rop rop = insn.getOpcode();
459
460        /*
461         * First, just try looking up the rop in the MAP of easy
462         * cases.
463         */
464        Dop result = MAP.get(rop);
465        if (result != null) {
466            return result;
467        }
468
469        /*
470         * There was no easy case for the rop, so look up the opcode, and
471         * do something special for each:
472         *
473         * The move_exception, new_array, filled_new_array, and
474         * invoke* opcodes won't be found in MAP, since they'll each
475         * have different source and/or result register types / lists.
476         *
477         * The get* and put* opcodes for (non-long) integral types
478         * aren't in the map, since the type signatures aren't
479         * sufficient to distinguish between the types (the salient
480         * source or result will always be just "int").
481         *
482         * And const instruction need to distinguish between strings and
483         * classes.
484         */
485
486        switch (rop.getOpcode()) {
487            case RegOps.MOVE_EXCEPTION:   return Dops.MOVE_EXCEPTION;
488            case RegOps.INVOKE_STATIC:    return Dops.INVOKE_STATIC;
489            case RegOps.INVOKE_VIRTUAL:   return Dops.INVOKE_VIRTUAL;
490            case RegOps.INVOKE_SUPER:     return Dops.INVOKE_SUPER;
491            case RegOps.INVOKE_DIRECT:    return Dops.INVOKE_DIRECT;
492            case RegOps.INVOKE_INTERFACE: return Dops.INVOKE_INTERFACE;
493            case RegOps.NEW_ARRAY:        return Dops.NEW_ARRAY;
494            case RegOps.FILLED_NEW_ARRAY: return Dops.FILLED_NEW_ARRAY;
495            case RegOps.FILL_ARRAY_DATA:  return Dops.FILL_ARRAY_DATA;
496            case RegOps.MOVE_RESULT: {
497                RegisterSpec resultReg = insn.getResult();
498
499                if (resultReg == null) {
500                    return Dops.NOP;
501                } else {
502                    switch (resultReg.getBasicType()) {
503                        case Type.BT_INT:
504                        case Type.BT_FLOAT:
505                        case Type.BT_BOOLEAN:
506                        case Type.BT_BYTE:
507                        case Type.BT_CHAR:
508                        case Type.BT_SHORT:
509                            return Dops.MOVE_RESULT;
510                        case Type.BT_LONG:
511                        case Type.BT_DOUBLE:
512                            return Dops.MOVE_RESULT_WIDE;
513                        case Type.BT_OBJECT:
514                            return Dops.MOVE_RESULT_OBJECT;
515                        default: {
516                            throw new RuntimeException("Unexpected basic type");
517                        }
518                    }
519                }
520            }
521
522            case RegOps.GET_FIELD: {
523                CstFieldRef ref =
524                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
525                int basicType = ref.getBasicType();
526                switch (basicType) {
527                    case Type.BT_BOOLEAN: return Dops.IGET_BOOLEAN;
528                    case Type.BT_BYTE:    return Dops.IGET_BYTE;
529                    case Type.BT_CHAR:    return Dops.IGET_CHAR;
530                    case Type.BT_SHORT:   return Dops.IGET_SHORT;
531                    case Type.BT_INT:     return Dops.IGET;
532                }
533                break;
534            }
535            case RegOps.PUT_FIELD: {
536                CstFieldRef ref =
537                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
538                int basicType = ref.getBasicType();
539                switch (basicType) {
540                    case Type.BT_BOOLEAN: return Dops.IPUT_BOOLEAN;
541                    case Type.BT_BYTE:    return Dops.IPUT_BYTE;
542                    case Type.BT_CHAR:    return Dops.IPUT_CHAR;
543                    case Type.BT_SHORT:   return Dops.IPUT_SHORT;
544                    case Type.BT_INT:     return Dops.IPUT;
545                }
546                break;
547            }
548            case RegOps.GET_STATIC: {
549                CstFieldRef ref =
550                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
551                int basicType = ref.getBasicType();
552                switch (basicType) {
553                    case Type.BT_BOOLEAN: return Dops.SGET_BOOLEAN;
554                    case Type.BT_BYTE:    return Dops.SGET_BYTE;
555                    case Type.BT_CHAR:    return Dops.SGET_CHAR;
556                    case Type.BT_SHORT:   return Dops.SGET_SHORT;
557                    case Type.BT_INT:     return Dops.SGET;
558                }
559                break;
560            }
561            case RegOps.PUT_STATIC: {
562                CstFieldRef ref =
563                    (CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
564                int basicType = ref.getBasicType();
565                switch (basicType) {
566                    case Type.BT_BOOLEAN: return Dops.SPUT_BOOLEAN;
567                    case Type.BT_BYTE:    return Dops.SPUT_BYTE;
568                    case Type.BT_CHAR:    return Dops.SPUT_CHAR;
569                    case Type.BT_SHORT:   return Dops.SPUT_SHORT;
570                    case Type.BT_INT:     return Dops.SPUT;
571                }
572                break;
573            }
574            case RegOps.CONST: {
575                Constant cst = ((ThrowingCstInsn) insn).getConstant();
576                if (cst instanceof CstType) {
577                    return Dops.CONST_CLASS;
578                } else if (cst instanceof CstString) {
579                    return Dops.CONST_STRING;
580                }
581                break;
582            }
583        }
584
585        throw new RuntimeException("unknown rop: " + rop);
586    }
587}
588