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.rop.code;
18
19import com.android.dexgen.util.Hex;
20
21/**
22 * All the register-based opcodes, and related utilities.
23 *
24 * <p><b>Note:</b> Opcode descriptions use a rough pseudocode. {@code r}
25 * is the result register, {@code x} is the first argument,
26 * {@code y} is the second argument, and {@code z} is the
27 * third argument. The expression which describes
28 * the operation uses Java-ish syntax but is preceded by type indicators for
29 * each of the values.
30 */
31public final class RegOps {
32    /** {@code nop()} */
33    public static final int NOP = 1;
34
35    /** {@code T: any type; r,x: T :: r = x;} */
36    public static final int MOVE = 2;
37
38    /** {@code T: any type; r,param(x): T :: r = param(x)} */
39    public static final int MOVE_PARAM = 3;
40
41    /**
42     * {@code T: Throwable; r: T :: r = caught_exception}.
43     * <b>Note:</b> This opcode should only ever be used in the
44     * first instruction of a block, and such blocks must be
45     * the start of an exception handler.
46     */
47    public static final int MOVE_EXCEPTION = 4;
48
49    /** {@code T: any type; r, literal: T :: r = literal;} */
50    public static final int CONST = 5;
51
52    /** {@code goto label} */
53    public static final int GOTO = 6;
54
55    /**
56     * {@code T: int or Object; x,y: T :: if (x == y) goto
57     * label}
58     */
59    public static final int IF_EQ = 7;
60
61    /**
62     * {@code T: int or Object; x,y: T :: if (x != y) goto
63     * label}
64     */
65    public static final int IF_NE = 8;
66
67    /** {@code x,y: int :: if (x < y) goto label} */
68    public static final int IF_LT = 9;
69
70    /** {@code x,y: int :: if (x >= y) goto label} */
71    public static final int IF_GE = 10;
72
73    /** {@code x,y: int :: if (x <= y) goto label} */
74    public static final int IF_LE = 11;
75
76    /** {@code x,y: int :: if (x > y) goto label} */
77    public static final int IF_GT = 12;
78
79    /** {@code x: int :: goto table[x]} */
80    public static final int SWITCH = 13;
81
82    /** {@code T: any numeric type; r,x,y: T :: r = x + y} */
83    public static final int ADD = 14;
84
85    /** {@code T: any numeric type; r,x,y: T :: r = x - y} */
86    public static final int SUB = 15;
87
88    /** {@code T: any numeric type; r,x,y: T :: r = x * y} */
89    public static final int MUL = 16;
90
91    /** {@code T: any numeric type; r,x,y: T :: r = x / y} */
92    public static final int DIV = 17;
93
94    /**
95     * {@code T: any numeric type; r,x,y: T :: r = x % y}
96     * (Java-style remainder)
97     */
98    public static final int REM = 18;
99
100    /** {@code T: any numeric type; r,x: T :: r = -x} */
101    public static final int NEG = 19;
102
103    /** {@code T: any integral type; r,x,y: T :: r = x & y} */
104    public static final int AND = 20;
105
106    /** {@code T: any integral type; r,x,y: T :: r = x | y} */
107    public static final int OR = 21;
108
109    /** {@code T: any integral type; r,x,y: T :: r = x ^ y} */
110    public static final int XOR = 22;
111
112    /**
113     * {@code T: any integral type; r,x: T; y: int :: r = x << y}
114     */
115    public static final int SHL = 23;
116
117    /**
118     * {@code T: any integral type; r,x: T; y: int :: r = x >> y}
119     * (signed right-shift)
120     */
121    public static final int SHR = 24;
122
123    /**
124     * {@code T: any integral type; r,x: T; y: int :: r = x >>> y}
125     * (unsigned right-shift)
126     */
127    public static final int USHR = 25;
128
129    /** {@code T: any integral type; r,x: T :: r = ~x} */
130    public static final int NOT = 26;
131
132    /**
133     * {@code T: any numeric type; r: int; x,y: T :: r = (x == y) ? 0
134     * : (x > y) ? 1 : -1} (Java-style "cmpl" where a NaN is
135     * considered "less than" all other values; also used for integral
136     * comparisons)
137     */
138    public static final int CMPL = 27;
139
140    /**
141     * {@code T: any floating point type; r: int; x,y: T :: r = (x == y) ? 0
142     * : (x < y) ? -1 : 1} (Java-style "cmpg" where a NaN is
143     * considered "greater than" all other values)
144     */
145    public static final int CMPG = 28;
146
147    /**
148     * {@code T: any numeric type; U: any numeric type; r: T; x: U ::
149     * r = (T) x} (numeric type conversion between the four
150     * "real" numeric types)
151     */
152    public static final int CONV = 29;
153
154    /**
155     * {@code r,x: int :: r = (x << 24) >> 24} (Java-style
156     * convert int to byte)
157     */
158    public static final int TO_BYTE = 30;
159
160    /**
161     * {@code r,x: int :: r = x & 0xffff} (Java-style convert int to char)
162     */
163    public static final int TO_CHAR = 31;
164
165    /**
166     * {@code r,x: int :: r = (x << 16) >> 16} (Java-style
167     * convert int to short)
168     */
169    public static final int TO_SHORT = 32;
170
171    /** {@code T: return type for the method; x: T; return x} */
172    public static final int RETURN = 33;
173
174    /** {@code T: any type; r: int; x: T[]; :: r = x.length} */
175    public static final int ARRAY_LENGTH = 34;
176
177    /** {@code x: Throwable :: throw(x)} */
178    public static final int THROW = 35;
179
180    /** {@code x: Object :: monitorenter(x)} */
181    public static final int MONITOR_ENTER = 36;
182
183    /** {@code x: Object :: monitorexit(x)} */
184    public static final int MONITOR_EXIT = 37;
185
186    /** {@code T: any type; r: T; x: T[]; y: int :: r = x[y]} */
187    public static final int AGET = 38;
188
189    /** {@code T: any type; x: T; y: T[]; z: int :: x[y] = z} */
190    public static final int APUT = 39;
191
192    /**
193     * {@code T: any non-array object type :: r =
194     * alloc(T)} (allocate heap space for an object)
195     */
196    public static final int NEW_INSTANCE = 40;
197
198    /** {@code T: any array type; r: T; x: int :: r = new T[x]} */
199    public static final int NEW_ARRAY = 41;
200
201    /**
202     * {@code T: any array type; r: T; x: int; v0..vx: T :: r = new T[x]
203     * {v0, ..., vx}}
204     */
205    public static final int FILLED_NEW_ARRAY = 42;
206
207    /**
208     * {@code T: any object type; x: Object :: (T) x} (can
209     * throw {@code ClassCastException})
210     */
211    public static final int CHECK_CAST = 43;
212
213    /**
214     * {@code T: any object type; x: Object :: x instanceof T}
215     */
216    public static final int INSTANCE_OF = 44;
217
218    /**
219     * {@code T: any type; r: T; x: Object; f: instance field spec of
220     * type T :: r = x.f}
221     */
222    public static final int GET_FIELD = 45;
223
224    /**
225     * {@code T: any type; r: T; f: static field spec of type T :: r =
226     * f}
227     */
228    public static final int GET_STATIC = 46;
229
230    /**
231     * {@code T: any type; x: T; y: Object; f: instance field spec of type
232     * T :: y.f = x}
233     */
234    public static final int PUT_FIELD = 47;
235
236    /**
237     * {@code T: any type; f: static field spec of type T; x: T :: f = x}
238     */
239    public static final int PUT_STATIC = 48;
240
241    /**
242     * {@code Tr, T0, T1...: any types; r: Tr; m: static method spec;
243     * y0: T0; y1: T1 ... :: r = m(y0, y1, ...)} (call static
244     * method)
245     */
246    public static final int INVOKE_STATIC = 49;
247
248    /**
249     * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
250     * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call normal
251     * virtual method)
252     */
253    public static final int INVOKE_VIRTUAL = 50;
254
255    /**
256     * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
257     * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call
258     * superclass virtual method)
259     */
260    public static final int INVOKE_SUPER = 51;
261
262    /**
263     * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: instance method
264     * spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1, ...)} (call
265     * direct/special method)
266     */
267    public static final int INVOKE_DIRECT = 52;
268
269    /**
270     * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: interface
271     * (instance) method spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1,
272     * ...)} (call interface method)
273     */
274    public static final int INVOKE_INTERFACE = 53;
275
276    /**
277     * {@code T0: any type; name: local variable name  :: mark(name,T0)}
278     * (mark beginning or end of local variable name)
279     */
280    public static final int MARK_LOCAL = 54;
281
282    /**
283     * {@code T: Any type; r: T :: r = return_type}.
284     * <b>Note:</b> This opcode should only ever be used in the
285     * first instruction of a block following an invoke-*.
286     */
287    public static final int MOVE_RESULT = 55;
288
289    /**
290     * {@code T: Any type; r: T :: r = return_type}.
291     * <b>Note:</b> This opcode should only ever be used in the
292     * first instruction of a block following a non-invoke throwing insn
293     */
294    public static final int MOVE_RESULT_PSEUDO = 56;
295
296    /** {@code T: Any primitive type; v0..vx: T :: {v0, ..., vx}} */
297    public static final int FILL_ARRAY_DATA = 57;
298
299    /**
300     * This class is uninstantiable.
301     */
302    private RegOps() {
303        // This space intentionally left blank.
304    }
305
306    /**
307     * Gets the name of the given opcode.
308     *
309     * @param opcode {@code >= 0, <= 255;} the opcode
310     * @return {@code non-null;} its name
311     */
312    public static String opName(int opcode) {
313        switch (opcode) {
314            case NOP: return "nop";
315            case MOVE: return "move";
316            case MOVE_PARAM: return "move-param";
317            case MOVE_EXCEPTION: return "move-exception";
318            case CONST: return "const";
319            case GOTO: return "goto";
320            case IF_EQ: return "if-eq";
321            case IF_NE: return "if-ne";
322            case IF_LT: return "if-lt";
323            case IF_GE: return "if-ge";
324            case IF_LE: return "if-le";
325            case IF_GT: return "if-gt";
326            case SWITCH: return "switch";
327            case ADD: return "add";
328            case SUB: return "sub";
329            case MUL: return "mul";
330            case DIV: return "div";
331            case REM: return "rem";
332            case NEG: return "neg";
333            case AND: return "and";
334            case OR: return "or";
335            case XOR: return "xor";
336            case SHL: return "shl";
337            case SHR: return "shr";
338            case USHR: return "ushr";
339            case NOT: return "not";
340            case CMPL: return "cmpl";
341            case CMPG: return "cmpg";
342            case CONV: return "conv";
343            case TO_BYTE: return "to-byte";
344            case TO_CHAR: return "to-char";
345            case TO_SHORT: return "to-short";
346            case RETURN: return "return";
347            case ARRAY_LENGTH: return "array-length";
348            case THROW: return "throw";
349            case MONITOR_ENTER: return "monitor-enter";
350            case MONITOR_EXIT: return "monitor-exit";
351            case AGET: return "aget";
352            case APUT: return "aput";
353            case NEW_INSTANCE: return "new-instance";
354            case NEW_ARRAY: return "new-array";
355            case FILLED_NEW_ARRAY: return "filled-new-array";
356            case CHECK_CAST: return "check-cast";
357            case INSTANCE_OF: return "instance-of";
358            case GET_FIELD: return "get-field";
359            case GET_STATIC: return "get-static";
360            case PUT_FIELD: return "put-field";
361            case PUT_STATIC: return "put-static";
362            case INVOKE_STATIC: return "invoke-static";
363            case INVOKE_VIRTUAL: return "invoke-virtual";
364            case INVOKE_SUPER: return "invoke-super";
365            case INVOKE_DIRECT: return "invoke-direct";
366            case INVOKE_INTERFACE: return "invoke-interface";
367            case MOVE_RESULT: return "move-result";
368            case MOVE_RESULT_PSEUDO: return "move-result-pseudo";
369            case FILL_ARRAY_DATA: return "fill-array-data";
370        }
371
372        return "unknown-" + Hex.u1(opcode);
373    }
374
375    /**
376     * Given an IF_* RegOp, returns the right-to-left flipped version. For
377     * example, IF_GT becomes IF_LT.
378     *
379     * @param opcode An IF_* RegOp
380     * @return flipped IF Regop
381     */
382    public static int flippedIfOpcode(final int opcode) {
383        switch (opcode) {
384            case RegOps.IF_EQ:
385            case RegOps.IF_NE:
386                return opcode;
387            case RegOps.IF_LT:
388                return RegOps.IF_GT;
389            case RegOps.IF_GE:
390                return RegOps.IF_LE;
391            case RegOps.IF_LE:
392                return RegOps.IF_GE;
393            case RegOps.IF_GT:
394                return RegOps.IF_LT;
395            default:
396                throw new RuntimeException("Unrecognized IF regop: " + opcode);
397        }
398    }
399}
400