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 < y) goto <i>label</i></code> */ 68 public static final int IF_LT = 9; 69 70 /** <code>x,y: int :: if (x >= y) goto <i>label</i></code> */ 71 public static final int IF_GE = 10; 72 73 /** <code>x,y: int :: if (x <= y) goto <i>label</i></code> */ 74 public static final int IF_LE = 11; 75 76 /** <code>x,y: int :: if (x > 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 & 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 << 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 >> 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 * >>> 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 > 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 < 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 << 24) >> 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 & 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 << 16) >> 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 >= 0, <= 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