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