1 /* forward declarations of goto targets */ 2 GOTO_TARGET_DECL(filledNewArray, bool methodCallRange); 3 GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange); 4 GOTO_TARGET_DECL(invokeSuper, bool methodCallRange); 5 GOTO_TARGET_DECL(invokeInterface, bool methodCallRange); 6 GOTO_TARGET_DECL(invokeDirect, bool methodCallRange); 7 GOTO_TARGET_DECL(invokeStatic, bool methodCallRange); 8 GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange); 9 GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange); 10 GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall, 11 u2 count, u2 regs); 12 GOTO_TARGET_DECL(returnFromMethod); 13 GOTO_TARGET_DECL(exceptionThrown); 14 15 /* 16 * =========================================================================== 17 * 18 * What follows are opcode definitions shared between multiple opcodes with 19 * minor substitutions handled by the C pre-processor. These should probably 20 * use the mterp substitution mechanism instead, with the code here moved 21 * into common fragment files (like the asm "binop.S"), although it's hard 22 * to give up the C preprocessor in favor of the much simpler text subst. 23 * 24 * =========================================================================== 25 */ 26 27 #define HANDLE_NUMCONV(_opcode, _opname, _fromtype, _totype) \ 28 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 29 vdst = INST_A(inst); \ 30 vsrc1 = INST_B(inst); \ 31 ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \ 32 SET_REGISTER##_totype(vdst, \ 33 GET_REGISTER##_fromtype(vsrc1)); \ 34 FINISH(1); 35 36 #define HANDLE_FLOAT_TO_INT(_opcode, _opname, _fromvtype, _fromrtype, \ 37 _tovtype, _tortype) \ 38 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 39 { \ 40 /* spec defines specific handling for +/- inf and NaN values */ \ 41 _fromvtype val; \ 42 _tovtype intMin, intMax, result; \ 43 vdst = INST_A(inst); \ 44 vsrc1 = INST_B(inst); \ 45 ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \ 46 val = GET_REGISTER##_fromrtype(vsrc1); \ 47 intMin = (_tovtype) 1 << (sizeof(_tovtype) * 8 -1); \ 48 intMax = ~intMin; \ 49 result = (_tovtype) val; \ 50 if (val >= intMax) /* +inf */ \ 51 result = intMax; \ 52 else if (val <= intMin) /* -inf */ \ 53 result = intMin; \ 54 else if (val != val) /* NaN */ \ 55 result = 0; \ 56 else \ 57 result = (_tovtype) val; \ 58 SET_REGISTER##_tortype(vdst, result); \ 59 } \ 60 FINISH(1); 61 62 #define HANDLE_INT_TO_SMALL(_opcode, _opname, _type) \ 63 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 64 vdst = INST_A(inst); \ 65 vsrc1 = INST_B(inst); \ 66 ILOGV("|int-to-%s v%d,v%d", (_opname), vdst, vsrc1); \ 67 SET_REGISTER(vdst, (_type) GET_REGISTER(vsrc1)); \ 68 FINISH(1); 69 70 /* NOTE: the comparison result is always a signed 4-byte integer */ 71 #define HANDLE_OP_CMPX(_opcode, _opname, _varType, _type, _nanVal) \ 72 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 73 { \ 74 int result; \ 75 u2 regs; \ 76 _varType val1, val2; \ 77 vdst = INST_AA(inst); \ 78 regs = FETCH(1); \ 79 vsrc1 = regs & 0xff; \ 80 vsrc2 = regs >> 8; \ 81 ILOGV("|cmp%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 82 val1 = GET_REGISTER##_type(vsrc1); \ 83 val2 = GET_REGISTER##_type(vsrc2); \ 84 if (val1 == val2) \ 85 result = 0; \ 86 else if (val1 < val2) \ 87 result = -1; \ 88 else if (val1 > val2) \ 89 result = 1; \ 90 else \ 91 result = (_nanVal); \ 92 ILOGV("+ result=%d\n", result); \ 93 SET_REGISTER(vdst, result); \ 94 } \ 95 FINISH(2); 96 97 #define HANDLE_OP_IF_XX(_opcode, _opname, _cmp) \ 98 HANDLE_OPCODE(_opcode /*vA, vB, +CCCC*/) \ 99 vsrc1 = INST_A(inst); \ 100 vsrc2 = INST_B(inst); \ 101 if ((s4) GET_REGISTER(vsrc1) _cmp (s4) GET_REGISTER(vsrc2)) { \ 102 int branchOffset = (s2)FETCH(1); /* sign-extended */ \ 103 ILOGV("|if-%s v%d,v%d,+0x%04x", (_opname), vsrc1, vsrc2, \ 104 branchOffset); \ 105 ILOGV("> branch taken"); \ 106 if (branchOffset < 0) \ 107 PERIODIC_CHECKS(kInterpEntryInstr, branchOffset); \ 108 FINISH(branchOffset); \ 109 } else { \ 110 ILOGV("|if-%s v%d,v%d,-", (_opname), vsrc1, vsrc2); \ 111 FINISH(2); \ 112 } 113 114 #define HANDLE_OP_IF_XXZ(_opcode, _opname, _cmp) \ 115 HANDLE_OPCODE(_opcode /*vAA, +BBBB*/) \ 116 vsrc1 = INST_AA(inst); \ 117 if ((s4) GET_REGISTER(vsrc1) _cmp 0) { \ 118 int branchOffset = (s2)FETCH(1); /* sign-extended */ \ 119 ILOGV("|if-%s v%d,+0x%04x", (_opname), vsrc1, branchOffset); \ 120 ILOGV("> branch taken"); \ 121 if (branchOffset < 0) \ 122 PERIODIC_CHECKS(kInterpEntryInstr, branchOffset); \ 123 FINISH(branchOffset); \ 124 } else { \ 125 ILOGV("|if-%s v%d,-", (_opname), vsrc1); \ 126 FINISH(2); \ 127 } 128 129 #define HANDLE_UNOP(_opcode, _opname, _pfx, _sfx, _type) \ 130 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 131 vdst = INST_A(inst); \ 132 vsrc1 = INST_B(inst); \ 133 ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \ 134 SET_REGISTER##_type(vdst, _pfx GET_REGISTER##_type(vsrc1) _sfx); \ 135 FINISH(1); 136 137 #define HANDLE_OP_X_INT(_opcode, _opname, _op, _chkdiv) \ 138 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 139 { \ 140 u2 srcRegs; \ 141 vdst = INST_AA(inst); \ 142 srcRegs = FETCH(1); \ 143 vsrc1 = srcRegs & 0xff; \ 144 vsrc2 = srcRegs >> 8; \ 145 ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \ 146 if (_chkdiv != 0) { \ 147 s4 firstVal, secondVal, result; \ 148 firstVal = GET_REGISTER(vsrc1); \ 149 secondVal = GET_REGISTER(vsrc2); \ 150 if (secondVal == 0) { \ 151 EXPORT_PC(); \ 152 dvmThrowException("Ljava/lang/ArithmeticException;", \ 153 "divide by zero"); \ 154 GOTO_exceptionThrown(); \ 155 } \ 156 if ((u4)firstVal == 0x80000000 && secondVal == -1) { \ 157 if (_chkdiv == 1) \ 158 result = firstVal; /* division */ \ 159 else \ 160 result = 0; /* remainder */ \ 161 } else { \ 162 result = firstVal _op secondVal; \ 163 } \ 164 SET_REGISTER(vdst, result); \ 165 } else { \ 166 /* non-div/rem case */ \ 167 SET_REGISTER(vdst, \ 168 (s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2)); \ 169 } \ 170 } \ 171 FINISH(2); 172 173 #define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op) \ 174 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 175 { \ 176 u2 srcRegs; \ 177 vdst = INST_AA(inst); \ 178 srcRegs = FETCH(1); \ 179 vsrc1 = srcRegs & 0xff; \ 180 vsrc2 = srcRegs >> 8; \ 181 ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \ 182 SET_REGISTER(vdst, \ 183 _cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f)); \ 184 } \ 185 FINISH(2); 186 187 #define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv) \ 188 HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/) \ 189 vdst = INST_A(inst); \ 190 vsrc1 = INST_B(inst); \ 191 vsrc2 = FETCH(1); \ 192 ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x", \ 193 (_opname), vdst, vsrc1, vsrc2); \ 194 if (_chkdiv != 0) { \ 195 s4 firstVal, result; \ 196 firstVal = GET_REGISTER(vsrc1); \ 197 if ((s2) vsrc2 == 0) { \ 198 EXPORT_PC(); \ 199 dvmThrowException("Ljava/lang/ArithmeticException;", \ 200 "divide by zero"); \ 201 GOTO_exceptionThrown(); \ 202 } \ 203 if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) { \ 204 /* won't generate /lit16 instr for this; check anyway */ \ 205 if (_chkdiv == 1) \ 206 result = firstVal; /* division */ \ 207 else \ 208 result = 0; /* remainder */ \ 209 } else { \ 210 result = firstVal _op (s2) vsrc2; \ 211 } \ 212 SET_REGISTER(vdst, result); \ 213 } else { \ 214 /* non-div/rem case */ \ 215 SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2); \ 216 } \ 217 FINISH(2); 218 219 #define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv) \ 220 HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \ 221 { \ 222 u2 litInfo; \ 223 vdst = INST_AA(inst); \ 224 litInfo = FETCH(1); \ 225 vsrc1 = litInfo & 0xff; \ 226 vsrc2 = litInfo >> 8; /* constant */ \ 227 ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \ 228 (_opname), vdst, vsrc1, vsrc2); \ 229 if (_chkdiv != 0) { \ 230 s4 firstVal, result; \ 231 firstVal = GET_REGISTER(vsrc1); \ 232 if ((s1) vsrc2 == 0) { \ 233 EXPORT_PC(); \ 234 dvmThrowException("Ljava/lang/ArithmeticException;", \ 235 "divide by zero"); \ 236 GOTO_exceptionThrown(); \ 237 } \ 238 if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) { \ 239 if (_chkdiv == 1) \ 240 result = firstVal; /* division */ \ 241 else \ 242 result = 0; /* remainder */ \ 243 } else { \ 244 result = firstVal _op ((s1) vsrc2); \ 245 } \ 246 SET_REGISTER(vdst, result); \ 247 } else { \ 248 SET_REGISTER(vdst, \ 249 (s4) GET_REGISTER(vsrc1) _op (s1) vsrc2); \ 250 } \ 251 } \ 252 FINISH(2); 253 254 #define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op) \ 255 HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \ 256 { \ 257 u2 litInfo; \ 258 vdst = INST_AA(inst); \ 259 litInfo = FETCH(1); \ 260 vsrc1 = litInfo & 0xff; \ 261 vsrc2 = litInfo >> 8; /* constant */ \ 262 ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \ 263 (_opname), vdst, vsrc1, vsrc2); \ 264 SET_REGISTER(vdst, \ 265 _cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f)); \ 266 } \ 267 FINISH(2); 268 269 #define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv) \ 270 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 271 vdst = INST_A(inst); \ 272 vsrc1 = INST_B(inst); \ 273 ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 274 if (_chkdiv != 0) { \ 275 s4 firstVal, secondVal, result; \ 276 firstVal = GET_REGISTER(vdst); \ 277 secondVal = GET_REGISTER(vsrc1); \ 278 if (secondVal == 0) { \ 279 EXPORT_PC(); \ 280 dvmThrowException("Ljava/lang/ArithmeticException;", \ 281 "divide by zero"); \ 282 GOTO_exceptionThrown(); \ 283 } \ 284 if ((u4)firstVal == 0x80000000 && secondVal == -1) { \ 285 if (_chkdiv == 1) \ 286 result = firstVal; /* division */ \ 287 else \ 288 result = 0; /* remainder */ \ 289 } else { \ 290 result = firstVal _op secondVal; \ 291 } \ 292 SET_REGISTER(vdst, result); \ 293 } else { \ 294 SET_REGISTER(vdst, \ 295 (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1)); \ 296 } \ 297 FINISH(1); 298 299 #define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op) \ 300 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 301 vdst = INST_A(inst); \ 302 vsrc1 = INST_B(inst); \ 303 ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 304 SET_REGISTER(vdst, \ 305 _cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f)); \ 306 FINISH(1); 307 308 #define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv) \ 309 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 310 { \ 311 u2 srcRegs; \ 312 vdst = INST_AA(inst); \ 313 srcRegs = FETCH(1); \ 314 vsrc1 = srcRegs & 0xff; \ 315 vsrc2 = srcRegs >> 8; \ 316 ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 317 if (_chkdiv != 0) { \ 318 s8 firstVal, secondVal, result; \ 319 firstVal = GET_REGISTER_WIDE(vsrc1); \ 320 secondVal = GET_REGISTER_WIDE(vsrc2); \ 321 if (secondVal == 0LL) { \ 322 EXPORT_PC(); \ 323 dvmThrowException("Ljava/lang/ArithmeticException;", \ 324 "divide by zero"); \ 325 GOTO_exceptionThrown(); \ 326 } \ 327 if ((u8)firstVal == 0x8000000000000000ULL && \ 328 secondVal == -1LL) \ 329 { \ 330 if (_chkdiv == 1) \ 331 result = firstVal; /* division */ \ 332 else \ 333 result = 0; /* remainder */ \ 334 } else { \ 335 result = firstVal _op secondVal; \ 336 } \ 337 SET_REGISTER_WIDE(vdst, result); \ 338 } else { \ 339 SET_REGISTER_WIDE(vdst, \ 340 (s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \ 341 } \ 342 } \ 343 FINISH(2); 344 345 #define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op) \ 346 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 347 { \ 348 u2 srcRegs; \ 349 vdst = INST_AA(inst); \ 350 srcRegs = FETCH(1); \ 351 vsrc1 = srcRegs & 0xff; \ 352 vsrc2 = srcRegs >> 8; \ 353 ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 354 SET_REGISTER_WIDE(vdst, \ 355 _cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \ 356 } \ 357 FINISH(2); 358 359 #define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv) \ 360 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 361 vdst = INST_A(inst); \ 362 vsrc1 = INST_B(inst); \ 363 ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 364 if (_chkdiv != 0) { \ 365 s8 firstVal, secondVal, result; \ 366 firstVal = GET_REGISTER_WIDE(vdst); \ 367 secondVal = GET_REGISTER_WIDE(vsrc1); \ 368 if (secondVal == 0LL) { \ 369 EXPORT_PC(); \ 370 dvmThrowException("Ljava/lang/ArithmeticException;", \ 371 "divide by zero"); \ 372 GOTO_exceptionThrown(); \ 373 } \ 374 if ((u8)firstVal == 0x8000000000000000ULL && \ 375 secondVal == -1LL) \ 376 { \ 377 if (_chkdiv == 1) \ 378 result = firstVal; /* division */ \ 379 else \ 380 result = 0; /* remainder */ \ 381 } else { \ 382 result = firstVal _op secondVal; \ 383 } \ 384 SET_REGISTER_WIDE(vdst, result); \ 385 } else { \ 386 SET_REGISTER_WIDE(vdst, \ 387 (s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\ 388 } \ 389 FINISH(1); 390 391 #define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op) \ 392 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 393 vdst = INST_A(inst); \ 394 vsrc1 = INST_B(inst); \ 395 ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 396 SET_REGISTER_WIDE(vdst, \ 397 _cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \ 398 FINISH(1); 399 400 #define HANDLE_OP_X_FLOAT(_opcode, _opname, _op) \ 401 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 402 { \ 403 u2 srcRegs; \ 404 vdst = INST_AA(inst); \ 405 srcRegs = FETCH(1); \ 406 vsrc1 = srcRegs & 0xff; \ 407 vsrc2 = srcRegs >> 8; \ 408 ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 409 SET_REGISTER_FLOAT(vdst, \ 410 GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2)); \ 411 } \ 412 FINISH(2); 413 414 #define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op) \ 415 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 416 { \ 417 u2 srcRegs; \ 418 vdst = INST_AA(inst); \ 419 srcRegs = FETCH(1); \ 420 vsrc1 = srcRegs & 0xff; \ 421 vsrc2 = srcRegs >> 8; \ 422 ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 423 SET_REGISTER_DOUBLE(vdst, \ 424 GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2)); \ 425 } \ 426 FINISH(2); 427 428 #define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op) \ 429 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 430 vdst = INST_A(inst); \ 431 vsrc1 = INST_B(inst); \ 432 ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 433 SET_REGISTER_FLOAT(vdst, \ 434 GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1)); \ 435 FINISH(1); 436 437 #define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op) \ 438 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 439 vdst = INST_A(inst); \ 440 vsrc1 = INST_B(inst); \ 441 ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 442 SET_REGISTER_DOUBLE(vdst, \ 443 GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1)); \ 444 FINISH(1); 445 446 #define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize) \ 447 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 448 { \ 449 ArrayObject* arrayObj; \ 450 u2 arrayInfo; \ 451 EXPORT_PC(); \ 452 vdst = INST_AA(inst); \ 453 arrayInfo = FETCH(1); \ 454 vsrc1 = arrayInfo & 0xff; /* array ptr */ \ 455 vsrc2 = arrayInfo >> 8; /* index */ \ 456 ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 457 arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \ 458 if (!checkForNull((Object*) arrayObj)) \ 459 GOTO_exceptionThrown(); \ 460 if (GET_REGISTER(vsrc2) >= arrayObj->length) { \ 461 LOGV("Invalid array access: %p %d (len=%d)\n", \ 462 arrayObj, vsrc2, arrayObj->length); \ 463 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \ 464 NULL); \ 465 GOTO_exceptionThrown(); \ 466 } \ 467 SET_REGISTER##_regsize(vdst, \ 468 ((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)]); \ 469 ILOGV("+ AGET[%d]=0x%x", GET_REGISTER(vsrc2), GET_REGISTER(vdst)); \ 470 } \ 471 FINISH(2); 472 473 #define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize) \ 474 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 475 { \ 476 ArrayObject* arrayObj; \ 477 u2 arrayInfo; \ 478 EXPORT_PC(); \ 479 vdst = INST_AA(inst); /* AA: source value */ \ 480 arrayInfo = FETCH(1); \ 481 vsrc1 = arrayInfo & 0xff; /* BB: array ptr */ \ 482 vsrc2 = arrayInfo >> 8; /* CC: index */ \ 483 ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 484 arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \ 485 if (!checkForNull((Object*) arrayObj)) \ 486 GOTO_exceptionThrown(); \ 487 if (GET_REGISTER(vsrc2) >= arrayObj->length) { \ 488 dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \ 489 NULL); \ 490 GOTO_exceptionThrown(); \ 491 } \ 492 ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\ 493 ((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)] = \ 494 GET_REGISTER##_regsize(vdst); \ 495 } \ 496 FINISH(2); 497 498 /* 499 * It's possible to get a bad value out of a field with sub-32-bit stores 500 * because the -quick versions always operate on 32 bits. Consider: 501 * short foo = -1 (sets a 32-bit register to 0xffffffff) 502 * iput-quick foo (writes all 32 bits to the field) 503 * short bar = 1 (sets a 32-bit register to 0x00000001) 504 * iput-short (writes the low 16 bits to the field) 505 * iget-quick foo (reads all 32 bits from the field, yielding 0xffff0001) 506 * This can only happen when optimized and non-optimized code has interleaved 507 * access to the same field. This is unlikely but possible. 508 * 509 * The easiest way to fix this is to always read/write 32 bits at a time. On 510 * a device with a 16-bit data bus this is sub-optimal. (The alternative 511 * approach is to have sub-int versions of iget-quick, but now we're wasting 512 * Dalvik instruction space and making it less likely that handler code will 513 * already be in the CPU i-cache.) 514 */ 515 #define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize) \ 516 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 517 { \ 518 InstField* ifield; \ 519 Object* obj; \ 520 EXPORT_PC(); \ 521 vdst = INST_A(inst); \ 522 vsrc1 = INST_B(inst); /* object ptr */ \ 523 ref = FETCH(1); /* field ref */ \ 524 ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \ 525 obj = (Object*) GET_REGISTER(vsrc1); \ 526 if (!checkForNull(obj)) \ 527 GOTO_exceptionThrown(); \ 528 ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \ 529 if (ifield == NULL) { \ 530 ifield = dvmResolveInstField(curMethod->clazz, ref); \ 531 if (ifield == NULL) \ 532 GOTO_exceptionThrown(); \ 533 } \ 534 SET_REGISTER##_regsize(vdst, \ 535 dvmGetField##_ftype(obj, ifield->byteOffset)); \ 536 ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \ 537 (u8) GET_REGISTER##_regsize(vdst)); \ 538 UPDATE_FIELD_GET(&ifield->field); \ 539 } \ 540 FINISH(2); 541 542 #define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize) \ 543 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 544 { \ 545 Object* obj; \ 546 vdst = INST_A(inst); \ 547 vsrc1 = INST_B(inst); /* object ptr */ \ 548 ref = FETCH(1); /* field offset */ \ 549 ILOGV("|iget%s-quick v%d,v%d,field@+%u", \ 550 (_opname), vdst, vsrc1, ref); \ 551 obj = (Object*) GET_REGISTER(vsrc1); \ 552 if (!checkForNullExportPC(obj, fp, pc)) \ 553 GOTO_exceptionThrown(); \ 554 SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref)); \ 555 ILOGV("+ IGETQ %d=0x%08llx", ref, \ 556 (u8) GET_REGISTER##_regsize(vdst)); \ 557 } \ 558 FINISH(2); 559 560 #define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize) \ 561 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 562 { \ 563 InstField* ifield; \ 564 Object* obj; \ 565 EXPORT_PC(); \ 566 vdst = INST_A(inst); \ 567 vsrc1 = INST_B(inst); /* object ptr */ \ 568 ref = FETCH(1); /* field ref */ \ 569 ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \ 570 obj = (Object*) GET_REGISTER(vsrc1); \ 571 if (!checkForNull(obj)) \ 572 GOTO_exceptionThrown(); \ 573 ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \ 574 if (ifield == NULL) { \ 575 ifield = dvmResolveInstField(curMethod->clazz, ref); \ 576 if (ifield == NULL) \ 577 GOTO_exceptionThrown(); \ 578 } \ 579 dvmSetField##_ftype(obj, ifield->byteOffset, \ 580 GET_REGISTER##_regsize(vdst)); \ 581 ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \ 582 (u8) GET_REGISTER##_regsize(vdst)); \ 583 UPDATE_FIELD_PUT(&ifield->field); \ 584 } \ 585 FINISH(2); 586 587 #define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize) \ 588 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 589 { \ 590 Object* obj; \ 591 vdst = INST_A(inst); \ 592 vsrc1 = INST_B(inst); /* object ptr */ \ 593 ref = FETCH(1); /* field offset */ \ 594 ILOGV("|iput%s-quick v%d,v%d,field@0x%04x", \ 595 (_opname), vdst, vsrc1, ref); \ 596 obj = (Object*) GET_REGISTER(vsrc1); \ 597 if (!checkForNullExportPC(obj, fp, pc)) \ 598 GOTO_exceptionThrown(); \ 599 dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst)); \ 600 ILOGV("+ IPUTQ %d=0x%08llx", ref, \ 601 (u8) GET_REGISTER##_regsize(vdst)); \ 602 } \ 603 FINISH(2); 604 605 /* 606 * The JIT needs dvmDexGetResolvedField() to return non-null. 607 * Since we use the portable interpreter to build the trace, the extra 608 * checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp. 609 */ 610 #define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \ 611 HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \ 612 { \ 613 StaticField* sfield; \ 614 vdst = INST_AA(inst); \ 615 ref = FETCH(1); /* field ref */ \ 616 ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref); \ 617 sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \ 618 if (sfield == NULL) { \ 619 EXPORT_PC(); \ 620 sfield = dvmResolveStaticField(curMethod->clazz, ref); \ 621 if (sfield == NULL) \ 622 GOTO_exceptionThrown(); \ 623 if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \ 624 ABORT_JIT_TSELECT(); \ 625 } \ 626 } \ 627 SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \ 628 ILOGV("+ SGET '%s'=0x%08llx", \ 629 sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \ 630 UPDATE_FIELD_GET(&sfield->field); \ 631 } \ 632 FINISH(2); 633 634 #define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize) \ 635 HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \ 636 { \ 637 StaticField* sfield; \ 638 vdst = INST_AA(inst); \ 639 ref = FETCH(1); /* field ref */ \ 640 ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref); \ 641 sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \ 642 if (sfield == NULL) { \ 643 EXPORT_PC(); \ 644 sfield = dvmResolveStaticField(curMethod->clazz, ref); \ 645 if (sfield == NULL) \ 646 GOTO_exceptionThrown(); \ 647 if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \ 648 ABORT_JIT_TSELECT(); \ 649 } \ 650 } \ 651 dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \ 652 ILOGV("+ SPUT '%s'=0x%08llx", \ 653 sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \ 654 UPDATE_FIELD_PUT(&sfield->field); \ 655 } \ 656 FINISH(2); 657