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