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", 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(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(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 dvmThrowArithmeticException("divide by zero"); \ 153 GOTO_exceptionThrown(); \ 154 } \ 155 if ((u4)firstVal == 0x80000000 && secondVal == -1) { \ 156 if (_chkdiv == 1) \ 157 result = firstVal; /* division */ \ 158 else \ 159 result = 0; /* remainder */ \ 160 } else { \ 161 result = firstVal _op secondVal; \ 162 } \ 163 SET_REGISTER(vdst, result); \ 164 } else { \ 165 /* non-div/rem case */ \ 166 SET_REGISTER(vdst, \ 167 (s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2)); \ 168 } \ 169 } \ 170 FINISH(2); 171 172 #define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op) \ 173 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 174 { \ 175 u2 srcRegs; \ 176 vdst = INST_AA(inst); \ 177 srcRegs = FETCH(1); \ 178 vsrc1 = srcRegs & 0xff; \ 179 vsrc2 = srcRegs >> 8; \ 180 ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \ 181 SET_REGISTER(vdst, \ 182 _cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f)); \ 183 } \ 184 FINISH(2); 185 186 #define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv) \ 187 HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/) \ 188 vdst = INST_A(inst); \ 189 vsrc1 = INST_B(inst); \ 190 vsrc2 = FETCH(1); \ 191 ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x", \ 192 (_opname), vdst, vsrc1, vsrc2); \ 193 if (_chkdiv != 0) { \ 194 s4 firstVal, result; \ 195 firstVal = GET_REGISTER(vsrc1); \ 196 if ((s2) vsrc2 == 0) { \ 197 EXPORT_PC(); \ 198 dvmThrowArithmeticException("divide by zero"); \ 199 GOTO_exceptionThrown(); \ 200 } \ 201 if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) { \ 202 /* won't generate /lit16 instr for this; check anyway */ \ 203 if (_chkdiv == 1) \ 204 result = firstVal; /* division */ \ 205 else \ 206 result = 0; /* remainder */ \ 207 } else { \ 208 result = firstVal _op (s2) vsrc2; \ 209 } \ 210 SET_REGISTER(vdst, result); \ 211 } else { \ 212 /* non-div/rem case */ \ 213 SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2); \ 214 } \ 215 FINISH(2); 216 217 #define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv) \ 218 HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \ 219 { \ 220 u2 litInfo; \ 221 vdst = INST_AA(inst); \ 222 litInfo = FETCH(1); \ 223 vsrc1 = litInfo & 0xff; \ 224 vsrc2 = litInfo >> 8; /* constant */ \ 225 ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \ 226 (_opname), vdst, vsrc1, vsrc2); \ 227 if (_chkdiv != 0) { \ 228 s4 firstVal, result; \ 229 firstVal = GET_REGISTER(vsrc1); \ 230 if ((s1) vsrc2 == 0) { \ 231 EXPORT_PC(); \ 232 dvmThrowArithmeticException("divide by zero"); \ 233 GOTO_exceptionThrown(); \ 234 } \ 235 if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) { \ 236 if (_chkdiv == 1) \ 237 result = firstVal; /* division */ \ 238 else \ 239 result = 0; /* remainder */ \ 240 } else { \ 241 result = firstVal _op ((s1) vsrc2); \ 242 } \ 243 SET_REGISTER(vdst, result); \ 244 } else { \ 245 SET_REGISTER(vdst, \ 246 (s4) GET_REGISTER(vsrc1) _op (s1) vsrc2); \ 247 } \ 248 } \ 249 FINISH(2); 250 251 #define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op) \ 252 HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \ 253 { \ 254 u2 litInfo; \ 255 vdst = INST_AA(inst); \ 256 litInfo = FETCH(1); \ 257 vsrc1 = litInfo & 0xff; \ 258 vsrc2 = litInfo >> 8; /* constant */ \ 259 ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \ 260 (_opname), vdst, vsrc1, vsrc2); \ 261 SET_REGISTER(vdst, \ 262 _cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f)); \ 263 } \ 264 FINISH(2); 265 266 #define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv) \ 267 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 268 vdst = INST_A(inst); \ 269 vsrc1 = INST_B(inst); \ 270 ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 271 if (_chkdiv != 0) { \ 272 s4 firstVal, secondVal, result; \ 273 firstVal = GET_REGISTER(vdst); \ 274 secondVal = GET_REGISTER(vsrc1); \ 275 if (secondVal == 0) { \ 276 EXPORT_PC(); \ 277 dvmThrowArithmeticException("divide by zero"); \ 278 GOTO_exceptionThrown(); \ 279 } \ 280 if ((u4)firstVal == 0x80000000 && secondVal == -1) { \ 281 if (_chkdiv == 1) \ 282 result = firstVal; /* division */ \ 283 else \ 284 result = 0; /* remainder */ \ 285 } else { \ 286 result = firstVal _op secondVal; \ 287 } \ 288 SET_REGISTER(vdst, result); \ 289 } else { \ 290 SET_REGISTER(vdst, \ 291 (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1)); \ 292 } \ 293 FINISH(1); 294 295 #define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op) \ 296 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 297 vdst = INST_A(inst); \ 298 vsrc1 = INST_B(inst); \ 299 ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 300 SET_REGISTER(vdst, \ 301 _cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f)); \ 302 FINISH(1); 303 304 #define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv) \ 305 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 306 { \ 307 u2 srcRegs; \ 308 vdst = INST_AA(inst); \ 309 srcRegs = FETCH(1); \ 310 vsrc1 = srcRegs & 0xff; \ 311 vsrc2 = srcRegs >> 8; \ 312 ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 313 if (_chkdiv != 0) { \ 314 s8 firstVal, secondVal, result; \ 315 firstVal = GET_REGISTER_WIDE(vsrc1); \ 316 secondVal = GET_REGISTER_WIDE(vsrc2); \ 317 if (secondVal == 0LL) { \ 318 EXPORT_PC(); \ 319 dvmThrowArithmeticException("divide by zero"); \ 320 GOTO_exceptionThrown(); \ 321 } \ 322 if ((u8)firstVal == 0x8000000000000000ULL && \ 323 secondVal == -1LL) \ 324 { \ 325 if (_chkdiv == 1) \ 326 result = firstVal; /* division */ \ 327 else \ 328 result = 0; /* remainder */ \ 329 } else { \ 330 result = firstVal _op secondVal; \ 331 } \ 332 SET_REGISTER_WIDE(vdst, result); \ 333 } else { \ 334 SET_REGISTER_WIDE(vdst, \ 335 (s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \ 336 } \ 337 } \ 338 FINISH(2); 339 340 #define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op) \ 341 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 342 { \ 343 u2 srcRegs; \ 344 vdst = INST_AA(inst); \ 345 srcRegs = FETCH(1); \ 346 vsrc1 = srcRegs & 0xff; \ 347 vsrc2 = srcRegs >> 8; \ 348 ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 349 SET_REGISTER_WIDE(vdst, \ 350 _cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \ 351 } \ 352 FINISH(2); 353 354 #define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv) \ 355 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 356 vdst = INST_A(inst); \ 357 vsrc1 = INST_B(inst); \ 358 ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 359 if (_chkdiv != 0) { \ 360 s8 firstVal, secondVal, result; \ 361 firstVal = GET_REGISTER_WIDE(vdst); \ 362 secondVal = GET_REGISTER_WIDE(vsrc1); \ 363 if (secondVal == 0LL) { \ 364 EXPORT_PC(); \ 365 dvmThrowArithmeticException("divide by zero"); \ 366 GOTO_exceptionThrown(); \ 367 } \ 368 if ((u8)firstVal == 0x8000000000000000ULL && \ 369 secondVal == -1LL) \ 370 { \ 371 if (_chkdiv == 1) \ 372 result = firstVal; /* division */ \ 373 else \ 374 result = 0; /* remainder */ \ 375 } else { \ 376 result = firstVal _op secondVal; \ 377 } \ 378 SET_REGISTER_WIDE(vdst, result); \ 379 } else { \ 380 SET_REGISTER_WIDE(vdst, \ 381 (s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\ 382 } \ 383 FINISH(1); 384 385 #define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op) \ 386 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 387 vdst = INST_A(inst); \ 388 vsrc1 = INST_B(inst); \ 389 ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 390 SET_REGISTER_WIDE(vdst, \ 391 _cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \ 392 FINISH(1); 393 394 #define HANDLE_OP_X_FLOAT(_opcode, _opname, _op) \ 395 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 396 { \ 397 u2 srcRegs; \ 398 vdst = INST_AA(inst); \ 399 srcRegs = FETCH(1); \ 400 vsrc1 = srcRegs & 0xff; \ 401 vsrc2 = srcRegs >> 8; \ 402 ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 403 SET_REGISTER_FLOAT(vdst, \ 404 GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2)); \ 405 } \ 406 FINISH(2); 407 408 #define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op) \ 409 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 410 { \ 411 u2 srcRegs; \ 412 vdst = INST_AA(inst); \ 413 srcRegs = FETCH(1); \ 414 vsrc1 = srcRegs & 0xff; \ 415 vsrc2 = srcRegs >> 8; \ 416 ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 417 SET_REGISTER_DOUBLE(vdst, \ 418 GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2)); \ 419 } \ 420 FINISH(2); 421 422 #define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op) \ 423 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 424 vdst = INST_A(inst); \ 425 vsrc1 = INST_B(inst); \ 426 ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 427 SET_REGISTER_FLOAT(vdst, \ 428 GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1)); \ 429 FINISH(1); 430 431 #define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op) \ 432 HANDLE_OPCODE(_opcode /*vA, vB*/) \ 433 vdst = INST_A(inst); \ 434 vsrc1 = INST_B(inst); \ 435 ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1); \ 436 SET_REGISTER_DOUBLE(vdst, \ 437 GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1)); \ 438 FINISH(1); 439 440 #define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize) \ 441 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 442 { \ 443 ArrayObject* arrayObj; \ 444 u2 arrayInfo; \ 445 EXPORT_PC(); \ 446 vdst = INST_AA(inst); \ 447 arrayInfo = FETCH(1); \ 448 vsrc1 = arrayInfo & 0xff; /* array ptr */ \ 449 vsrc2 = arrayInfo >> 8; /* index */ \ 450 ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 451 arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \ 452 if (!checkForNull((Object*) arrayObj)) \ 453 GOTO_exceptionThrown(); \ 454 if (GET_REGISTER(vsrc2) >= arrayObj->length) { \ 455 dvmThrowArrayIndexOutOfBoundsException( \ 456 arrayObj->length, GET_REGISTER(vsrc2)); \ 457 GOTO_exceptionThrown(); \ 458 } \ 459 SET_REGISTER##_regsize(vdst, \ 460 ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]); \ 461 ILOGV("+ AGET[%d]=%#x", GET_REGISTER(vsrc2), GET_REGISTER(vdst)); \ 462 } \ 463 FINISH(2); 464 465 #define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize) \ 466 HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \ 467 { \ 468 ArrayObject* arrayObj; \ 469 u2 arrayInfo; \ 470 EXPORT_PC(); \ 471 vdst = INST_AA(inst); /* AA: source value */ \ 472 arrayInfo = FETCH(1); \ 473 vsrc1 = arrayInfo & 0xff; /* BB: array ptr */ \ 474 vsrc2 = arrayInfo >> 8; /* CC: index */ \ 475 ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \ 476 arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \ 477 if (!checkForNull((Object*) arrayObj)) \ 478 GOTO_exceptionThrown(); \ 479 if (GET_REGISTER(vsrc2) >= arrayObj->length) { \ 480 dvmThrowArrayIndexOutOfBoundsException( \ 481 arrayObj->length, GET_REGISTER(vsrc2)); \ 482 GOTO_exceptionThrown(); \ 483 } \ 484 ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\ 485 ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)] = \ 486 GET_REGISTER##_regsize(vdst); \ 487 } \ 488 FINISH(2); 489 490 /* 491 * It's possible to get a bad value out of a field with sub-32-bit stores 492 * because the -quick versions always operate on 32 bits. Consider: 493 * short foo = -1 (sets a 32-bit register to 0xffffffff) 494 * iput-quick foo (writes all 32 bits to the field) 495 * short bar = 1 (sets a 32-bit register to 0x00000001) 496 * iput-short (writes the low 16 bits to the field) 497 * iget-quick foo (reads all 32 bits from the field, yielding 0xffff0001) 498 * This can only happen when optimized and non-optimized code has interleaved 499 * access to the same field. This is unlikely but possible. 500 * 501 * The easiest way to fix this is to always read/write 32 bits at a time. On 502 * a device with a 16-bit data bus this is sub-optimal. (The alternative 503 * approach is to have sub-int versions of iget-quick, but now we're wasting 504 * Dalvik instruction space and making it less likely that handler code will 505 * already be in the CPU i-cache.) 506 */ 507 #define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize) \ 508 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 509 { \ 510 InstField* ifield; \ 511 Object* obj; \ 512 EXPORT_PC(); \ 513 vdst = INST_A(inst); \ 514 vsrc1 = INST_B(inst); /* object ptr */ \ 515 ref = FETCH(1); /* field ref */ \ 516 ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \ 517 obj = (Object*) GET_REGISTER(vsrc1); \ 518 if (!checkForNull(obj)) \ 519 GOTO_exceptionThrown(); \ 520 ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \ 521 if (ifield == NULL) { \ 522 ifield = dvmResolveInstField(curMethod->clazz, ref); \ 523 if (ifield == NULL) \ 524 GOTO_exceptionThrown(); \ 525 } \ 526 SET_REGISTER##_regsize(vdst, \ 527 dvmGetField##_ftype(obj, ifield->byteOffset)); \ 528 ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \ 529 (u8) GET_REGISTER##_regsize(vdst)); \ 530 } \ 531 FINISH(2); 532 533 #define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize) \ 534 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 535 { \ 536 Object* obj; \ 537 vdst = INST_A(inst); \ 538 vsrc1 = INST_B(inst); /* object ptr */ \ 539 ref = FETCH(1); /* field offset */ \ 540 ILOGV("|iget%s-quick v%d,v%d,field@+%u", \ 541 (_opname), vdst, vsrc1, ref); \ 542 obj = (Object*) GET_REGISTER(vsrc1); \ 543 if (!checkForNullExportPC(obj, fp, pc)) \ 544 GOTO_exceptionThrown(); \ 545 SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref)); \ 546 ILOGV("+ IGETQ %d=0x%08llx", ref, \ 547 (u8) GET_REGISTER##_regsize(vdst)); \ 548 } \ 549 FINISH(2); 550 551 #define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize) \ 552 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 553 { \ 554 InstField* ifield; \ 555 Object* obj; \ 556 EXPORT_PC(); \ 557 vdst = INST_A(inst); \ 558 vsrc1 = INST_B(inst); /* object ptr */ \ 559 ref = FETCH(1); /* field ref */ \ 560 ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \ 561 obj = (Object*) GET_REGISTER(vsrc1); \ 562 if (!checkForNull(obj)) \ 563 GOTO_exceptionThrown(); \ 564 ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \ 565 if (ifield == NULL) { \ 566 ifield = dvmResolveInstField(curMethod->clazz, ref); \ 567 if (ifield == NULL) \ 568 GOTO_exceptionThrown(); \ 569 } \ 570 dvmSetField##_ftype(obj, ifield->byteOffset, \ 571 GET_REGISTER##_regsize(vdst)); \ 572 ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \ 573 (u8) GET_REGISTER##_regsize(vdst)); \ 574 } \ 575 FINISH(2); 576 577 #define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize) \ 578 HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \ 579 { \ 580 Object* obj; \ 581 vdst = INST_A(inst); \ 582 vsrc1 = INST_B(inst); /* object ptr */ \ 583 ref = FETCH(1); /* field offset */ \ 584 ILOGV("|iput%s-quick v%d,v%d,field@0x%04x", \ 585 (_opname), vdst, vsrc1, ref); \ 586 obj = (Object*) GET_REGISTER(vsrc1); \ 587 if (!checkForNullExportPC(obj, fp, pc)) \ 588 GOTO_exceptionThrown(); \ 589 dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst)); \ 590 ILOGV("+ IPUTQ %d=0x%08llx", ref, \ 591 (u8) GET_REGISTER##_regsize(vdst)); \ 592 } \ 593 FINISH(2); 594 595 /* 596 * The JIT needs dvmDexGetResolvedField() to return non-null. 597 * Because the portable interpreter is not involved with the JIT 598 * and trace building, we only need the extra check here when this 599 * code is massaged into a stub called from an assembly interpreter. 600 * This is controlled by the JIT_STUB_HACK maco. 601 */ 602 603 #define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \ 604 HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \ 605 { \ 606 StaticField* sfield; \ 607 vdst = INST_AA(inst); \ 608 ref = FETCH(1); /* field ref */ \ 609 ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref); \ 610 sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \ 611 if (sfield == NULL) { \ 612 EXPORT_PC(); \ 613 sfield = dvmResolveStaticField(curMethod->clazz, ref); \ 614 if (sfield == NULL) \ 615 GOTO_exceptionThrown(); \ 616 if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \ 617 JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc)); \ 618 } \ 619 } \ 620 SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \ 621 ILOGV("+ SGET '%s'=0x%08llx", \ 622 sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \ 623 } \ 624 FINISH(2); 625 626 #define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize) \ 627 HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \ 628 { \ 629 StaticField* sfield; \ 630 vdst = INST_AA(inst); \ 631 ref = FETCH(1); /* field ref */ \ 632 ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref); \ 633 sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \ 634 if (sfield == NULL) { \ 635 EXPORT_PC(); \ 636 sfield = dvmResolveStaticField(curMethod->clazz, ref); \ 637 if (sfield == NULL) \ 638 GOTO_exceptionThrown(); \ 639 if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \ 640 JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc)); \ 641 } \ 642 } \ 643 dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \ 644 ILOGV("+ SPUT '%s'=0x%08llx", \ 645 sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \ 646 } \ 647 FINISH(2); 648