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 
17 package com.android.dx.rop.code;
18 
19 import 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}
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  */
31 public 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      */
RegOps()302     private RegOps() {
303         // This space intentionally left blank.
304     }
305 
306     /**
307      * Gets the name of the given opcode.
308      *
309      * @param opcode the opcode
310      * @return {@code non-null;} its name
311      */
opName(int opcode)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      */
flippedIfOpcode(final int opcode)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