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.dexgen.dex.code;
18
19import com.android.dexgen.rop.code.Insn;
20import com.android.dexgen.rop.code.RegOps;
21import com.android.dexgen.rop.code.RegisterSpec;
22import com.android.dexgen.rop.code.Rop;
23import com.android.dexgen.rop.code.Rops;
24import com.android.dexgen.rop.code.ThrowingCstInsn;
25import com.android.dexgen.rop.cst.Constant;
26import com.android.dexgen.rop.cst.CstFieldRef;
27import com.android.dexgen.rop.cst.CstString;
28import com.android.dexgen.rop.cst.CstType;
29import com.android.dexgen.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