1 /* 2 * Copyright (C) 2009 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 /* 18 * This file contains codegen and support common to all supported 19 * ARM variants. It is included by: 20 * 21 * Codegen-$(TARGET_ARCH_VARIANT).c 22 * 23 * which combines this common code with specific support found in the 24 * applicable directory below this one. 25 */ 26 27 /* 28 * Mark garbage collection card. Skip if the value we're storing is null. 29 */ 30 static void markCard(CompilationUnit *cUnit, int valReg, int tgtAddrReg) 31 { 32 int regCardBase = dvmCompilerAllocTemp(cUnit); 33 int regCardNo = dvmCompilerAllocTemp(cUnit); 34 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0); 35 loadWordDisp(cUnit, r6SELF, offsetof(Thread, cardTable), 36 regCardBase); 37 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT); 38 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0, 39 kUnsignedByte); 40 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 41 target->defMask = ENCODE_ALL; 42 branchOver->generic.target = (LIR *)target; 43 dvmCompilerFreeTemp(cUnit, regCardBase); 44 dvmCompilerFreeTemp(cUnit, regCardNo); 45 } 46 47 static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct, 48 int srcSize, int tgtSize) 49 { 50 /* 51 * Don't optimize the register usage since it calls out to template 52 * functions 53 */ 54 RegLocation rlSrc; 55 RegLocation rlDest; 56 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */ 57 if (srcSize == 1) { 58 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 59 loadValueDirectFixed(cUnit, rlSrc, r0); 60 } else { 61 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 62 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1); 63 } 64 LOAD_FUNC_ADDR(cUnit, r2, (int)funct); 65 opReg(cUnit, kOpBlx, r2); 66 dvmCompilerClobberCallRegs(cUnit); 67 if (tgtSize == 1) { 68 RegLocation rlResult; 69 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 70 rlResult = dvmCompilerGetReturn(cUnit); 71 storeValue(cUnit, rlDest, rlResult); 72 } else { 73 RegLocation rlResult; 74 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 75 rlResult = dvmCompilerGetReturnWide(cUnit); 76 storeValueWide(cUnit, rlDest, rlResult); 77 } 78 return false; 79 } 80 81 static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir, 82 RegLocation rlDest, RegLocation rlSrc1, 83 RegLocation rlSrc2) 84 { 85 RegLocation rlResult; 86 void* funct; 87 88 switch (mir->dalvikInsn.opcode) { 89 case OP_ADD_FLOAT_2ADDR: 90 case OP_ADD_FLOAT: 91 funct = (void*) __aeabi_fadd; 92 break; 93 case OP_SUB_FLOAT_2ADDR: 94 case OP_SUB_FLOAT: 95 funct = (void*) __aeabi_fsub; 96 break; 97 case OP_DIV_FLOAT_2ADDR: 98 case OP_DIV_FLOAT: 99 funct = (void*) __aeabi_fdiv; 100 break; 101 case OP_MUL_FLOAT_2ADDR: 102 case OP_MUL_FLOAT: 103 funct = (void*) __aeabi_fmul; 104 break; 105 case OP_REM_FLOAT_2ADDR: 106 case OP_REM_FLOAT: 107 funct = (void*) fmodf; 108 break; 109 case OP_NEG_FLOAT: { 110 genNegFloat(cUnit, rlDest, rlSrc1); 111 return false; 112 } 113 default: 114 return true; 115 } 116 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */ 117 loadValueDirectFixed(cUnit, rlSrc1, r0); 118 loadValueDirectFixed(cUnit, rlSrc2, r1); 119 LOAD_FUNC_ADDR(cUnit, r2, (int)funct); 120 opReg(cUnit, kOpBlx, r2); 121 dvmCompilerClobberCallRegs(cUnit); 122 rlResult = dvmCompilerGetReturn(cUnit); 123 storeValue(cUnit, rlDest, rlResult); 124 return false; 125 } 126 127 static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir, 128 RegLocation rlDest, RegLocation rlSrc1, 129 RegLocation rlSrc2) 130 { 131 RegLocation rlResult; 132 void* funct; 133 134 switch (mir->dalvikInsn.opcode) { 135 case OP_ADD_DOUBLE_2ADDR: 136 case OP_ADD_DOUBLE: 137 funct = (void*) __aeabi_dadd; 138 break; 139 case OP_SUB_DOUBLE_2ADDR: 140 case OP_SUB_DOUBLE: 141 funct = (void*) __aeabi_dsub; 142 break; 143 case OP_DIV_DOUBLE_2ADDR: 144 case OP_DIV_DOUBLE: 145 funct = (void*) __aeabi_ddiv; 146 break; 147 case OP_MUL_DOUBLE_2ADDR: 148 case OP_MUL_DOUBLE: 149 funct = (void*) __aeabi_dmul; 150 break; 151 case OP_REM_DOUBLE_2ADDR: 152 case OP_REM_DOUBLE: 153 funct = (void*) (double (*)(double, double)) fmod; 154 break; 155 case OP_NEG_DOUBLE: { 156 genNegDouble(cUnit, rlDest, rlSrc1); 157 return false; 158 } 159 default: 160 return true; 161 } 162 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */ 163 LOAD_FUNC_ADDR(cUnit, r14lr, (int)funct); 164 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); 165 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); 166 opReg(cUnit, kOpBlx, r14lr); 167 dvmCompilerClobberCallRegs(cUnit); 168 rlResult = dvmCompilerGetReturnWide(cUnit); 169 storeValueWide(cUnit, rlDest, rlResult); 170 #if defined(WITH_SELF_VERIFICATION) 171 cUnit->usesLinkRegister = true; 172 #endif 173 return false; 174 } 175 176 static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir) 177 { 178 Opcode opcode = mir->dalvikInsn.opcode; 179 180 switch (opcode) { 181 case OP_INT_TO_FLOAT: 182 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1); 183 case OP_FLOAT_TO_INT: 184 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1); 185 case OP_DOUBLE_TO_FLOAT: 186 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1); 187 case OP_FLOAT_TO_DOUBLE: 188 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2); 189 case OP_INT_TO_DOUBLE: 190 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2); 191 case OP_DOUBLE_TO_INT: 192 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1); 193 case OP_FLOAT_TO_LONG: 194 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2); 195 case OP_LONG_TO_FLOAT: 196 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1); 197 case OP_DOUBLE_TO_LONG: 198 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2); 199 case OP_LONG_TO_DOUBLE: 200 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2); 201 default: 202 return true; 203 } 204 return false; 205 } 206 207 #if defined(WITH_SELF_VERIFICATION) 208 static void selfVerificationBranchInsert(LIR *currentLIR, ArmOpcode opcode, 209 int dest, int src1) 210 { 211 ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); 212 insn->opcode = opcode; 213 insn->operands[0] = dest; 214 insn->operands[1] = src1; 215 setupResourceMasks(insn); 216 dvmCompilerInsertLIRBefore(currentLIR, (LIR *) insn); 217 } 218 219 /* 220 * Example where r14 (LR) is preserved around a heap access under 221 * self-verification mode in Thumb2: 222 * 223 * D/dalvikvm( 1538): 0x59414c5e (0026): ldr r14, [r15pc, #220] <-hoisted 224 * D/dalvikvm( 1538): 0x59414c62 (002a): mla r4, r0, r8, r4 225 * D/dalvikvm( 1538): 0x59414c66 (002e): adds r3, r4, r3 226 * D/dalvikvm( 1538): 0x59414c6a (0032): push <r5, r14> ---+ 227 * D/dalvikvm( 1538): 0x59414c6c (0034): blx_1 0x5940f494 | 228 * D/dalvikvm( 1538): 0x59414c6e (0036): blx_2 see above <-MEM_OP_DECODE 229 * D/dalvikvm( 1538): 0x59414c70 (0038): ldr r10, [r9, #0] | 230 * D/dalvikvm( 1538): 0x59414c74 (003c): pop <r5, r14> ---+ 231 * D/dalvikvm( 1538): 0x59414c78 (0040): mov r11, r10 232 * D/dalvikvm( 1538): 0x59414c7a (0042): asr r12, r11, #31 233 * D/dalvikvm( 1538): 0x59414c7e (0046): movs r0, r2 234 * D/dalvikvm( 1538): 0x59414c80 (0048): movs r1, r3 235 * D/dalvikvm( 1538): 0x59414c82 (004a): str r2, [r5, #16] 236 * D/dalvikvm( 1538): 0x59414c84 (004c): mov r2, r11 237 * D/dalvikvm( 1538): 0x59414c86 (004e): str r3, [r5, #20] 238 * D/dalvikvm( 1538): 0x59414c88 (0050): mov r3, r12 239 * D/dalvikvm( 1538): 0x59414c8a (0052): str r11, [r5, #24] 240 * D/dalvikvm( 1538): 0x59414c8e (0056): str r12, [r5, #28] 241 * D/dalvikvm( 1538): 0x59414c92 (005a): blx r14 <-use of LR 242 * 243 */ 244 static void selfVerificationBranchInsertPass(CompilationUnit *cUnit) 245 { 246 ArmLIR *thisLIR; 247 TemplateOpcode opcode = TEMPLATE_MEM_OP_DECODE; 248 249 for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn; 250 thisLIR != (ArmLIR *) cUnit->lastLIRInsn; 251 thisLIR = NEXT_LIR(thisLIR)) { 252 if (!thisLIR->flags.isNop && thisLIR->flags.insertWrapper) { 253 /* 254 * Push r5(FP) and r14(LR) onto stack. We need to make sure that 255 * SP is 8-byte aligned, and we use r5 as a temp to restore LR 256 * for Thumb-only target since LR cannot be directly accessed in 257 * Thumb mode. Another reason to choose r5 here is it is the Dalvik 258 * frame pointer and cannot be the target of the emulated heap 259 * load. 260 */ 261 if (cUnit->usesLinkRegister) { 262 genSelfVerificationPreBranch(cUnit, thisLIR); 263 } 264 265 /* Branch to mem op decode template */ 266 selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx1, 267 (int) gDvmJit.codeCache + templateEntryOffsets[opcode], 268 (int) gDvmJit.codeCache + templateEntryOffsets[opcode]); 269 selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx2, 270 (int) gDvmJit.codeCache + templateEntryOffsets[opcode], 271 (int) gDvmJit.codeCache + templateEntryOffsets[opcode]); 272 273 /* Restore LR */ 274 if (cUnit->usesLinkRegister) { 275 genSelfVerificationPostBranch(cUnit, thisLIR); 276 } 277 } 278 } 279 } 280 #endif 281 282 /* Generate conditional branch instructions */ 283 static ArmLIR *genConditionalBranch(CompilationUnit *cUnit, 284 ArmConditionCode cond, 285 ArmLIR *target) 286 { 287 ArmLIR *branch = opCondBranch(cUnit, cond); 288 branch->generic.target = (LIR *) target; 289 return branch; 290 } 291 292 /* Generate a unconditional branch to go to the interpreter */ 293 static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset, 294 ArmLIR *pcrLabel) 295 { 296 ArmLIR *branch = opNone(cUnit, kOpUncondBr); 297 return genCheckCommon(cUnit, dOffset, branch, pcrLabel); 298 } 299 300 /* Load a wide field from an object instance */ 301 static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset) 302 { 303 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0); 304 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 305 RegLocation rlResult; 306 rlObj = loadValue(cUnit, rlObj, kCoreReg); 307 int regPtr = dvmCompilerAllocTemp(cUnit); 308 309 assert(rlDest.wide); 310 311 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, 312 NULL);/* null object? */ 313 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset); 314 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 315 316 HEAP_ACCESS_SHADOW(true); 317 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg); 318 HEAP_ACCESS_SHADOW(false); 319 320 dvmCompilerFreeTemp(cUnit, regPtr); 321 storeValueWide(cUnit, rlDest, rlResult); 322 } 323 324 /* Store a wide field to an object instance */ 325 static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset) 326 { 327 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 328 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 2); 329 rlObj = loadValue(cUnit, rlObj, kCoreReg); 330 int regPtr; 331 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg); 332 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, 333 NULL);/* null object? */ 334 regPtr = dvmCompilerAllocTemp(cUnit); 335 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset); 336 337 HEAP_ACCESS_SHADOW(true); 338 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg); 339 HEAP_ACCESS_SHADOW(false); 340 341 dvmCompilerFreeTemp(cUnit, regPtr); 342 } 343 344 /* 345 * Load a field from an object instance 346 * 347 */ 348 static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size, 349 int fieldOffset, bool isVolatile) 350 { 351 RegLocation rlResult; 352 RegisterClass regClass = dvmCompilerRegClassBySize(size); 353 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0); 354 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 355 rlObj = loadValue(cUnit, rlObj, kCoreReg); 356 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true); 357 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, 358 NULL);/* null object? */ 359 360 HEAP_ACCESS_SHADOW(true); 361 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg, 362 size, rlObj.sRegLow); 363 HEAP_ACCESS_SHADOW(false); 364 if (isVolatile) { 365 dvmCompilerGenMemBarrier(cUnit, kSY); 366 } 367 368 storeValue(cUnit, rlDest, rlResult); 369 } 370 371 /* 372 * Store a field to an object instance 373 * 374 */ 375 static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size, 376 int fieldOffset, bool isObject, bool isVolatile) 377 { 378 RegisterClass regClass = dvmCompilerRegClassBySize(size); 379 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 380 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 1); 381 rlObj = loadValue(cUnit, rlObj, kCoreReg); 382 rlSrc = loadValue(cUnit, rlSrc, regClass); 383 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, 384 NULL);/* null object? */ 385 386 if (isVolatile) { 387 dvmCompilerGenMemBarrier(cUnit, kST); 388 } 389 HEAP_ACCESS_SHADOW(true); 390 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size); 391 HEAP_ACCESS_SHADOW(false); 392 if (isVolatile) { 393 dvmCompilerGenMemBarrier(cUnit, kSY); 394 } 395 if (isObject) { 396 /* NOTE: marking card based on object head */ 397 markCard(cUnit, rlSrc.lowReg, rlObj.lowReg); 398 } 399 } 400 401 402 /* 403 * Generate array load 404 */ 405 static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size, 406 RegLocation rlArray, RegLocation rlIndex, 407 RegLocation rlDest, int scale) 408 { 409 RegisterClass regClass = dvmCompilerRegClassBySize(size); 410 int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); 411 int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents); 412 RegLocation rlResult; 413 rlArray = loadValue(cUnit, rlArray, kCoreReg); 414 rlIndex = loadValue(cUnit, rlIndex, kCoreReg); 415 int regPtr; 416 417 /* null object? */ 418 ArmLIR * pcrLabel = NULL; 419 420 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) { 421 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, 422 rlArray.lowReg, mir->offset, NULL); 423 } 424 425 regPtr = dvmCompilerAllocTemp(cUnit); 426 427 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { 428 int regLen = dvmCompilerAllocTemp(cUnit); 429 /* Get len */ 430 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen); 431 /* regPtr -> array data */ 432 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset); 433 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset, 434 pcrLabel); 435 dvmCompilerFreeTemp(cUnit, regLen); 436 } else { 437 /* regPtr -> array data */ 438 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset); 439 } 440 if ((size == kLong) || (size == kDouble)) { 441 if (scale) { 442 int rNewIndex = dvmCompilerAllocTemp(cUnit); 443 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale); 444 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex); 445 dvmCompilerFreeTemp(cUnit, rNewIndex); 446 } else { 447 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg); 448 } 449 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true); 450 451 HEAP_ACCESS_SHADOW(true); 452 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg); 453 HEAP_ACCESS_SHADOW(false); 454 455 dvmCompilerFreeTemp(cUnit, regPtr); 456 storeValueWide(cUnit, rlDest, rlResult); 457 } else { 458 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true); 459 460 HEAP_ACCESS_SHADOW(true); 461 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg, 462 scale, size); 463 HEAP_ACCESS_SHADOW(false); 464 465 dvmCompilerFreeTemp(cUnit, regPtr); 466 storeValue(cUnit, rlDest, rlResult); 467 } 468 } 469 470 /* 471 * Generate array store 472 * 473 */ 474 static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size, 475 RegLocation rlArray, RegLocation rlIndex, 476 RegLocation rlSrc, int scale) 477 { 478 RegisterClass regClass = dvmCompilerRegClassBySize(size); 479 int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); 480 int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents); 481 482 int regPtr; 483 rlArray = loadValue(cUnit, rlArray, kCoreReg); 484 rlIndex = loadValue(cUnit, rlIndex, kCoreReg); 485 486 if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) { 487 dvmCompilerClobber(cUnit, rlArray.lowReg); 488 regPtr = rlArray.lowReg; 489 } else { 490 regPtr = dvmCompilerAllocTemp(cUnit); 491 genRegCopy(cUnit, regPtr, rlArray.lowReg); 492 } 493 494 /* null object? */ 495 ArmLIR * pcrLabel = NULL; 496 497 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) { 498 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, 499 mir->offset, NULL); 500 } 501 502 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { 503 int regLen = dvmCompilerAllocTemp(cUnit); 504 //NOTE: max live temps(4) here. 505 /* Get len */ 506 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen); 507 /* regPtr -> array data */ 508 opRegImm(cUnit, kOpAdd, regPtr, dataOffset); 509 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset, 510 pcrLabel); 511 dvmCompilerFreeTemp(cUnit, regLen); 512 } else { 513 /* regPtr -> array data */ 514 opRegImm(cUnit, kOpAdd, regPtr, dataOffset); 515 } 516 /* at this point, regPtr points to array, 2 live temps */ 517 if ((size == kLong) || (size == kDouble)) { 518 //TODO: need specific wide routine that can handle fp regs 519 if (scale) { 520 int rNewIndex = dvmCompilerAllocTemp(cUnit); 521 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale); 522 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex); 523 dvmCompilerFreeTemp(cUnit, rNewIndex); 524 } else { 525 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg); 526 } 527 rlSrc = loadValueWide(cUnit, rlSrc, regClass); 528 529 HEAP_ACCESS_SHADOW(true); 530 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg); 531 HEAP_ACCESS_SHADOW(false); 532 533 dvmCompilerFreeTemp(cUnit, regPtr); 534 } else { 535 rlSrc = loadValue(cUnit, rlSrc, regClass); 536 537 HEAP_ACCESS_SHADOW(true); 538 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg, 539 scale, size); 540 HEAP_ACCESS_SHADOW(false); 541 } 542 } 543 544 /* 545 * Generate array object store 546 * Must use explicit register allocation here because of 547 * call-out to dvmCanPutArrayElement 548 */ 549 static void genArrayObjectPut(CompilationUnit *cUnit, MIR *mir, 550 RegLocation rlArray, RegLocation rlIndex, 551 RegLocation rlSrc, int scale) 552 { 553 int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); 554 int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents); 555 556 dvmCompilerFlushAllRegs(cUnit); 557 558 int regLen = r0; 559 int regPtr = r4PC; /* Preserved across call */ 560 int regArray = r1; 561 int regIndex = r7; /* Preserved across call */ 562 563 loadValueDirectFixed(cUnit, rlArray, regArray); 564 loadValueDirectFixed(cUnit, rlIndex, regIndex); 565 566 /* null object? */ 567 ArmLIR * pcrLabel = NULL; 568 569 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) { 570 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, regArray, 571 mir->offset, NULL); 572 } 573 574 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { 575 /* Get len */ 576 loadWordDisp(cUnit, regArray, lenOffset, regLen); 577 /* regPtr -> array data */ 578 opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset); 579 genBoundsCheck(cUnit, regIndex, regLen, mir->offset, 580 pcrLabel); 581 } else { 582 /* regPtr -> array data */ 583 opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset); 584 } 585 586 /* Get object to store */ 587 loadValueDirectFixed(cUnit, rlSrc, r0); 588 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmCanPutArrayElement); 589 590 /* Are we storing null? If so, avoid check */ 591 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondEq, r0, 0); 592 593 /* Make sure the types are compatible */ 594 loadWordDisp(cUnit, regArray, offsetof(Object, clazz), r1); 595 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0); 596 opReg(cUnit, kOpBlx, r2); 597 dvmCompilerClobberCallRegs(cUnit); 598 599 /* 600 * Using fixed registers here, and counting on r4 and r7 being 601 * preserved across the above call. Tell the register allocation 602 * utilities about the regs we are using directly 603 */ 604 dvmCompilerLockTemp(cUnit, regPtr); // r4PC 605 dvmCompilerLockTemp(cUnit, regIndex); // r7 606 dvmCompilerLockTemp(cUnit, r0); 607 dvmCompilerLockTemp(cUnit, r1); 608 609 /* Bad? - roll back and re-execute if so */ 610 genRegImmCheck(cUnit, kArmCondEq, r0, 0, mir->offset, pcrLabel); 611 612 /* Resume here - must reload element & array, regPtr & index preserved */ 613 loadValueDirectFixed(cUnit, rlSrc, r0); 614 loadValueDirectFixed(cUnit, rlArray, r1); 615 616 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 617 target->defMask = ENCODE_ALL; 618 branchOver->generic.target = (LIR *) target; 619 620 HEAP_ACCESS_SHADOW(true); 621 storeBaseIndexed(cUnit, regPtr, regIndex, r0, 622 scale, kWord); 623 HEAP_ACCESS_SHADOW(false); 624 625 dvmCompilerFreeTemp(cUnit, regPtr); 626 dvmCompilerFreeTemp(cUnit, regIndex); 627 628 /* NOTE: marking card here based on object head */ 629 markCard(cUnit, r0, r1); 630 } 631 632 static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, 633 RegLocation rlDest, RegLocation rlSrc1, 634 RegLocation rlShift) 635 { 636 /* 637 * Don't mess with the regsiters here as there is a particular calling 638 * convention to the out-of-line handler. 639 */ 640 RegLocation rlResult; 641 642 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); 643 loadValueDirect(cUnit, rlShift, r2); 644 switch( mir->dalvikInsn.opcode) { 645 case OP_SHL_LONG: 646 case OP_SHL_LONG_2ADDR: 647 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG); 648 break; 649 case OP_SHR_LONG: 650 case OP_SHR_LONG_2ADDR: 651 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG); 652 break; 653 case OP_USHR_LONG: 654 case OP_USHR_LONG_2ADDR: 655 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG); 656 break; 657 default: 658 return true; 659 } 660 rlResult = dvmCompilerGetReturnWide(cUnit); 661 storeValueWide(cUnit, rlDest, rlResult); 662 return false; 663 } 664 665 static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, 666 RegLocation rlDest, RegLocation rlSrc1, 667 RegLocation rlSrc2) 668 { 669 RegLocation rlResult; 670 OpKind firstOp = kOpBkpt; 671 OpKind secondOp = kOpBkpt; 672 bool callOut = false; 673 void *callTgt; 674 int retReg = r0; 675 676 switch (mir->dalvikInsn.opcode) { 677 case OP_NOT_LONG: 678 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); 679 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 680 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg); 681 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg); 682 storeValueWide(cUnit, rlDest, rlResult); 683 return false; 684 break; 685 case OP_ADD_LONG: 686 case OP_ADD_LONG_2ADDR: 687 firstOp = kOpAdd; 688 secondOp = kOpAdc; 689 break; 690 case OP_SUB_LONG: 691 case OP_SUB_LONG_2ADDR: 692 firstOp = kOpSub; 693 secondOp = kOpSbc; 694 break; 695 case OP_MUL_LONG: 696 case OP_MUL_LONG_2ADDR: 697 genMulLong(cUnit, rlDest, rlSrc1, rlSrc2); 698 return false; 699 case OP_DIV_LONG: 700 case OP_DIV_LONG_2ADDR: 701 callOut = true; 702 retReg = r0; 703 callTgt = (void*)__aeabi_ldivmod; 704 break; 705 /* NOTE - result is in r2/r3 instead of r0/r1 */ 706 case OP_REM_LONG: 707 case OP_REM_LONG_2ADDR: 708 callOut = true; 709 callTgt = (void*)__aeabi_ldivmod; 710 retReg = r2; 711 break; 712 case OP_AND_LONG_2ADDR: 713 case OP_AND_LONG: 714 firstOp = kOpAnd; 715 secondOp = kOpAnd; 716 break; 717 case OP_OR_LONG: 718 case OP_OR_LONG_2ADDR: 719 firstOp = kOpOr; 720 secondOp = kOpOr; 721 break; 722 case OP_XOR_LONG: 723 case OP_XOR_LONG_2ADDR: 724 firstOp = kOpXor; 725 secondOp = kOpXor; 726 break; 727 case OP_NEG_LONG: { 728 //TUNING: can improve this using Thumb2 code 729 int tReg = dvmCompilerAllocTemp(cUnit); 730 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); 731 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 732 loadConstantNoClobber(cUnit, tReg, 0); 733 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, 734 tReg, rlSrc2.lowReg); 735 opRegReg(cUnit, kOpSbc, tReg, rlSrc2.highReg); 736 genRegCopy(cUnit, rlResult.highReg, tReg); 737 storeValueWide(cUnit, rlDest, rlResult); 738 return false; 739 } 740 default: 741 LOGE("Invalid long arith op"); 742 dvmCompilerAbort(cUnit); 743 } 744 if (!callOut) { 745 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2); 746 } else { 747 // Adjust return regs in to handle case of rem returning r2/r3 748 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */ 749 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); 750 LOAD_FUNC_ADDR(cUnit, r14lr, (int) callTgt); 751 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); 752 opReg(cUnit, kOpBlx, r14lr); 753 dvmCompilerClobberCallRegs(cUnit); 754 if (retReg == r0) 755 rlResult = dvmCompilerGetReturnWide(cUnit); 756 else 757 rlResult = dvmCompilerGetReturnWideAlt(cUnit); 758 storeValueWide(cUnit, rlDest, rlResult); 759 #if defined(WITH_SELF_VERIFICATION) 760 cUnit->usesLinkRegister = true; 761 #endif 762 } 763 return false; 764 } 765 766 static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, 767 RegLocation rlDest, RegLocation rlSrc1, 768 RegLocation rlSrc2) 769 { 770 OpKind op = kOpBkpt; 771 bool callOut = false; 772 bool checkZero = false; 773 bool unary = false; 774 int retReg = r0; 775 int (*callTgt)(int, int); 776 RegLocation rlResult; 777 bool shiftOp = false; 778 779 switch (mir->dalvikInsn.opcode) { 780 case OP_NEG_INT: 781 op = kOpNeg; 782 unary = true; 783 break; 784 case OP_NOT_INT: 785 op = kOpMvn; 786 unary = true; 787 break; 788 case OP_ADD_INT: 789 case OP_ADD_INT_2ADDR: 790 op = kOpAdd; 791 break; 792 case OP_SUB_INT: 793 case OP_SUB_INT_2ADDR: 794 op = kOpSub; 795 break; 796 case OP_MUL_INT: 797 case OP_MUL_INT_2ADDR: 798 op = kOpMul; 799 break; 800 case OP_DIV_INT: 801 case OP_DIV_INT_2ADDR: 802 callOut = true; 803 checkZero = true; 804 callTgt = __aeabi_idiv; 805 retReg = r0; 806 break; 807 /* NOTE: returns in r1 */ 808 case OP_REM_INT: 809 case OP_REM_INT_2ADDR: 810 callOut = true; 811 checkZero = true; 812 callTgt = __aeabi_idivmod; 813 retReg = r1; 814 break; 815 case OP_AND_INT: 816 case OP_AND_INT_2ADDR: 817 op = kOpAnd; 818 break; 819 case OP_OR_INT: 820 case OP_OR_INT_2ADDR: 821 op = kOpOr; 822 break; 823 case OP_XOR_INT: 824 case OP_XOR_INT_2ADDR: 825 op = kOpXor; 826 break; 827 case OP_SHL_INT: 828 case OP_SHL_INT_2ADDR: 829 shiftOp = true; 830 op = kOpLsl; 831 break; 832 case OP_SHR_INT: 833 case OP_SHR_INT_2ADDR: 834 shiftOp = true; 835 op = kOpAsr; 836 break; 837 case OP_USHR_INT: 838 case OP_USHR_INT_2ADDR: 839 shiftOp = true; 840 op = kOpLsr; 841 break; 842 default: 843 LOGE("Invalid word arith op: %#x(%d)", 844 mir->dalvikInsn.opcode, mir->dalvikInsn.opcode); 845 dvmCompilerAbort(cUnit); 846 } 847 if (!callOut) { 848 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); 849 if (unary) { 850 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 851 opRegReg(cUnit, op, rlResult.lowReg, 852 rlSrc1.lowReg); 853 } else { 854 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); 855 if (shiftOp) { 856 int tReg = dvmCompilerAllocTemp(cUnit); 857 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31); 858 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 859 opRegRegReg(cUnit, op, rlResult.lowReg, 860 rlSrc1.lowReg, tReg); 861 dvmCompilerFreeTemp(cUnit, tReg); 862 } else { 863 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 864 opRegRegReg(cUnit, op, rlResult.lowReg, 865 rlSrc1.lowReg, rlSrc2.lowReg); 866 } 867 } 868 storeValue(cUnit, rlDest, rlResult); 869 } else { 870 RegLocation rlResult; 871 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */ 872 loadValueDirectFixed(cUnit, rlSrc2, r1); 873 LOAD_FUNC_ADDR(cUnit, r2, (int) callTgt); 874 loadValueDirectFixed(cUnit, rlSrc1, r0); 875 if (checkZero) { 876 genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL); 877 } 878 opReg(cUnit, kOpBlx, r2); 879 dvmCompilerClobberCallRegs(cUnit); 880 if (retReg == r0) 881 rlResult = dvmCompilerGetReturn(cUnit); 882 else 883 rlResult = dvmCompilerGetReturnAlt(cUnit); 884 storeValue(cUnit, rlDest, rlResult); 885 } 886 return false; 887 } 888 889 static bool genArithOp(CompilationUnit *cUnit, MIR *mir) 890 { 891 Opcode opcode = mir->dalvikInsn.opcode; 892 RegLocation rlDest; 893 RegLocation rlSrc1; 894 RegLocation rlSrc2; 895 /* Deduce sizes of operands */ 896 if (mir->ssaRep->numUses == 2) { 897 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0); 898 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1); 899 } else if (mir->ssaRep->numUses == 3) { 900 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 901 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2); 902 } else { 903 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 904 rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3); 905 assert(mir->ssaRep->numUses == 4); 906 } 907 if (mir->ssaRep->numDefs == 1) { 908 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 909 } else { 910 assert(mir->ssaRep->numDefs == 2); 911 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 912 } 913 914 if ((opcode >= OP_ADD_LONG_2ADDR) && (opcode <= OP_XOR_LONG_2ADDR)) { 915 return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2); 916 } 917 if ((opcode >= OP_ADD_LONG) && (opcode <= OP_XOR_LONG)) { 918 return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2); 919 } 920 if ((opcode >= OP_SHL_LONG_2ADDR) && (opcode <= OP_USHR_LONG_2ADDR)) { 921 return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2); 922 } 923 if ((opcode >= OP_SHL_LONG) && (opcode <= OP_USHR_LONG)) { 924 return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2); 925 } 926 if ((opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_USHR_INT_2ADDR)) { 927 return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2); 928 } 929 if ((opcode >= OP_ADD_INT) && (opcode <= OP_USHR_INT)) { 930 return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2); 931 } 932 if ((opcode >= OP_ADD_FLOAT_2ADDR) && (opcode <= OP_REM_FLOAT_2ADDR)) { 933 return genArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2); 934 } 935 if ((opcode >= OP_ADD_FLOAT) && (opcode <= OP_REM_FLOAT)) { 936 return genArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2); 937 } 938 if ((opcode >= OP_ADD_DOUBLE_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) { 939 return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2); 940 } 941 if ((opcode >= OP_ADD_DOUBLE) && (opcode <= OP_REM_DOUBLE)) { 942 return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2); 943 } 944 return true; 945 } 946 947 /* Generate unconditional branch instructions */ 948 static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target) 949 { 950 ArmLIR *branch = opNone(cUnit, kOpUncondBr); 951 branch->generic.target = (LIR *) target; 952 return branch; 953 } 954 955 /* Perform the actual operation for OP_RETURN_* */ 956 static void genReturnCommon(CompilationUnit *cUnit, MIR *mir) 957 { 958 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 959 TEMPLATE_RETURN_PROF : TEMPLATE_RETURN); 960 #if defined(WITH_JIT_TUNING) 961 gDvmJit.returnOp++; 962 #endif 963 int dPC = (int) (cUnit->method->insns + mir->offset); 964 /* Insert branch, but defer setting of target */ 965 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL); 966 /* Set up the place holder to reconstruct this Dalvik PC */ 967 ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); 968 pcrLabel->opcode = kArmPseudoPCReconstructionCell; 969 pcrLabel->operands[0] = dPC; 970 pcrLabel->operands[1] = mir->offset; 971 /* Insert the place holder to the growable list */ 972 dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel); 973 /* Branch to the PC reconstruction code */ 974 branch->generic.target = (LIR *) pcrLabel; 975 } 976 977 static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir, 978 DecodedInstruction *dInsn, 979 ArmLIR **pcrLabel) 980 { 981 unsigned int i; 982 unsigned int regMask = 0; 983 RegLocation rlArg; 984 int numDone = 0; 985 986 /* 987 * Load arguments to r0..r4. Note that these registers may contain 988 * live values, so we clobber them immediately after loading to prevent 989 * them from being used as sources for subsequent loads. 990 */ 991 dvmCompilerLockAllTemps(cUnit); 992 for (i = 0; i < dInsn->vA; i++) { 993 regMask |= 1 << i; 994 rlArg = dvmCompilerGetSrc(cUnit, mir, numDone++); 995 loadValueDirectFixed(cUnit, rlArg, i); 996 } 997 if (regMask) { 998 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */ 999 opRegRegImm(cUnit, kOpSub, r7, r5FP, 1000 sizeof(StackSaveArea) + (dInsn->vA << 2)); 1001 /* generate null check */ 1002 if (pcrLabel) { 1003 *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0, 1004 mir->offset, NULL); 1005 } 1006 storeMultiple(cUnit, r7, regMask); 1007 } 1008 } 1009 1010 static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir, 1011 DecodedInstruction *dInsn, 1012 ArmLIR **pcrLabel) 1013 { 1014 int srcOffset = dInsn->vC << 2; 1015 int numArgs = dInsn->vA; 1016 int regMask; 1017 1018 /* 1019 * Note: here, all promoted registers will have been flushed 1020 * back to the Dalvik base locations, so register usage restrictins 1021 * are lifted. All parms loaded from original Dalvik register 1022 * region - even though some might conceivably have valid copies 1023 * cached in a preserved register. 1024 */ 1025 dvmCompilerLockAllTemps(cUnit); 1026 1027 /* 1028 * r4PC : &r5FP[vC] 1029 * r7: &newFP[0] 1030 */ 1031 opRegRegImm(cUnit, kOpAdd, r4PC, r5FP, srcOffset); 1032 /* load [r0 .. min(numArgs,4)] */ 1033 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1; 1034 /* 1035 * Protect the loadMultiple instruction from being reordered with other 1036 * Dalvik stack accesses. 1037 * 1038 * This code is also shared by the invoke jumbo instructions, and this 1039 * does not need to be done if the invoke jumbo has no arguments. 1040 */ 1041 if (numArgs != 0) loadMultiple(cUnit, r4PC, regMask); 1042 1043 opRegRegImm(cUnit, kOpSub, r7, r5FP, 1044 sizeof(StackSaveArea) + (numArgs << 2)); 1045 /* generate null check */ 1046 if (pcrLabel) { 1047 *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0, 1048 mir->offset, NULL); 1049 } 1050 1051 /* 1052 * Handle remaining 4n arguments: 1053 * store previously loaded 4 values and load the next 4 values 1054 */ 1055 if (numArgs >= 8) { 1056 ArmLIR *loopLabel = NULL; 1057 /* 1058 * r0 contains "this" and it will be used later, so push it to the stack 1059 * first. Pushing r5FP is just for stack alignment purposes. 1060 */ 1061 opImm(cUnit, kOpPush, (1 << r0 | 1 << r5FP)); 1062 /* No need to generate the loop structure if numArgs <= 11 */ 1063 if (numArgs > 11) { 1064 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2); 1065 loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel); 1066 loopLabel->defMask = ENCODE_ALL; 1067 } 1068 storeMultiple(cUnit, r7, regMask); 1069 /* 1070 * Protect the loadMultiple instruction from being reordered with other 1071 * Dalvik stack accesses. 1072 */ 1073 loadMultiple(cUnit, r4PC, regMask); 1074 /* No need to generate the loop structure if numArgs <= 11 */ 1075 if (numArgs > 11) { 1076 opRegImm(cUnit, kOpSub, r5FP, 4); 1077 genConditionalBranch(cUnit, kArmCondNe, loopLabel); 1078 } 1079 } 1080 1081 /* Save the last batch of loaded values */ 1082 if (numArgs != 0) storeMultiple(cUnit, r7, regMask); 1083 1084 /* Generate the loop epilogue - don't use r0 */ 1085 if ((numArgs > 4) && (numArgs % 4)) { 1086 regMask = ((1 << (numArgs & 0x3)) - 1) << 1; 1087 /* 1088 * Protect the loadMultiple instruction from being reordered with other 1089 * Dalvik stack accesses. 1090 */ 1091 loadMultiple(cUnit, r4PC, regMask); 1092 } 1093 if (numArgs >= 8) 1094 opImm(cUnit, kOpPop, (1 << r0 | 1 << r5FP)); 1095 1096 /* Save the modulo 4 arguments */ 1097 if ((numArgs > 4) && (numArgs % 4)) { 1098 storeMultiple(cUnit, r7, regMask); 1099 } 1100 } 1101 1102 /* 1103 * Generate code to setup the call stack then jump to the chaining cell if it 1104 * is not a native method. 1105 */ 1106 static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir, 1107 BasicBlock *bb, ArmLIR *labelList, 1108 ArmLIR *pcrLabel, 1109 const Method *calleeMethod) 1110 { 1111 /* 1112 * Note: all Dalvik register state should be flushed to 1113 * memory by the point, so register usage restrictions no 1114 * longer apply. All temp & preserved registers may be used. 1115 */ 1116 dvmCompilerLockAllTemps(cUnit); 1117 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id]; 1118 1119 /* r1 = &retChainingCell */ 1120 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0); 1121 1122 /* r4PC = dalvikCallsite */ 1123 loadConstant(cUnit, r4PC, 1124 (int) (cUnit->method->insns + mir->offset)); 1125 addrRetChain->generic.target = (LIR *) retChainingCell; 1126 1127 /* r7 = calleeMethod->registersSize */ 1128 loadConstant(cUnit, r7, calleeMethod->registersSize); 1129 /* 1130 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon) 1131 * r1 = &ChainingCell 1132 * r2 = calleeMethod->outsSize (to be loaded later for Java callees) 1133 * r4PC = callsiteDPC 1134 * r7 = calleeMethod->registersSize 1135 */ 1136 if (dvmIsNativeMethod(calleeMethod)) { 1137 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 1138 TEMPLATE_INVOKE_METHOD_NATIVE_PROF : 1139 TEMPLATE_INVOKE_METHOD_NATIVE); 1140 #if defined(WITH_JIT_TUNING) 1141 gDvmJit.invokeNative++; 1142 #endif 1143 } else { 1144 /* For Java callees, set up r2 to be calleeMethod->outsSize */ 1145 loadConstant(cUnit, r2, calleeMethod->outsSize); 1146 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 1147 TEMPLATE_INVOKE_METHOD_CHAIN_PROF : 1148 TEMPLATE_INVOKE_METHOD_CHAIN); 1149 #if defined(WITH_JIT_TUNING) 1150 gDvmJit.invokeMonomorphic++; 1151 #endif 1152 /* Branch to the chaining cell */ 1153 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]); 1154 } 1155 /* Handle exceptions using the interpreter */ 1156 genTrap(cUnit, mir->offset, pcrLabel); 1157 } 1158 1159 /* 1160 * Generate code to check the validity of a predicted chain and take actions 1161 * based on the result. 1162 * 1163 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke 1164 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell 1165 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell 1166 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN 1167 * 0x426a99b2 : blx_2 see above --+ 1168 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain 1169 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter 1170 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx] 1171 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0 1172 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain 1173 * 0x426a99be : ldr r7, [pc, #off]--+ dvmJitToPatchPredictedChain 1174 * 0x426a99c0 : blx r7 --+ 1175 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell 1176 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT 1177 * 0x426a99c6 : blx_2 see above --+ 1178 */ 1179 static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir, 1180 int methodIndex, 1181 ArmLIR *retChainingCell, 1182 ArmLIR *predChainingCell, 1183 ArmLIR *pcrLabel) 1184 { 1185 /* 1186 * Note: all Dalvik register state should be flushed to 1187 * memory by the point, so register usage restrictions no 1188 * longer apply. Lock temps to prevent them from being 1189 * allocated by utility routines. 1190 */ 1191 dvmCompilerLockAllTemps(cUnit); 1192 1193 /* 1194 * For verbose printing, store the method pointer in operands[1] first as 1195 * operands[0] will be clobbered in dvmCompilerMIR2LIR. 1196 */ 1197 predChainingCell->operands[1] = (int) mir->meta.callsiteInfo->method; 1198 1199 /* "this" is already left in r0 by genProcessArgs* */ 1200 1201 /* r4PC = dalvikCallsite */ 1202 loadConstant(cUnit, r4PC, 1203 (int) (cUnit->method->insns + mir->offset)); 1204 1205 /* r1 = &retChainingCell */ 1206 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0); 1207 addrRetChain->generic.target = (LIR *) retChainingCell; 1208 1209 /* r2 = &predictedChainingCell */ 1210 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, r15pc, 0); 1211 predictedChainingCell->generic.target = (LIR *) predChainingCell; 1212 1213 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 1214 TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF : 1215 TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN); 1216 1217 /* return through lr - jump to the chaining cell */ 1218 genUnconditionalBranch(cUnit, predChainingCell); 1219 1220 /* 1221 * null-check on "this" may have been eliminated, but we still need a PC- 1222 * reconstruction label for stack overflow bailout. 1223 */ 1224 if (pcrLabel == NULL) { 1225 int dPC = (int) (cUnit->method->insns + mir->offset); 1226 pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); 1227 pcrLabel->opcode = kArmPseudoPCReconstructionCell; 1228 pcrLabel->operands[0] = dPC; 1229 pcrLabel->operands[1] = mir->offset; 1230 /* Insert the place holder to the growable list */ 1231 dvmInsertGrowableList(&cUnit->pcReconstructionList, 1232 (intptr_t) pcrLabel); 1233 } 1234 1235 /* return through lr+2 - punt to the interpreter */ 1236 genUnconditionalBranch(cUnit, pcrLabel); 1237 1238 /* 1239 * return through lr+4 - fully resolve the callee method. 1240 * r1 <- count 1241 * r2 <- &predictedChainCell 1242 * r3 <- this->class 1243 * r4 <- dPC 1244 * r7 <- this->class->vtable 1245 */ 1246 1247 /* r0 <- calleeMethod */ 1248 loadWordDisp(cUnit, r7, methodIndex * 4, r0); 1249 1250 /* Check if rechain limit is reached */ 1251 ArmLIR *bypassRechaining = genCmpImmBranch(cUnit, kArmCondGt, r1, 0); 1252 1253 LOAD_FUNC_ADDR(cUnit, r7, (int) dvmJitToPatchPredictedChain); 1254 1255 genRegCopy(cUnit, r1, r6SELF); 1256 1257 /* 1258 * r0 = calleeMethod 1259 * r2 = &predictedChainingCell 1260 * r3 = class 1261 * 1262 * &returnChainingCell has been loaded into r1 but is not needed 1263 * when patching the chaining cell and will be clobbered upon 1264 * returning so it will be reconstructed again. 1265 */ 1266 opReg(cUnit, kOpBlx, r7); 1267 1268 /* r1 = &retChainingCell */ 1269 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0); 1270 addrRetChain->generic.target = (LIR *) retChainingCell; 1271 1272 bypassRechaining->generic.target = (LIR *) addrRetChain; 1273 /* 1274 * r0 = calleeMethod, 1275 * r1 = &ChainingCell, 1276 * r4PC = callsiteDPC, 1277 */ 1278 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 1279 TEMPLATE_INVOKE_METHOD_NO_OPT_PROF : 1280 TEMPLATE_INVOKE_METHOD_NO_OPT); 1281 #if defined(WITH_JIT_TUNING) 1282 gDvmJit.invokePolymorphic++; 1283 #endif 1284 /* Handle exceptions using the interpreter */ 1285 genTrap(cUnit, mir->offset, pcrLabel); 1286 } 1287 1288 /* "this" pointer is already in r0 */ 1289 static void genInvokeVirtualWholeMethod(CompilationUnit *cUnit, 1290 MIR *mir, 1291 void *calleeAddr, 1292 ArmLIR *retChainingCell) 1293 { 1294 CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo; 1295 dvmCompilerLockAllTemps(cUnit); 1296 1297 loadClassPointer(cUnit, r1, (int) callsiteInfo); 1298 1299 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r2); 1300 /* Branch to the slow path if classes are not equal */ 1301 opRegReg(cUnit, kOpCmp, r1, r2); 1302 /* 1303 * Set the misPredBranchOver target so that it will be generated when the 1304 * code for the non-optimized invoke is generated. 1305 */ 1306 ArmLIR *classCheck = opCondBranch(cUnit, kArmCondNe); 1307 1308 /* r0 = the Dalvik PC of the callsite */ 1309 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset)); 1310 1311 newLIR2(cUnit, kThumbBl1, (int) calleeAddr, (int) calleeAddr); 1312 newLIR2(cUnit, kThumbBl2, (int) calleeAddr, (int) calleeAddr); 1313 genUnconditionalBranch(cUnit, retChainingCell); 1314 1315 /* Target of slow path */ 1316 ArmLIR *slowPathLabel = newLIR0(cUnit, kArmPseudoTargetLabel); 1317 1318 slowPathLabel->defMask = ENCODE_ALL; 1319 classCheck->generic.target = (LIR *) slowPathLabel; 1320 1321 // FIXME 1322 cUnit->printMe = true; 1323 } 1324 1325 static void genInvokeSingletonWholeMethod(CompilationUnit *cUnit, 1326 MIR *mir, 1327 void *calleeAddr, 1328 ArmLIR *retChainingCell) 1329 { 1330 /* r0 = the Dalvik PC of the callsite */ 1331 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset)); 1332 1333 newLIR2(cUnit, kThumbBl1, (int) calleeAddr, (int) calleeAddr); 1334 newLIR2(cUnit, kThumbBl2, (int) calleeAddr, (int) calleeAddr); 1335 genUnconditionalBranch(cUnit, retChainingCell); 1336 1337 // FIXME 1338 cUnit->printMe = true; 1339 } 1340 1341 /* Geneate a branch to go back to the interpreter */ 1342 static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset) 1343 { 1344 /* r0 = dalvik pc */ 1345 dvmCompilerFlushAllRegs(cUnit); 1346 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset)); 1347 loadWordDisp(cUnit, r6SELF, offsetof(Thread, 1348 jitToInterpEntries.dvmJitToInterpPunt), r1); 1349 opReg(cUnit, kOpBlx, r1); 1350 } 1351 1352 /* 1353 * Attempt to single step one instruction using the interpreter and return 1354 * to the compiled code for the next Dalvik instruction 1355 */ 1356 static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir) 1357 { 1358 int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode); 1359 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn; 1360 1361 // Single stepping is considered loop mode breaker 1362 if (cUnit->jitMode == kJitLoop) { 1363 cUnit->quitLoopMode = true; 1364 return; 1365 } 1366 1367 //If already optimized out, just ignore 1368 if (mir->dalvikInsn.opcode == OP_NOP) 1369 return; 1370 1371 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them 1372 dvmCompilerFlushAllRegs(cUnit); 1373 1374 if ((mir->next == NULL) || (flags & flagsToCheck)) { 1375 genPuntToInterp(cUnit, mir->offset); 1376 return; 1377 } 1378 int entryAddr = offsetof(Thread, 1379 jitToInterpEntries.dvmJitToInterpSingleStep); 1380 loadWordDisp(cUnit, r6SELF, entryAddr, r2); 1381 /* r0 = dalvik pc */ 1382 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset)); 1383 /* r1 = dalvik pc of following instruction */ 1384 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset)); 1385 opReg(cUnit, kOpBlx, r2); 1386 } 1387 1388 #if defined(_ARMV5TE) || defined(_ARMV5TE_VFP) 1389 /* 1390 * To prevent a thread in a monitor wait from blocking the Jit from 1391 * resetting the code cache, heavyweight monitor lock will not 1392 * be allowed to return to an existing translation. Instead, we will 1393 * handle them by branching to a handler, which will in turn call the 1394 * runtime lock routine and then branch directly back to the 1395 * interpreter main loop. Given the high cost of the heavyweight 1396 * lock operation, this additional cost should be slight (especially when 1397 * considering that we expect the vast majority of lock operations to 1398 * use the fast-path thin lock bypass). 1399 */ 1400 static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir) 1401 { 1402 bool isEnter = (mir->dalvikInsn.opcode == OP_MONITOR_ENTER); 1403 genExportPC(cUnit, mir); 1404 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */ 1405 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1406 loadValueDirectFixed(cUnit, rlSrc, r1); 1407 genRegCopy(cUnit, r0, r6SELF); 1408 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL); 1409 if (isEnter) { 1410 /* Get dPC of next insn */ 1411 loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset + 1412 dexGetWidthFromOpcode(OP_MONITOR_ENTER))); 1413 genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER); 1414 } else { 1415 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmUnlockObject); 1416 /* Do the call */ 1417 opReg(cUnit, kOpBlx, r2); 1418 /* Did we throw? */ 1419 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 1420 loadConstant(cUnit, r0, 1421 (int) (cUnit->method->insns + mir->offset + 1422 dexGetWidthFromOpcode(OP_MONITOR_EXIT))); 1423 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 1424 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 1425 target->defMask = ENCODE_ALL; 1426 branchOver->generic.target = (LIR *) target; 1427 dvmCompilerClobberCallRegs(cUnit); 1428 } 1429 } 1430 #endif 1431 1432 /* 1433 * Fetch *self->info.breakFlags. If the breakFlags are non-zero, 1434 * punt to the interpreter. 1435 */ 1436 static void genSuspendPoll(CompilationUnit *cUnit, MIR *mir) 1437 { 1438 int rTemp = dvmCompilerAllocTemp(cUnit); 1439 ArmLIR *ld; 1440 ld = loadBaseDisp(cUnit, NULL, r6SELF, 1441 offsetof(Thread, interpBreak.ctl.breakFlags), 1442 rTemp, kUnsignedByte, INVALID_SREG); 1443 setMemRefType(ld, true /* isLoad */, kMustNotAlias); 1444 genRegImmCheck(cUnit, kArmCondNe, rTemp, 0, mir->offset, NULL); 1445 } 1446 1447 /* 1448 * The following are the first-level codegen routines that analyze the format 1449 * of each bytecode then either dispatch special purpose codegen routines 1450 * or produce corresponding Thumb instructions directly. 1451 */ 1452 1453 static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir, 1454 BasicBlock *bb, ArmLIR *labelList) 1455 { 1456 /* backward branch? */ 1457 bool backwardBranch = (bb->taken->startOffset <= mir->offset); 1458 1459 if (backwardBranch && 1460 (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) { 1461 genSuspendPoll(cUnit, mir); 1462 } 1463 1464 int numPredecessors = dvmCountSetBits(bb->taken->predecessors); 1465 /* 1466 * Things could be hoisted out of the taken block into the predecessor, so 1467 * make sure it is dominated by the predecessor. 1468 */ 1469 if (numPredecessors == 1 && bb->taken->visited == false && 1470 bb->taken->blockType == kDalvikByteCode) { 1471 cUnit->nextCodegenBlock = bb->taken; 1472 } else { 1473 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */ 1474 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]); 1475 } 1476 return false; 1477 } 1478 1479 static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir) 1480 { 1481 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 1482 if ((dalvikOpcode >= OP_UNUSED_3E) && (dalvikOpcode <= OP_UNUSED_43)) { 1483 LOGE("Codegen: got unused opcode %#x",dalvikOpcode); 1484 return true; 1485 } 1486 switch (dalvikOpcode) { 1487 case OP_RETURN_VOID_BARRIER: 1488 dvmCompilerGenMemBarrier(cUnit, kST); 1489 // Intentional fallthrough 1490 case OP_RETURN_VOID: 1491 genReturnCommon(cUnit,mir); 1492 break; 1493 case OP_UNUSED_73: 1494 case OP_UNUSED_79: 1495 case OP_UNUSED_7A: 1496 case OP_DISPATCH_FF: 1497 LOGE("Codegen: got unused opcode %#x",dalvikOpcode); 1498 return true; 1499 case OP_NOP: 1500 break; 1501 default: 1502 return true; 1503 } 1504 return false; 1505 } 1506 1507 static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir) 1508 { 1509 RegLocation rlDest; 1510 RegLocation rlResult; 1511 if (mir->ssaRep->numDefs == 2) { 1512 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1513 } else { 1514 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1515 } 1516 1517 switch (mir->dalvikInsn.opcode) { 1518 case OP_CONST: 1519 case OP_CONST_4: { 1520 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1521 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB); 1522 storeValue(cUnit, rlDest, rlResult); 1523 break; 1524 } 1525 case OP_CONST_WIDE_32: { 1526 //TUNING: single routine to load constant pair for support doubles 1527 //TUNING: load 0/-1 separately to avoid load dependency 1528 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1529 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB); 1530 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, 1531 rlResult.lowReg, 31); 1532 storeValueWide(cUnit, rlDest, rlResult); 1533 break; 1534 } 1535 default: 1536 return true; 1537 } 1538 return false; 1539 } 1540 1541 static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir) 1542 { 1543 RegLocation rlDest; 1544 RegLocation rlResult; 1545 if (mir->ssaRep->numDefs == 2) { 1546 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1547 } else { 1548 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1549 } 1550 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1551 1552 switch (mir->dalvikInsn.opcode) { 1553 case OP_CONST_HIGH16: { 1554 loadConstantNoClobber(cUnit, rlResult.lowReg, 1555 mir->dalvikInsn.vB << 16); 1556 storeValue(cUnit, rlDest, rlResult); 1557 break; 1558 } 1559 case OP_CONST_WIDE_HIGH16: { 1560 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg, 1561 0, mir->dalvikInsn.vB << 16); 1562 storeValueWide(cUnit, rlDest, rlResult); 1563 break; 1564 } 1565 default: 1566 return true; 1567 } 1568 return false; 1569 } 1570 1571 static bool handleFmt20bc_Fmt40sc(CompilationUnit *cUnit, MIR *mir) 1572 { 1573 /* For OP_THROW_VERIFICATION_ERROR & OP_THROW_VERIFICATION_ERROR_JUMBO */ 1574 genInterpSingleStep(cUnit, mir); 1575 return false; 1576 } 1577 1578 static bool handleFmt21c_Fmt31c_Fmt41c(CompilationUnit *cUnit, MIR *mir) 1579 { 1580 RegLocation rlResult; 1581 RegLocation rlDest; 1582 RegLocation rlSrc; 1583 1584 switch (mir->dalvikInsn.opcode) { 1585 case OP_CONST_STRING_JUMBO: 1586 case OP_CONST_STRING: { 1587 void *strPtr = (void*) 1588 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]); 1589 1590 if (strPtr == NULL) { 1591 BAIL_LOOP_COMPILATION(); 1592 LOGE("Unexpected null string"); 1593 dvmAbort(); 1594 } 1595 1596 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1597 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1598 loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr ); 1599 storeValue(cUnit, rlDest, rlResult); 1600 break; 1601 } 1602 case OP_CONST_CLASS: 1603 case OP_CONST_CLASS_JUMBO: { 1604 void *classPtr = (void*) 1605 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]); 1606 1607 if (classPtr == NULL) { 1608 BAIL_LOOP_COMPILATION(); 1609 LOGE("Unexpected null class"); 1610 dvmAbort(); 1611 } 1612 1613 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1614 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1615 loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr ); 1616 storeValue(cUnit, rlDest, rlResult); 1617 break; 1618 } 1619 case OP_SGET: 1620 case OP_SGET_VOLATILE: 1621 case OP_SGET_VOLATILE_JUMBO: 1622 case OP_SGET_JUMBO: 1623 case OP_SGET_OBJECT: 1624 case OP_SGET_OBJECT_VOLATILE: 1625 case OP_SGET_OBJECT_VOLATILE_JUMBO: 1626 case OP_SGET_OBJECT_JUMBO: 1627 case OP_SGET_BOOLEAN: 1628 case OP_SGET_BOOLEAN_JUMBO: 1629 case OP_SGET_CHAR: 1630 case OP_SGET_CHAR_JUMBO: 1631 case OP_SGET_BYTE: 1632 case OP_SGET_BYTE_JUMBO: 1633 case OP_SGET_SHORT: 1634 case OP_SGET_SHORT_JUMBO: { 1635 int valOffset = OFFSETOF_MEMBER(StaticField, value); 1636 int tReg = dvmCompilerAllocTemp(cUnit); 1637 bool isVolatile; 1638 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1639 mir->meta.calleeMethod : cUnit->method; 1640 void *fieldPtr = (void*) 1641 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1642 1643 if (fieldPtr == NULL) { 1644 BAIL_LOOP_COMPILATION(); 1645 LOGE("Unexpected null static field"); 1646 dvmAbort(); 1647 } 1648 1649 /* 1650 * On SMP systems, Dalvik opcodes found to be referencing 1651 * volatile fields are rewritten to their _VOLATILE variant. 1652 * However, this does not happen on non-SMP systems. The JIT 1653 * still needs to know about volatility to avoid unsafe 1654 * optimizations so we determine volatility based on either 1655 * the opcode or the field access flags. 1656 */ 1657 #if ANDROID_SMP != 0 1658 Opcode opcode = mir->dalvikInsn.opcode; 1659 isVolatile = (opcode == OP_SGET_VOLATILE) || 1660 (opcode == OP_SGET_VOLATILE_JUMBO) || 1661 (opcode == OP_SGET_OBJECT_VOLATILE) || 1662 (opcode == OP_SGET_OBJECT_VOLATILE_JUMBO); 1663 assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr)); 1664 #else 1665 isVolatile = dvmIsVolatileField((Field *) fieldPtr); 1666 #endif 1667 1668 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1669 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1670 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset); 1671 1672 if (isVolatile) { 1673 dvmCompilerGenMemBarrier(cUnit, kSY); 1674 } 1675 HEAP_ACCESS_SHADOW(true); 1676 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg); 1677 HEAP_ACCESS_SHADOW(false); 1678 1679 storeValue(cUnit, rlDest, rlResult); 1680 break; 1681 } 1682 case OP_SGET_WIDE: 1683 case OP_SGET_WIDE_JUMBO: { 1684 int valOffset = OFFSETOF_MEMBER(StaticField, value); 1685 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1686 mir->meta.calleeMethod : cUnit->method; 1687 void *fieldPtr = (void*) 1688 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1689 1690 if (fieldPtr == NULL) { 1691 BAIL_LOOP_COMPILATION(); 1692 LOGE("Unexpected null static field"); 1693 dvmAbort(); 1694 } 1695 1696 int tReg = dvmCompilerAllocTemp(cUnit); 1697 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1698 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1699 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset); 1700 1701 HEAP_ACCESS_SHADOW(true); 1702 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg); 1703 HEAP_ACCESS_SHADOW(false); 1704 1705 storeValueWide(cUnit, rlDest, rlResult); 1706 break; 1707 } 1708 case OP_SPUT: 1709 case OP_SPUT_VOLATILE: 1710 case OP_SPUT_VOLATILE_JUMBO: 1711 case OP_SPUT_JUMBO: 1712 case OP_SPUT_OBJECT: 1713 case OP_SPUT_OBJECT_VOLATILE: 1714 case OP_SPUT_OBJECT_VOLATILE_JUMBO: 1715 case OP_SPUT_OBJECT_JUMBO: 1716 case OP_SPUT_BOOLEAN: 1717 case OP_SPUT_BOOLEAN_JUMBO: 1718 case OP_SPUT_CHAR: 1719 case OP_SPUT_CHAR_JUMBO: 1720 case OP_SPUT_BYTE: 1721 case OP_SPUT_BYTE_JUMBO: 1722 case OP_SPUT_SHORT: 1723 case OP_SPUT_SHORT_JUMBO: { 1724 int valOffset = OFFSETOF_MEMBER(StaticField, value); 1725 int tReg = dvmCompilerAllocTemp(cUnit); 1726 int objHead; 1727 bool isVolatile; 1728 bool isSputObject; 1729 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1730 mir->meta.calleeMethod : cUnit->method; 1731 void *fieldPtr = (void*) 1732 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1733 Opcode opcode = mir->dalvikInsn.opcode; 1734 1735 if (fieldPtr == NULL) { 1736 BAIL_LOOP_COMPILATION(); 1737 LOGE("Unexpected null static field"); 1738 dvmAbort(); 1739 } 1740 1741 #if ANDROID_SMP != 0 1742 isVolatile = (opcode == OP_SPUT_VOLATILE) || 1743 (opcode == OP_SPUT_VOLATILE_JUMBO) || 1744 (opcode == OP_SPUT_OBJECT_VOLATILE) || 1745 (opcode == OP_SPUT_OBJECT_VOLATILE_JUMBO); 1746 assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr)); 1747 #else 1748 isVolatile = dvmIsVolatileField((Field *) fieldPtr); 1749 #endif 1750 1751 isSputObject = (opcode == OP_SPUT_OBJECT) || 1752 (opcode == OP_SPUT_OBJECT_JUMBO) || 1753 (opcode == OP_SPUT_OBJECT_VOLATILE) || 1754 (opcode == OP_SPUT_OBJECT_VOLATILE_JUMBO); 1755 1756 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1757 rlSrc = loadValue(cUnit, rlSrc, kAnyReg); 1758 loadConstant(cUnit, tReg, (int) fieldPtr); 1759 if (isSputObject) { 1760 objHead = dvmCompilerAllocTemp(cUnit); 1761 loadWordDisp(cUnit, tReg, OFFSETOF_MEMBER(Field, clazz), objHead); 1762 } 1763 if (isVolatile) { 1764 dvmCompilerGenMemBarrier(cUnit, kST); 1765 } 1766 HEAP_ACCESS_SHADOW(true); 1767 storeWordDisp(cUnit, tReg, valOffset ,rlSrc.lowReg); 1768 dvmCompilerFreeTemp(cUnit, tReg); 1769 HEAP_ACCESS_SHADOW(false); 1770 if (isVolatile) { 1771 dvmCompilerGenMemBarrier(cUnit, kSY); 1772 } 1773 if (isSputObject) { 1774 /* NOTE: marking card based sfield->clazz */ 1775 markCard(cUnit, rlSrc.lowReg, objHead); 1776 dvmCompilerFreeTemp(cUnit, objHead); 1777 } 1778 1779 break; 1780 } 1781 case OP_SPUT_WIDE: 1782 case OP_SPUT_WIDE_JUMBO: { 1783 int tReg = dvmCompilerAllocTemp(cUnit); 1784 int valOffset = OFFSETOF_MEMBER(StaticField, value); 1785 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1786 mir->meta.calleeMethod : cUnit->method; 1787 void *fieldPtr = (void*) 1788 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1789 1790 if (fieldPtr == NULL) { 1791 BAIL_LOOP_COMPILATION(); 1792 LOGE("Unexpected null static field"); 1793 dvmAbort(); 1794 } 1795 1796 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 1797 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg); 1798 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset); 1799 1800 HEAP_ACCESS_SHADOW(true); 1801 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg); 1802 HEAP_ACCESS_SHADOW(false); 1803 break; 1804 } 1805 case OP_NEW_INSTANCE: 1806 case OP_NEW_INSTANCE_JUMBO: { 1807 /* 1808 * Obey the calling convention and don't mess with the register 1809 * usage. 1810 */ 1811 ClassObject *classPtr = (ClassObject *) 1812 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]); 1813 1814 if (classPtr == NULL) { 1815 BAIL_LOOP_COMPILATION(); 1816 LOGE("Unexpected null class"); 1817 dvmAbort(); 1818 } 1819 1820 /* 1821 * If it is going to throw, it should not make to the trace to begin 1822 * with. However, Alloc might throw, so we need to genExportPC() 1823 */ 1824 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0); 1825 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 1826 genExportPC(cUnit, mir); 1827 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmAllocObject); 1828 loadConstant(cUnit, r0, (int) classPtr); 1829 loadConstant(cUnit, r1, ALLOC_DONT_TRACK); 1830 opReg(cUnit, kOpBlx, r2); 1831 dvmCompilerClobberCallRegs(cUnit); 1832 /* generate a branch over if allocation is successful */ 1833 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 1834 /* 1835 * OOM exception needs to be thrown here and cannot re-execute 1836 */ 1837 loadConstant(cUnit, r0, 1838 (int) (cUnit->method->insns + mir->offset)); 1839 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 1840 /* noreturn */ 1841 1842 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 1843 target->defMask = ENCODE_ALL; 1844 branchOver->generic.target = (LIR *) target; 1845 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1846 rlResult = dvmCompilerGetReturn(cUnit); 1847 storeValue(cUnit, rlDest, rlResult); 1848 break; 1849 } 1850 case OP_CHECK_CAST: 1851 case OP_CHECK_CAST_JUMBO: { 1852 /* 1853 * Obey the calling convention and don't mess with the register 1854 * usage. 1855 */ 1856 ClassObject *classPtr = 1857 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]); 1858 /* 1859 * Note: It is possible that classPtr is NULL at this point, 1860 * even though this instruction has been successfully interpreted. 1861 * If the previous interpretation had a null source, the 1862 * interpreter would not have bothered to resolve the clazz. 1863 * Bail out to the interpreter in this case, and log it 1864 * so that we can tell if it happens frequently. 1865 */ 1866 if (classPtr == NULL) { 1867 BAIL_LOOP_COMPILATION(); 1868 LOGVV("null clazz in OP_CHECK_CAST, single-stepping"); 1869 genInterpSingleStep(cUnit, mir); 1870 return false; 1871 } 1872 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 1873 loadConstant(cUnit, r1, (int) classPtr ); 1874 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1875 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 1876 /* Null? */ 1877 ArmLIR *branch1 = genCmpImmBranch(cUnit, kArmCondEq, 1878 rlSrc.lowReg, 0); 1879 /* 1880 * rlSrc.lowReg now contains object->clazz. Note that 1881 * it could have been allocated r0, but we're okay so long 1882 * as we don't do anything desctructive until r0 is loaded 1883 * with clazz. 1884 */ 1885 /* r0 now contains object->clazz */ 1886 loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0); 1887 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInstanceofNonTrivial); 1888 opRegReg(cUnit, kOpCmp, r0, r1); 1889 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq); 1890 opReg(cUnit, kOpBlx, r2); 1891 dvmCompilerClobberCallRegs(cUnit); 1892 /* 1893 * If null, check cast failed - punt to the interpreter. Because 1894 * interpreter will be the one throwing, we don't need to 1895 * genExportPC() here. 1896 */ 1897 genZeroCheck(cUnit, r0, mir->offset, NULL); 1898 /* check cast passed - branch target here */ 1899 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 1900 target->defMask = ENCODE_ALL; 1901 branch1->generic.target = (LIR *)target; 1902 branch2->generic.target = (LIR *)target; 1903 break; 1904 } 1905 case OP_SGET_WIDE_VOLATILE: 1906 case OP_SGET_WIDE_VOLATILE_JUMBO: 1907 case OP_SPUT_WIDE_VOLATILE: 1908 case OP_SPUT_WIDE_VOLATILE_JUMBO: 1909 genInterpSingleStep(cUnit, mir); 1910 break; 1911 default: 1912 return true; 1913 } 1914 return false; 1915 } 1916 1917 /* 1918 * A typical example of inlined getter/setter from a monomorphic callsite: 1919 * 1920 * D/dalvikvm( 289): -------- dalvik offset: 0x0000 @ invoke-static (I) 1921 * D/dalvikvm( 289): -------- dalvik offset: 0x0000 @ sget-object (C) v0, ... 1922 * D/dalvikvm( 289): 0x4427fc22 (0002): ldr r0, [pc, #56] 1923 * D/dalvikvm( 289): 0x4427fc24 (0004): ldr r1, [r0, #0] 1924 * D/dalvikvm( 289): 0x4427fc26 (0006): str r1, [r5, #0] 1925 * D/dalvikvm( 289): 0x4427fc28 (0008): .align4 1926 * D/dalvikvm( 289): L0x0003: 1927 * D/dalvikvm( 289): -------- dalvik offset: 0x0003 @ move-result-object (I) v0 1928 * 1929 * Note the invoke-static and move-result-object with the (I) notation are 1930 * turned into no-op. 1931 */ 1932 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir) 1933 { 1934 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 1935 RegLocation rlResult; 1936 switch (dalvikOpcode) { 1937 case OP_MOVE_EXCEPTION: { 1938 int exOffset = offsetof(Thread, exception); 1939 int resetReg = dvmCompilerAllocTemp(cUnit); 1940 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1941 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1942 loadWordDisp(cUnit, r6SELF, exOffset, rlResult.lowReg); 1943 loadConstant(cUnit, resetReg, 0); 1944 storeWordDisp(cUnit, r6SELF, exOffset, resetReg); 1945 storeValue(cUnit, rlDest, rlResult); 1946 break; 1947 } 1948 case OP_MOVE_RESULT: 1949 case OP_MOVE_RESULT_OBJECT: { 1950 /* An inlined move result is effectively no-op */ 1951 if (mir->OptimizationFlags & MIR_INLINED) 1952 break; 1953 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1954 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL; 1955 rlSrc.fp = rlDest.fp; 1956 storeValue(cUnit, rlDest, rlSrc); 1957 break; 1958 } 1959 case OP_MOVE_RESULT_WIDE: { 1960 /* An inlined move result is effectively no-op */ 1961 if (mir->OptimizationFlags & MIR_INLINED) 1962 break; 1963 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1964 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE; 1965 rlSrc.fp = rlDest.fp; 1966 storeValueWide(cUnit, rlDest, rlSrc); 1967 break; 1968 } 1969 case OP_RETURN_WIDE: { 1970 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 1971 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE; 1972 rlDest.fp = rlSrc.fp; 1973 storeValueWide(cUnit, rlDest, rlSrc); 1974 genReturnCommon(cUnit,mir); 1975 break; 1976 } 1977 case OP_RETURN: 1978 case OP_RETURN_OBJECT: { 1979 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1980 RegLocation rlDest = LOC_DALVIK_RETURN_VAL; 1981 rlDest.fp = rlSrc.fp; 1982 storeValue(cUnit, rlDest, rlSrc); 1983 genReturnCommon(cUnit, mir); 1984 break; 1985 } 1986 case OP_MONITOR_EXIT: 1987 case OP_MONITOR_ENTER: 1988 genMonitor(cUnit, mir); 1989 break; 1990 case OP_THROW: 1991 genInterpSingleStep(cUnit, mir); 1992 break; 1993 default: 1994 return true; 1995 } 1996 return false; 1997 } 1998 1999 static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir) 2000 { 2001 Opcode opcode = mir->dalvikInsn.opcode; 2002 RegLocation rlDest; 2003 RegLocation rlSrc; 2004 RegLocation rlResult; 2005 2006 if ( (opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) { 2007 return genArithOp( cUnit, mir ); 2008 } 2009 2010 if (mir->ssaRep->numUses == 2) 2011 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 2012 else 2013 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2014 if (mir->ssaRep->numDefs == 2) 2015 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 2016 else 2017 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2018 2019 switch (opcode) { 2020 case OP_DOUBLE_TO_INT: 2021 case OP_INT_TO_FLOAT: 2022 case OP_FLOAT_TO_INT: 2023 case OP_DOUBLE_TO_FLOAT: 2024 case OP_FLOAT_TO_DOUBLE: 2025 case OP_INT_TO_DOUBLE: 2026 case OP_FLOAT_TO_LONG: 2027 case OP_LONG_TO_FLOAT: 2028 case OP_DOUBLE_TO_LONG: 2029 case OP_LONG_TO_DOUBLE: 2030 return genConversion(cUnit, mir); 2031 case OP_NEG_INT: 2032 case OP_NOT_INT: 2033 return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc); 2034 case OP_NEG_LONG: 2035 case OP_NOT_LONG: 2036 return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc); 2037 case OP_NEG_FLOAT: 2038 return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc); 2039 case OP_NEG_DOUBLE: 2040 return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc); 2041 case OP_MOVE_WIDE: 2042 storeValueWide(cUnit, rlDest, rlSrc); 2043 break; 2044 case OP_INT_TO_LONG: 2045 rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc); 2046 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2047 //TUNING: shouldn't loadValueDirect already check for phys reg? 2048 if (rlSrc.location == kLocPhysReg) { 2049 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); 2050 } else { 2051 loadValueDirect(cUnit, rlSrc, rlResult.lowReg); 2052 } 2053 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, 2054 rlResult.lowReg, 31); 2055 storeValueWide(cUnit, rlDest, rlResult); 2056 break; 2057 case OP_LONG_TO_INT: 2058 rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc); 2059 rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc); 2060 // Intentional fallthrough 2061 case OP_MOVE: 2062 case OP_MOVE_OBJECT: 2063 storeValue(cUnit, rlDest, rlSrc); 2064 break; 2065 case OP_INT_TO_BYTE: 2066 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2067 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2068 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg); 2069 storeValue(cUnit, rlDest, rlResult); 2070 break; 2071 case OP_INT_TO_SHORT: 2072 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2073 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2074 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg); 2075 storeValue(cUnit, rlDest, rlResult); 2076 break; 2077 case OP_INT_TO_CHAR: 2078 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2079 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2080 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg); 2081 storeValue(cUnit, rlDest, rlResult); 2082 break; 2083 case OP_ARRAY_LENGTH: { 2084 int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); 2085 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2086 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg, 2087 mir->offset, NULL); 2088 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2089 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset, 2090 rlResult.lowReg); 2091 storeValue(cUnit, rlDest, rlResult); 2092 break; 2093 } 2094 default: 2095 return true; 2096 } 2097 return false; 2098 } 2099 2100 static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir) 2101 { 2102 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2103 RegLocation rlDest; 2104 RegLocation rlResult; 2105 int BBBB = mir->dalvikInsn.vB; 2106 if (dalvikOpcode == OP_CONST_WIDE_16) { 2107 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 2108 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2109 loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB); 2110 //TUNING: do high separately to avoid load dependency 2111 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31); 2112 storeValueWide(cUnit, rlDest, rlResult); 2113 } else if (dalvikOpcode == OP_CONST_16) { 2114 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2115 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 2116 loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB); 2117 storeValue(cUnit, rlDest, rlResult); 2118 } else 2119 return true; 2120 return false; 2121 } 2122 2123 /* Compare agaist zero */ 2124 static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 2125 ArmLIR *labelList) 2126 { 2127 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2128 ArmConditionCode cond; 2129 /* backward branch? */ 2130 bool backwardBranch = (bb->taken->startOffset <= mir->offset); 2131 2132 if (backwardBranch && 2133 (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) { 2134 genSuspendPoll(cUnit, mir); 2135 } 2136 2137 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2138 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2139 2140 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); 2141 2142 //TUNING: break this out to allow use of Thumb2 CB[N]Z 2143 switch (dalvikOpcode) { 2144 case OP_IF_EQZ: 2145 cond = kArmCondEq; 2146 break; 2147 case OP_IF_NEZ: 2148 cond = kArmCondNe; 2149 break; 2150 case OP_IF_LTZ: 2151 cond = kArmCondLt; 2152 break; 2153 case OP_IF_GEZ: 2154 cond = kArmCondGe; 2155 break; 2156 case OP_IF_GTZ: 2157 cond = kArmCondGt; 2158 break; 2159 case OP_IF_LEZ: 2160 cond = kArmCondLe; 2161 break; 2162 default: 2163 cond = (ArmConditionCode)0; 2164 LOGE("Unexpected opcode (%d) for Fmt21t", dalvikOpcode); 2165 dvmCompilerAbort(cUnit); 2166 } 2167 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]); 2168 /* This mostly likely will be optimized away in a later phase */ 2169 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); 2170 return false; 2171 } 2172 2173 static bool isPowerOfTwo(int x) 2174 { 2175 return (x & (x - 1)) == 0; 2176 } 2177 2178 // Returns true if no more than two bits are set in 'x'. 2179 static bool isPopCountLE2(unsigned int x) 2180 { 2181 x &= x - 1; 2182 return (x & (x - 1)) == 0; 2183 } 2184 2185 // Returns the index of the lowest set bit in 'x'. 2186 static int lowestSetBit(unsigned int x) { 2187 int bit_posn = 0; 2188 while ((x & 0xf) == 0) { 2189 bit_posn += 4; 2190 x >>= 4; 2191 } 2192 while ((x & 1) == 0) { 2193 bit_posn++; 2194 x >>= 1; 2195 } 2196 return bit_posn; 2197 } 2198 2199 // Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit' 2200 // and store the result in 'rlDest'. 2201 static bool handleEasyDivide(CompilationUnit *cUnit, Opcode dalvikOpcode, 2202 RegLocation rlSrc, RegLocation rlDest, int lit) 2203 { 2204 if (lit < 2 || !isPowerOfTwo(lit)) { 2205 return false; 2206 } 2207 int k = lowestSetBit(lit); 2208 if (k >= 30) { 2209 // Avoid special cases. 2210 return false; 2211 } 2212 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 || dalvikOpcode == OP_DIV_INT_LIT16); 2213 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2214 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2215 if (div) { 2216 int tReg = dvmCompilerAllocTemp(cUnit); 2217 if (lit == 2) { 2218 // Division by 2 is by far the most common division by constant. 2219 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k); 2220 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg); 2221 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k); 2222 } else { 2223 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31); 2224 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k); 2225 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg); 2226 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k); 2227 } 2228 } else { 2229 int cReg = dvmCompilerAllocTemp(cUnit); 2230 loadConstant(cUnit, cReg, lit - 1); 2231 int tReg1 = dvmCompilerAllocTemp(cUnit); 2232 int tReg2 = dvmCompilerAllocTemp(cUnit); 2233 if (lit == 2) { 2234 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k); 2235 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg); 2236 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg); 2237 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1); 2238 } else { 2239 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31); 2240 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k); 2241 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg); 2242 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg); 2243 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1); 2244 } 2245 } 2246 storeValue(cUnit, rlDest, rlResult); 2247 return true; 2248 } 2249 2250 // Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit' 2251 // and store the result in 'rlDest'. 2252 static bool handleEasyMultiply(CompilationUnit *cUnit, 2253 RegLocation rlSrc, RegLocation rlDest, int lit) 2254 { 2255 // Can we simplify this multiplication? 2256 bool powerOfTwo = false; 2257 bool popCountLE2 = false; 2258 bool powerOfTwoMinusOne = false; 2259 if (lit < 2) { 2260 // Avoid special cases. 2261 return false; 2262 } else if (isPowerOfTwo(lit)) { 2263 powerOfTwo = true; 2264 } else if (isPopCountLE2(lit)) { 2265 popCountLE2 = true; 2266 } else if (isPowerOfTwo(lit + 1)) { 2267 powerOfTwoMinusOne = true; 2268 } else { 2269 return false; 2270 } 2271 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2272 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2273 if (powerOfTwo) { 2274 // Shift. 2275 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg, 2276 lowestSetBit(lit)); 2277 } else if (popCountLE2) { 2278 // Shift and add and shift. 2279 int firstBit = lowestSetBit(lit); 2280 int secondBit = lowestSetBit(lit ^ (1 << firstBit)); 2281 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit, 2282 firstBit, secondBit); 2283 } else { 2284 // Reverse subtract: (src << (shift + 1)) - src. 2285 assert(powerOfTwoMinusOne); 2286 // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1) 2287 int tReg = dvmCompilerAllocTemp(cUnit); 2288 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1)); 2289 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg); 2290 } 2291 storeValue(cUnit, rlDest, rlResult); 2292 return true; 2293 } 2294 2295 static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir) 2296 { 2297 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2298 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2299 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2300 RegLocation rlResult; 2301 int lit = mir->dalvikInsn.vC; 2302 OpKind op = (OpKind)0; /* Make gcc happy */ 2303 int shiftOp = false; 2304 bool isDiv = false; 2305 2306 switch (dalvikOpcode) { 2307 case OP_RSUB_INT_LIT8: 2308 case OP_RSUB_INT: { 2309 int tReg; 2310 //TUNING: add support for use of Arm rsub op 2311 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2312 tReg = dvmCompilerAllocTemp(cUnit); 2313 loadConstant(cUnit, tReg, lit); 2314 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2315 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, 2316 tReg, rlSrc.lowReg); 2317 storeValue(cUnit, rlDest, rlResult); 2318 return false; 2319 break; 2320 } 2321 2322 case OP_ADD_INT_LIT8: 2323 case OP_ADD_INT_LIT16: 2324 op = kOpAdd; 2325 break; 2326 case OP_MUL_INT_LIT8: 2327 case OP_MUL_INT_LIT16: { 2328 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) { 2329 return false; 2330 } 2331 op = kOpMul; 2332 break; 2333 } 2334 case OP_AND_INT_LIT8: 2335 case OP_AND_INT_LIT16: 2336 op = kOpAnd; 2337 break; 2338 case OP_OR_INT_LIT8: 2339 case OP_OR_INT_LIT16: 2340 op = kOpOr; 2341 break; 2342 case OP_XOR_INT_LIT8: 2343 case OP_XOR_INT_LIT16: 2344 op = kOpXor; 2345 break; 2346 case OP_SHL_INT_LIT8: 2347 lit &= 31; 2348 shiftOp = true; 2349 op = kOpLsl; 2350 break; 2351 case OP_SHR_INT_LIT8: 2352 lit &= 31; 2353 shiftOp = true; 2354 op = kOpAsr; 2355 break; 2356 case OP_USHR_INT_LIT8: 2357 lit &= 31; 2358 shiftOp = true; 2359 op = kOpLsr; 2360 break; 2361 2362 case OP_DIV_INT_LIT8: 2363 case OP_DIV_INT_LIT16: 2364 case OP_REM_INT_LIT8: 2365 case OP_REM_INT_LIT16: 2366 if (lit == 0) { 2367 /* Let the interpreter deal with div by 0 */ 2368 genInterpSingleStep(cUnit, mir); 2369 return false; 2370 } 2371 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) { 2372 return false; 2373 } 2374 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2375 loadValueDirectFixed(cUnit, rlSrc, r0); 2376 dvmCompilerClobber(cUnit, r0); 2377 if ((dalvikOpcode == OP_DIV_INT_LIT8) || 2378 (dalvikOpcode == OP_DIV_INT_LIT16)) { 2379 LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idiv); 2380 isDiv = true; 2381 } else { 2382 LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idivmod); 2383 isDiv = false; 2384 } 2385 loadConstant(cUnit, r1, lit); 2386 opReg(cUnit, kOpBlx, r2); 2387 dvmCompilerClobberCallRegs(cUnit); 2388 if (isDiv) 2389 rlResult = dvmCompilerGetReturn(cUnit); 2390 else 2391 rlResult = dvmCompilerGetReturnAlt(cUnit); 2392 storeValue(cUnit, rlDest, rlResult); 2393 return false; 2394 break; 2395 default: 2396 return true; 2397 } 2398 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2399 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2400 // Avoid shifts by literal 0 - no support in Thumb. Change to copy 2401 if (shiftOp && (lit == 0)) { 2402 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); 2403 } else { 2404 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit); 2405 } 2406 storeValue(cUnit, rlDest, rlResult); 2407 return false; 2408 } 2409 2410 static bool handleFmt22c_Fmt52c(CompilationUnit *cUnit, MIR *mir) 2411 { 2412 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2413 int fieldOffset = -1; 2414 bool isVolatile = false; 2415 switch (dalvikOpcode) { 2416 /* 2417 * Wide volatiles currently handled via single step. 2418 * Add them here if generating in-line code. 2419 * case OP_IGET_WIDE_VOLATILE: 2420 * case OP_IGET_WIDE_VOLATILE_JUMBO: 2421 * case OP_IPUT_WIDE_VOLATILE: 2422 * case OP_IPUT_WIDE_VOLATILE_JUMBO: 2423 */ 2424 case OP_IGET_VOLATILE: 2425 case OP_IGET_VOLATILE_JUMBO: 2426 case OP_IGET_OBJECT_VOLATILE: 2427 case OP_IGET_OBJECT_VOLATILE_JUMBO: 2428 case OP_IPUT_VOLATILE: 2429 case OP_IPUT_VOLATILE_JUMBO: 2430 case OP_IPUT_OBJECT_VOLATILE: 2431 case OP_IPUT_OBJECT_VOLATILE_JUMBO: 2432 #if ANDROID_SMP != 0 2433 isVolatile = true; 2434 // NOTE: intentional fallthrough 2435 #endif 2436 case OP_IGET: 2437 case OP_IGET_JUMBO: 2438 case OP_IGET_WIDE: 2439 case OP_IGET_WIDE_JUMBO: 2440 case OP_IGET_OBJECT: 2441 case OP_IGET_OBJECT_JUMBO: 2442 case OP_IGET_BOOLEAN: 2443 case OP_IGET_BOOLEAN_JUMBO: 2444 case OP_IGET_BYTE: 2445 case OP_IGET_BYTE_JUMBO: 2446 case OP_IGET_CHAR: 2447 case OP_IGET_CHAR_JUMBO: 2448 case OP_IGET_SHORT: 2449 case OP_IGET_SHORT_JUMBO: 2450 case OP_IPUT: 2451 case OP_IPUT_JUMBO: 2452 case OP_IPUT_WIDE: 2453 case OP_IPUT_WIDE_JUMBO: 2454 case OP_IPUT_OBJECT: 2455 case OP_IPUT_OBJECT_JUMBO: 2456 case OP_IPUT_BOOLEAN: 2457 case OP_IPUT_BOOLEAN_JUMBO: 2458 case OP_IPUT_BYTE: 2459 case OP_IPUT_BYTE_JUMBO: 2460 case OP_IPUT_CHAR: 2461 case OP_IPUT_CHAR_JUMBO: 2462 case OP_IPUT_SHORT: 2463 case OP_IPUT_SHORT_JUMBO: { 2464 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 2465 mir->meta.calleeMethod : cUnit->method; 2466 Field *fieldPtr = 2467 method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC]; 2468 2469 if (fieldPtr == NULL) { 2470 BAIL_LOOP_COMPILATION(); 2471 LOGE("Unexpected null instance field"); 2472 dvmAbort(); 2473 } 2474 2475 #if ANDROID_SMP != 0 2476 assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr)); 2477 #else 2478 isVolatile = dvmIsVolatileField((Field *) fieldPtr); 2479 #endif 2480 fieldOffset = ((InstField *)fieldPtr)->byteOffset; 2481 break; 2482 } 2483 default: 2484 break; 2485 } 2486 2487 switch (dalvikOpcode) { 2488 case OP_NEW_ARRAY: 2489 case OP_NEW_ARRAY_JUMBO: { 2490 // Generates a call - use explicit registers 2491 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2492 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2493 RegLocation rlResult; 2494 void *classPtr = (void*) 2495 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]); 2496 2497 if (classPtr == NULL) { 2498 BAIL_LOOP_COMPILATION(); 2499 LOGE("Unexpected null class"); 2500 dvmAbort(); 2501 } 2502 2503 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2504 genExportPC(cUnit, mir); 2505 loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */ 2506 loadConstant(cUnit, r0, (int) classPtr ); 2507 LOAD_FUNC_ADDR(cUnit, r3, (int)dvmAllocArrayByClass); 2508 /* 2509 * "len < 0": bail to the interpreter to re-execute the 2510 * instruction 2511 */ 2512 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL); 2513 loadConstant(cUnit, r2, ALLOC_DONT_TRACK); 2514 opReg(cUnit, kOpBlx, r3); 2515 dvmCompilerClobberCallRegs(cUnit); 2516 /* generate a branch over if allocation is successful */ 2517 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 2518 /* 2519 * OOM exception needs to be thrown here and cannot re-execute 2520 */ 2521 loadConstant(cUnit, r0, 2522 (int) (cUnit->method->insns + mir->offset)); 2523 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 2524 /* noreturn */ 2525 2526 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2527 target->defMask = ENCODE_ALL; 2528 branchOver->generic.target = (LIR *) target; 2529 rlResult = dvmCompilerGetReturn(cUnit); 2530 storeValue(cUnit, rlDest, rlResult); 2531 break; 2532 } 2533 case OP_INSTANCE_OF: 2534 case OP_INSTANCE_OF_JUMBO: { 2535 // May generate a call - use explicit registers 2536 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2537 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2538 RegLocation rlResult; 2539 ClassObject *classPtr = 2540 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]); 2541 /* 2542 * Note: It is possible that classPtr is NULL at this point, 2543 * even though this instruction has been successfully interpreted. 2544 * If the previous interpretation had a null source, the 2545 * interpreter would not have bothered to resolve the clazz. 2546 * Bail out to the interpreter in this case, and log it 2547 * so that we can tell if it happens frequently. 2548 */ 2549 if (classPtr == NULL) { 2550 BAIL_LOOP_COMPILATION(); 2551 LOGD("null clazz in OP_INSTANCE_OF, single-stepping"); 2552 genInterpSingleStep(cUnit, mir); 2553 break; 2554 } 2555 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2556 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */ 2557 loadConstant(cUnit, r2, (int) classPtr ); 2558 /* When taken r0 has NULL which can be used for store directly */ 2559 ArmLIR *branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0); 2560 /* r1 now contains object->clazz */ 2561 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1); 2562 /* r1 now contains object->clazz */ 2563 LOAD_FUNC_ADDR(cUnit, r3, (int)dvmInstanceofNonTrivial); 2564 loadConstant(cUnit, r0, 1); /* Assume true */ 2565 opRegReg(cUnit, kOpCmp, r1, r2); 2566 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq); 2567 genRegCopy(cUnit, r0, r1); 2568 genRegCopy(cUnit, r1, r2); 2569 opReg(cUnit, kOpBlx, r3); 2570 dvmCompilerClobberCallRegs(cUnit); 2571 /* branch target here */ 2572 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2573 target->defMask = ENCODE_ALL; 2574 rlResult = dvmCompilerGetReturn(cUnit); 2575 storeValue(cUnit, rlDest, rlResult); 2576 branch1->generic.target = (LIR *)target; 2577 branch2->generic.target = (LIR *)target; 2578 break; 2579 } 2580 case OP_IGET_WIDE: 2581 case OP_IGET_WIDE_JUMBO: 2582 genIGetWide(cUnit, mir, fieldOffset); 2583 break; 2584 case OP_IGET_VOLATILE: 2585 case OP_IGET_VOLATILE_JUMBO: 2586 case OP_IGET_OBJECT_VOLATILE: 2587 case OP_IGET_OBJECT_VOLATILE_JUMBO: 2588 case OP_IGET: 2589 case OP_IGET_JUMBO: 2590 case OP_IGET_OBJECT: 2591 case OP_IGET_OBJECT_JUMBO: 2592 case OP_IGET_BOOLEAN: 2593 case OP_IGET_BOOLEAN_JUMBO: 2594 case OP_IGET_BYTE: 2595 case OP_IGET_BYTE_JUMBO: 2596 case OP_IGET_CHAR: 2597 case OP_IGET_CHAR_JUMBO: 2598 case OP_IGET_SHORT: 2599 case OP_IGET_SHORT_JUMBO: 2600 genIGet(cUnit, mir, kWord, fieldOffset, isVolatile); 2601 break; 2602 case OP_IPUT_WIDE: 2603 case OP_IPUT_WIDE_JUMBO: 2604 genIPutWide(cUnit, mir, fieldOffset); 2605 break; 2606 case OP_IPUT_VOLATILE: 2607 case OP_IPUT_VOLATILE_JUMBO: 2608 case OP_IPUT: 2609 case OP_IPUT_JUMBO: 2610 case OP_IPUT_BOOLEAN: 2611 case OP_IPUT_BOOLEAN_JUMBO: 2612 case OP_IPUT_BYTE: 2613 case OP_IPUT_BYTE_JUMBO: 2614 case OP_IPUT_CHAR: 2615 case OP_IPUT_CHAR_JUMBO: 2616 case OP_IPUT_SHORT: 2617 case OP_IPUT_SHORT_JUMBO: 2618 genIPut(cUnit, mir, kWord, fieldOffset, false, isVolatile); 2619 break; 2620 case OP_IPUT_OBJECT_VOLATILE: 2621 case OP_IPUT_OBJECT_VOLATILE_JUMBO: 2622 case OP_IPUT_OBJECT: 2623 case OP_IPUT_OBJECT_JUMBO: 2624 genIPut(cUnit, mir, kWord, fieldOffset, true, isVolatile); 2625 break; 2626 case OP_IGET_WIDE_VOLATILE: 2627 case OP_IGET_WIDE_VOLATILE_JUMBO: 2628 case OP_IPUT_WIDE_VOLATILE: 2629 case OP_IPUT_WIDE_VOLATILE_JUMBO: 2630 genInterpSingleStep(cUnit, mir); 2631 break; 2632 default: 2633 return true; 2634 } 2635 return false; 2636 } 2637 2638 static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir) 2639 { 2640 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2641 int fieldOffset = mir->dalvikInsn.vC; 2642 switch (dalvikOpcode) { 2643 case OP_IGET_QUICK: 2644 case OP_IGET_OBJECT_QUICK: 2645 genIGet(cUnit, mir, kWord, fieldOffset, false); 2646 break; 2647 case OP_IPUT_QUICK: 2648 genIPut(cUnit, mir, kWord, fieldOffset, false, false); 2649 break; 2650 case OP_IPUT_OBJECT_QUICK: 2651 genIPut(cUnit, mir, kWord, fieldOffset, true, false); 2652 break; 2653 case OP_IGET_WIDE_QUICK: 2654 genIGetWide(cUnit, mir, fieldOffset); 2655 break; 2656 case OP_IPUT_WIDE_QUICK: 2657 genIPutWide(cUnit, mir, fieldOffset); 2658 break; 2659 default: 2660 return true; 2661 } 2662 return false; 2663 2664 } 2665 2666 /* Compare agaist zero */ 2667 static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 2668 ArmLIR *labelList) 2669 { 2670 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2671 ArmConditionCode cond; 2672 /* backward branch? */ 2673 bool backwardBranch = (bb->taken->startOffset <= mir->offset); 2674 2675 if (backwardBranch && 2676 (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) { 2677 genSuspendPoll(cUnit, mir); 2678 } 2679 2680 RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0); 2681 RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1); 2682 2683 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); 2684 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); 2685 2686 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); 2687 2688 switch (dalvikOpcode) { 2689 case OP_IF_EQ: 2690 cond = kArmCondEq; 2691 break; 2692 case OP_IF_NE: 2693 cond = kArmCondNe; 2694 break; 2695 case OP_IF_LT: 2696 cond = kArmCondLt; 2697 break; 2698 case OP_IF_GE: 2699 cond = kArmCondGe; 2700 break; 2701 case OP_IF_GT: 2702 cond = kArmCondGt; 2703 break; 2704 case OP_IF_LE: 2705 cond = kArmCondLe; 2706 break; 2707 default: 2708 cond = (ArmConditionCode)0; 2709 LOGE("Unexpected opcode (%d) for Fmt22t", dalvikOpcode); 2710 dvmCompilerAbort(cUnit); 2711 } 2712 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]); 2713 /* This mostly likely will be optimized away in a later phase */ 2714 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); 2715 return false; 2716 } 2717 2718 static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir) 2719 { 2720 Opcode opcode = mir->dalvikInsn.opcode; 2721 2722 switch (opcode) { 2723 case OP_MOVE_16: 2724 case OP_MOVE_OBJECT_16: 2725 case OP_MOVE_FROM16: 2726 case OP_MOVE_OBJECT_FROM16: { 2727 storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0), 2728 dvmCompilerGetSrc(cUnit, mir, 0)); 2729 break; 2730 } 2731 case OP_MOVE_WIDE_16: 2732 case OP_MOVE_WIDE_FROM16: { 2733 storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1), 2734 dvmCompilerGetSrcWide(cUnit, mir, 0, 1)); 2735 break; 2736 } 2737 default: 2738 return true; 2739 } 2740 return false; 2741 } 2742 2743 static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir) 2744 { 2745 Opcode opcode = mir->dalvikInsn.opcode; 2746 RegLocation rlSrc1; 2747 RegLocation rlSrc2; 2748 RegLocation rlDest; 2749 2750 if ( (opcode >= OP_ADD_INT) && (opcode <= OP_REM_DOUBLE)) { 2751 return genArithOp( cUnit, mir ); 2752 } 2753 2754 /* APUTs have 3 sources and no targets */ 2755 if (mir->ssaRep->numDefs == 0) { 2756 if (mir->ssaRep->numUses == 3) { 2757 rlDest = dvmCompilerGetSrc(cUnit, mir, 0); 2758 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1); 2759 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2); 2760 } else { 2761 assert(mir->ssaRep->numUses == 4); 2762 rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 2763 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2); 2764 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3); 2765 } 2766 } else { 2767 /* Two sources and 1 dest. Deduce the operand sizes */ 2768 if (mir->ssaRep->numUses == 4) { 2769 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 2770 rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3); 2771 } else { 2772 assert(mir->ssaRep->numUses == 2); 2773 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0); 2774 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1); 2775 } 2776 if (mir->ssaRep->numDefs == 2) { 2777 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 2778 } else { 2779 assert(mir->ssaRep->numDefs == 1); 2780 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2781 } 2782 } 2783 2784 2785 switch (opcode) { 2786 case OP_CMPL_FLOAT: 2787 case OP_CMPG_FLOAT: 2788 case OP_CMPL_DOUBLE: 2789 case OP_CMPG_DOUBLE: 2790 return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2); 2791 case OP_CMP_LONG: 2792 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2); 2793 break; 2794 case OP_AGET_WIDE: 2795 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3); 2796 break; 2797 case OP_AGET: 2798 case OP_AGET_OBJECT: 2799 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2); 2800 break; 2801 case OP_AGET_BOOLEAN: 2802 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0); 2803 break; 2804 case OP_AGET_BYTE: 2805 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0); 2806 break; 2807 case OP_AGET_CHAR: 2808 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1); 2809 break; 2810 case OP_AGET_SHORT: 2811 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1); 2812 break; 2813 case OP_APUT_WIDE: 2814 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3); 2815 break; 2816 case OP_APUT: 2817 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2); 2818 break; 2819 case OP_APUT_OBJECT: 2820 genArrayObjectPut(cUnit, mir, rlSrc1, rlSrc2, rlDest, 2); 2821 break; 2822 case OP_APUT_SHORT: 2823 case OP_APUT_CHAR: 2824 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1); 2825 break; 2826 case OP_APUT_BYTE: 2827 case OP_APUT_BOOLEAN: 2828 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0); 2829 break; 2830 default: 2831 return true; 2832 } 2833 return false; 2834 } 2835 2836 /* 2837 * Find the matching case. 2838 * 2839 * return values: 2840 * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case, 2841 * including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES). 2842 * r1 (high 32-bit): the branch offset of the matching case (only for indexes 2843 * above MAX_CHAINED_SWITCH_CASES). 2844 * 2845 * Instructions around the call are: 2846 * 2847 * mov r2, pc 2848 * blx &findPackedSwitchIndex 2849 * mov pc, r0 2850 * .align4 2851 * chaining cell for case 0 [12 bytes] 2852 * chaining cell for case 1 [12 bytes] 2853 * : 2854 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [12 bytes] 2855 * chaining cell for case default [8 bytes] 2856 * noChain exit 2857 */ 2858 static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc) 2859 { 2860 int size; 2861 int firstKey; 2862 const int *entries; 2863 int index; 2864 int jumpIndex; 2865 int caseDPCOffset = 0; 2866 /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */ 2867 int chainingPC = (pc + 4) & ~3; 2868 2869 /* 2870 * Packed switch data format: 2871 * ushort ident = 0x0100 magic value 2872 * ushort size number of entries in the table 2873 * int first_key first (and lowest) switch case value 2874 * int targets[size] branch targets, relative to switch opcode 2875 * 2876 * Total size is (4+size*2) 16-bit code units. 2877 */ 2878 size = switchData[1]; 2879 assert(size > 0); 2880 2881 firstKey = switchData[2]; 2882 firstKey |= switchData[3] << 16; 2883 2884 2885 /* The entries are guaranteed to be aligned on a 32-bit boundary; 2886 * we can treat them as a native int array. 2887 */ 2888 entries = (const int*) &switchData[4]; 2889 assert(((u4)entries & 0x3) == 0); 2890 2891 index = testVal - firstKey; 2892 2893 /* Jump to the default cell */ 2894 if (index < 0 || index >= size) { 2895 jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES); 2896 /* Jump to the non-chaining exit point */ 2897 } else if (index >= MAX_CHAINED_SWITCH_CASES) { 2898 jumpIndex = MAX_CHAINED_SWITCH_CASES + 1; 2899 caseDPCOffset = entries[index]; 2900 /* Jump to the inline chaining cell */ 2901 } else { 2902 jumpIndex = index; 2903 } 2904 2905 chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE; 2906 return (((s8) caseDPCOffset) << 32) | (u8) chainingPC; 2907 } 2908 2909 /* See comments for findPackedSwitchIndex */ 2910 static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc) 2911 { 2912 int size; 2913 const int *keys; 2914 const int *entries; 2915 int chainingPC = (pc + 4) & ~3; 2916 int i; 2917 2918 /* 2919 * Sparse switch data format: 2920 * ushort ident = 0x0200 magic value 2921 * ushort size number of entries in the table; > 0 2922 * int keys[size] keys, sorted low-to-high; 32-bit aligned 2923 * int targets[size] branch targets, relative to switch opcode 2924 * 2925 * Total size is (2+size*4) 16-bit code units. 2926 */ 2927 2928 size = switchData[1]; 2929 assert(size > 0); 2930 2931 /* The keys are guaranteed to be aligned on a 32-bit boundary; 2932 * we can treat them as a native int array. 2933 */ 2934 keys = (const int*) &switchData[2]; 2935 assert(((u4)keys & 0x3) == 0); 2936 2937 /* The entries are guaranteed to be aligned on a 32-bit boundary; 2938 * we can treat them as a native int array. 2939 */ 2940 entries = keys + size; 2941 assert(((u4)entries & 0x3) == 0); 2942 2943 /* 2944 * Run through the list of keys, which are guaranteed to 2945 * be sorted low-to-high. 2946 * 2947 * Most tables have 3-4 entries. Few have more than 10. A binary 2948 * search here is probably not useful. 2949 */ 2950 for (i = 0; i < size; i++) { 2951 int k = keys[i]; 2952 if (k == testVal) { 2953 /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */ 2954 int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ? 2955 i : MAX_CHAINED_SWITCH_CASES + 1; 2956 chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE; 2957 return (((s8) entries[i]) << 32) | (u8) chainingPC; 2958 } else if (k > testVal) { 2959 break; 2960 } 2961 } 2962 return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 2963 CHAIN_CELL_NORMAL_SIZE; 2964 } 2965 2966 static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir) 2967 { 2968 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2969 switch (dalvikOpcode) { 2970 case OP_FILL_ARRAY_DATA: { 2971 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2972 // Making a call - use explicit registers 2973 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2974 genExportPC(cUnit, mir); 2975 loadValueDirectFixed(cUnit, rlSrc, r0); 2976 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInterpHandleFillArrayData); 2977 loadConstant(cUnit, r1, 2978 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB)); 2979 opReg(cUnit, kOpBlx, r2); 2980 dvmCompilerClobberCallRegs(cUnit); 2981 /* generate a branch over if successful */ 2982 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 2983 loadConstant(cUnit, r0, 2984 (int) (cUnit->method->insns + mir->offset)); 2985 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 2986 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2987 target->defMask = ENCODE_ALL; 2988 branchOver->generic.target = (LIR *) target; 2989 break; 2990 } 2991 /* 2992 * Compute the goto target of up to 2993 * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells. 2994 * See the comment before findPackedSwitchIndex for the code layout. 2995 */ 2996 case OP_PACKED_SWITCH: 2997 case OP_SPARSE_SWITCH: { 2998 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2999 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 3000 loadValueDirectFixed(cUnit, rlSrc, r1); 3001 dvmCompilerLockAllTemps(cUnit); 3002 if (dalvikOpcode == OP_PACKED_SWITCH) { 3003 LOAD_FUNC_ADDR(cUnit, r4PC, (int)findPackedSwitchIndex); 3004 } else { 3005 LOAD_FUNC_ADDR(cUnit, r4PC, (int)findSparseSwitchIndex); 3006 } 3007 /* r0 <- Addr of the switch data */ 3008 loadConstant(cUnit, r0, 3009 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB)); 3010 /* r2 <- pc of the instruction following the blx */ 3011 opRegReg(cUnit, kOpMov, r2, r15pc); 3012 opReg(cUnit, kOpBlx, r4PC); 3013 dvmCompilerClobberCallRegs(cUnit); 3014 /* pc <- computed goto target */ 3015 opRegReg(cUnit, kOpMov, r15pc, r0); 3016 break; 3017 } 3018 default: 3019 return true; 3020 } 3021 return false; 3022 } 3023 3024 /* 3025 * See the example of predicted inlining listed before the 3026 * genValidationForPredictedInline function. The function here takes care the 3027 * branch over at 0x4858de78 and the misprediction target at 0x4858de7a. 3028 */ 3029 static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir, 3030 BasicBlock *bb, 3031 ArmLIR *labelList) 3032 { 3033 BasicBlock *fallThrough = bb->fallThrough; 3034 3035 /* Bypass the move-result block if there is one */ 3036 if (fallThrough->firstMIRInsn) { 3037 assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED); 3038 fallThrough = fallThrough->fallThrough; 3039 } 3040 /* Generate a branch over if the predicted inlining is correct */ 3041 genUnconditionalBranch(cUnit, &labelList[fallThrough->id]); 3042 3043 /* Reset the register state */ 3044 dvmCompilerResetRegPool(cUnit); 3045 dvmCompilerClobberAllRegs(cUnit); 3046 dvmCompilerResetNullCheck(cUnit); 3047 3048 /* Target for the slow invoke path */ 3049 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 3050 target->defMask = ENCODE_ALL; 3051 /* Hook up the target to the verification branch */ 3052 mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target; 3053 } 3054 3055 static bool handleFmt35c_3rc_5rc(CompilationUnit *cUnit, MIR *mir, 3056 BasicBlock *bb, ArmLIR *labelList) 3057 { 3058 ArmLIR *retChainingCell = NULL; 3059 ArmLIR *pcrLabel = NULL; 3060 3061 /* An invoke with the MIR_INLINED is effectively a no-op */ 3062 if (mir->OptimizationFlags & MIR_INLINED) 3063 return false; 3064 3065 if (bb->fallThrough != NULL) 3066 retChainingCell = &labelList[bb->fallThrough->id]; 3067 3068 DecodedInstruction *dInsn = &mir->dalvikInsn; 3069 switch (mir->dalvikInsn.opcode) { 3070 /* 3071 * calleeMethod = this->clazz->vtable[ 3072 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex 3073 * ] 3074 */ 3075 case OP_INVOKE_VIRTUAL: 3076 case OP_INVOKE_VIRTUAL_RANGE: 3077 case OP_INVOKE_VIRTUAL_JUMBO: { 3078 ArmLIR *predChainingCell = &labelList[bb->taken->id]; 3079 int methodIndex = 3080 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]-> 3081 methodIndex; 3082 3083 /* 3084 * If the invoke has non-null misPredBranchOver, we need to generate 3085 * the non-inlined version of the invoke here to handle the 3086 * mispredicted case. 3087 */ 3088 if (mir->meta.callsiteInfo->misPredBranchOver) { 3089 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList); 3090 } 3091 3092 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL) 3093 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3094 else 3095 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3096 3097 genInvokeVirtualCommon(cUnit, mir, methodIndex, 3098 retChainingCell, 3099 predChainingCell, 3100 pcrLabel); 3101 break; 3102 } 3103 /* 3104 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex 3105 * ->pResMethods[BBBB]->methodIndex] 3106 */ 3107 case OP_INVOKE_SUPER: 3108 case OP_INVOKE_SUPER_RANGE: 3109 case OP_INVOKE_SUPER_JUMBO: { 3110 /* Grab the method ptr directly from what the interpreter sees */ 3111 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3112 assert(calleeMethod == cUnit->method->clazz->super->vtable[ 3113 cUnit->method->clazz->pDvmDex-> 3114 pResMethods[dInsn->vB]->methodIndex]); 3115 3116 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER) 3117 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3118 else 3119 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3120 3121 if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) { 3122 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3123 void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns); 3124 assert(calleeAddr); 3125 genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr, 3126 retChainingCell); 3127 } else { 3128 /* r0 = calleeMethod */ 3129 loadConstant(cUnit, r0, (int) calleeMethod); 3130 3131 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 3132 calleeMethod); 3133 } 3134 break; 3135 } 3136 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */ 3137 case OP_INVOKE_DIRECT: 3138 case OP_INVOKE_DIRECT_RANGE: 3139 case OP_INVOKE_DIRECT_JUMBO: { 3140 /* Grab the method ptr directly from what the interpreter sees */ 3141 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3142 assert(calleeMethod == 3143 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]); 3144 3145 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) 3146 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3147 else 3148 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3149 3150 /* r0 = calleeMethod */ 3151 loadConstant(cUnit, r0, (int) calleeMethod); 3152 3153 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 3154 calleeMethod); 3155 break; 3156 } 3157 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */ 3158 case OP_INVOKE_STATIC: 3159 case OP_INVOKE_STATIC_RANGE: 3160 case OP_INVOKE_STATIC_JUMBO: { 3161 /* Grab the method ptr directly from what the interpreter sees */ 3162 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3163 assert(calleeMethod == 3164 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]); 3165 3166 if (mir->dalvikInsn.opcode == OP_INVOKE_STATIC) 3167 genProcessArgsNoRange(cUnit, mir, dInsn, 3168 NULL /* no null check */); 3169 else 3170 genProcessArgsRange(cUnit, mir, dInsn, 3171 NULL /* no null check */); 3172 3173 if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) { 3174 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3175 void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns); 3176 assert(calleeAddr); 3177 genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr, 3178 retChainingCell); 3179 } else { 3180 /* r0 = calleeMethod */ 3181 loadConstant(cUnit, r0, (int) calleeMethod); 3182 3183 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 3184 calleeMethod); 3185 } 3186 break; 3187 } 3188 /* 3189 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz, 3190 * BBBB, method, method->clazz->pDvmDex) 3191 * 3192 * The following is an example of generated code for 3193 * "invoke-interface v0" 3194 * 3195 * -------- dalvik offset: 0x0008 @ invoke-interface v0 3196 * 0x47357e36 : ldr r0, [r5, #0] --+ 3197 * 0x47357e38 : sub r7,r5,#24 | 3198 * 0x47357e3c : cmp r0, #0 | genProcessArgsNoRange 3199 * 0x47357e3e : beq 0x47357e82 | 3200 * 0x47357e40 : stmia r7, <r0> --+ 3201 * 0x47357e42 : ldr r4, [pc, #120] --> r4 <- dalvikPC of this invoke 3202 * 0x47357e44 : add r1, pc, #64 --> r1 <- &retChainingCell 3203 * 0x47357e46 : add r2, pc, #72 --> r2 <- &predictedChainingCell 3204 * 0x47357e48 : blx_1 0x47348190 --+ TEMPLATE_INVOKE_METHOD_ 3205 * 0x47357e4a : blx_2 see above --+ PREDICTED_CHAIN 3206 * 0x47357e4c : b 0x47357e90 --> off to the predicted chain 3207 * 0x47357e4e : b 0x47357e82 --> punt to the interpreter 3208 * 0x47357e50 : mov r8, r1 --+ 3209 * 0x47357e52 : mov r9, r2 | 3210 * 0x47357e54 : ldr r2, [pc, #96] | 3211 * 0x47357e56 : mov r10, r3 | 3212 * 0x47357e58 : movs r0, r3 | dvmFindInterfaceMethodInCache 3213 * 0x47357e5a : ldr r3, [pc, #88] | 3214 * 0x47357e5c : ldr r7, [pc, #80] | 3215 * 0x47357e5e : mov r1, #1452 | 3216 * 0x47357e62 : blx r7 --+ 3217 * 0x47357e64 : cmp r0, #0 --> calleeMethod == NULL? 3218 * 0x47357e66 : bne 0x47357e6e --> branch over the throw if !r0 3219 * 0x47357e68 : ldr r0, [pc, #80] --> load Dalvik PC of the invoke 3220 * 0x47357e6a : blx_1 0x47348494 --+ TEMPLATE_THROW_EXCEPTION_ 3221 * 0x47357e6c : blx_2 see above --+ COMMON 3222 * 0x47357e6e : mov r1, r8 --> r1 <- &retChainingCell 3223 * 0x47357e70 : cmp r1, #0 --> compare against 0 3224 * 0x47357e72 : bgt 0x47357e7c --> >=0? don't rechain 3225 * 0x47357e74 : ldr r7, [pc, #off] --+ 3226 * 0x47357e76 : mov r2, r9 | dvmJitToPatchPredictedChain 3227 * 0x47357e78 : mov r3, r10 | 3228 * 0x47357e7a : blx r7 --+ 3229 * 0x47357e7c : add r1, pc, #8 --> r1 <- &retChainingCell 3230 * 0x47357e7e : blx_1 0x4734809c --+ TEMPLATE_INVOKE_METHOD_NO_OPT 3231 * 0x47357e80 : blx_2 see above --+ 3232 * -------- reconstruct dalvik PC : 0x425719dc @ +0x0008 3233 * 0x47357e82 : ldr r0, [pc, #56] 3234 * Exception_Handling: 3235 * 0x47357e84 : ldr r1, [r6, #92] 3236 * 0x47357e86 : blx r1 3237 * 0x47357e88 : .align4 3238 * -------- chaining cell (hot): 0x000b 3239 * 0x47357e88 : ldr r0, [r6, #104] 3240 * 0x47357e8a : blx r0 3241 * 0x47357e8c : data 0x19e2(6626) 3242 * 0x47357e8e : data 0x4257(16983) 3243 * 0x47357e90 : .align4 3244 * -------- chaining cell (predicted) 3245 * 0x47357e90 : data 0xe7fe(59390) --> will be patched into bx 3246 * 0x47357e92 : data 0x0000(0) 3247 * 0x47357e94 : data 0x0000(0) --> class 3248 * 0x47357e96 : data 0x0000(0) 3249 * 0x47357e98 : data 0x0000(0) --> method 3250 * 0x47357e9a : data 0x0000(0) 3251 * 0x47357e9c : data 0x0000(0) --> rechain count 3252 * 0x47357e9e : data 0x0000(0) 3253 * -------- end of chaining cells (0x006c) 3254 * 0x47357eb0 : .word (0xad03e369) 3255 * 0x47357eb4 : .word (0x28a90) 3256 * 0x47357eb8 : .word (0x41a63394) 3257 * 0x47357ebc : .word (0x425719dc) 3258 */ 3259 case OP_INVOKE_INTERFACE: 3260 case OP_INVOKE_INTERFACE_RANGE: 3261 case OP_INVOKE_INTERFACE_JUMBO: { 3262 ArmLIR *predChainingCell = &labelList[bb->taken->id]; 3263 3264 /* 3265 * If the invoke has non-null misPredBranchOver, we need to generate 3266 * the non-inlined version of the invoke here to handle the 3267 * mispredicted case. 3268 */ 3269 if (mir->meta.callsiteInfo->misPredBranchOver) { 3270 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList); 3271 } 3272 3273 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE) 3274 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3275 else 3276 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3277 3278 /* "this" is already left in r0 by genProcessArgs* */ 3279 3280 /* r4PC = dalvikCallsite */ 3281 loadConstant(cUnit, r4PC, 3282 (int) (cUnit->method->insns + mir->offset)); 3283 3284 /* r1 = &retChainingCell */ 3285 ArmLIR *addrRetChain = 3286 opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0); 3287 addrRetChain->generic.target = (LIR *) retChainingCell; 3288 3289 /* r2 = &predictedChainingCell */ 3290 ArmLIR *predictedChainingCell = 3291 opRegRegImm(cUnit, kOpAdd, r2, r15pc, 0); 3292 predictedChainingCell->generic.target = (LIR *) predChainingCell; 3293 3294 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 3295 TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF : 3296 TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN); 3297 3298 /* return through lr - jump to the chaining cell */ 3299 genUnconditionalBranch(cUnit, predChainingCell); 3300 3301 /* 3302 * null-check on "this" may have been eliminated, but we still need 3303 * a PC-reconstruction label for stack overflow bailout. 3304 */ 3305 if (pcrLabel == NULL) { 3306 int dPC = (int) (cUnit->method->insns + mir->offset); 3307 pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); 3308 pcrLabel->opcode = kArmPseudoPCReconstructionCell; 3309 pcrLabel->operands[0] = dPC; 3310 pcrLabel->operands[1] = mir->offset; 3311 /* Insert the place holder to the growable list */ 3312 dvmInsertGrowableList(&cUnit->pcReconstructionList, 3313 (intptr_t) pcrLabel); 3314 } 3315 3316 /* return through lr+2 - punt to the interpreter */ 3317 genUnconditionalBranch(cUnit, pcrLabel); 3318 3319 /* 3320 * return through lr+4 - fully resolve the callee method. 3321 * r1 <- count 3322 * r2 <- &predictedChainCell 3323 * r3 <- this->class 3324 * r4 <- dPC 3325 * r7 <- this->class->vtable 3326 */ 3327 3328 /* Save count, &predictedChainCell, and class to high regs first */ 3329 genRegCopy(cUnit, r8, r1); 3330 genRegCopy(cUnit, r9, r2); 3331 genRegCopy(cUnit, r10, r3); 3332 3333 /* r0 now contains this->clazz */ 3334 genRegCopy(cUnit, r0, r3); 3335 3336 /* r1 = BBBB */ 3337 loadConstant(cUnit, r1, dInsn->vB); 3338 3339 /* r2 = method (caller) */ 3340 loadConstant(cUnit, r2, (int) cUnit->method); 3341 3342 /* r3 = pDvmDex */ 3343 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex); 3344 3345 LOAD_FUNC_ADDR(cUnit, r7, 3346 (intptr_t) dvmFindInterfaceMethodInCache); 3347 opReg(cUnit, kOpBlx, r7); 3348 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */ 3349 3350 dvmCompilerClobberCallRegs(cUnit); 3351 /* generate a branch over if the interface method is resolved */ 3352 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 3353 /* 3354 * calleeMethod == NULL -> throw 3355 */ 3356 loadConstant(cUnit, r0, 3357 (int) (cUnit->method->insns + mir->offset)); 3358 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 3359 /* noreturn */ 3360 3361 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 3362 target->defMask = ENCODE_ALL; 3363 branchOver->generic.target = (LIR *) target; 3364 3365 genRegCopy(cUnit, r1, r8); 3366 3367 /* Check if rechain limit is reached */ 3368 ArmLIR *bypassRechaining = genCmpImmBranch(cUnit, kArmCondGt, 3369 r1, 0); 3370 3371 LOAD_FUNC_ADDR(cUnit, r7, (int) dvmJitToPatchPredictedChain); 3372 3373 genRegCopy(cUnit, r1, r6SELF); 3374 genRegCopy(cUnit, r2, r9); 3375 genRegCopy(cUnit, r3, r10); 3376 3377 /* 3378 * r0 = calleeMethod 3379 * r2 = &predictedChainingCell 3380 * r3 = class 3381 * 3382 * &returnChainingCell has been loaded into r1 but is not needed 3383 * when patching the chaining cell and will be clobbered upon 3384 * returning so it will be reconstructed again. 3385 */ 3386 opReg(cUnit, kOpBlx, r7); 3387 3388 /* r1 = &retChainingCell */ 3389 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0); 3390 addrRetChain->generic.target = (LIR *) retChainingCell; 3391 3392 bypassRechaining->generic.target = (LIR *) addrRetChain; 3393 3394 /* 3395 * r0 = this, r1 = calleeMethod, 3396 * r1 = &ChainingCell, 3397 * r4PC = callsiteDPC, 3398 */ 3399 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 3400 TEMPLATE_INVOKE_METHOD_NO_OPT_PROF : 3401 TEMPLATE_INVOKE_METHOD_NO_OPT); 3402 #if defined(WITH_JIT_TUNING) 3403 gDvmJit.invokePolymorphic++; 3404 #endif 3405 /* Handle exceptions using the interpreter */ 3406 genTrap(cUnit, mir->offset, pcrLabel); 3407 break; 3408 } 3409 case OP_INVOKE_OBJECT_INIT_JUMBO: 3410 case OP_INVOKE_OBJECT_INIT_RANGE: 3411 case OP_FILLED_NEW_ARRAY: 3412 case OP_FILLED_NEW_ARRAY_RANGE: 3413 case OP_FILLED_NEW_ARRAY_JUMBO: { 3414 /* Just let the interpreter deal with these */ 3415 genInterpSingleStep(cUnit, mir); 3416 break; 3417 } 3418 default: 3419 return true; 3420 } 3421 return false; 3422 } 3423 3424 static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir, 3425 BasicBlock *bb, ArmLIR *labelList) 3426 { 3427 ArmLIR *pcrLabel = NULL; 3428 3429 /* An invoke with the MIR_INLINED is effectively a no-op */ 3430 if (mir->OptimizationFlags & MIR_INLINED) 3431 return false; 3432 3433 DecodedInstruction *dInsn = &mir->dalvikInsn; 3434 switch (mir->dalvikInsn.opcode) { 3435 /* calleeMethod = this->clazz->vtable[BBBB] */ 3436 case OP_INVOKE_VIRTUAL_QUICK_RANGE: 3437 case OP_INVOKE_VIRTUAL_QUICK: { 3438 int methodIndex = dInsn->vB; 3439 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id]; 3440 ArmLIR *predChainingCell = &labelList[bb->taken->id]; 3441 3442 /* 3443 * If the invoke has non-null misPredBranchOver, we need to generate 3444 * the non-inlined version of the invoke here to handle the 3445 * mispredicted case. 3446 */ 3447 if (mir->meta.callsiteInfo->misPredBranchOver) { 3448 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList); 3449 } 3450 3451 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL_QUICK) 3452 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3453 else 3454 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3455 3456 3457 if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) { 3458 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3459 void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns); 3460 assert(calleeAddr); 3461 genInvokeVirtualWholeMethod(cUnit, mir, calleeAddr, 3462 retChainingCell); 3463 } 3464 3465 genInvokeVirtualCommon(cUnit, mir, methodIndex, 3466 retChainingCell, 3467 predChainingCell, 3468 pcrLabel); 3469 break; 3470 } 3471 /* calleeMethod = method->clazz->super->vtable[BBBB] */ 3472 case OP_INVOKE_SUPER_QUICK: 3473 case OP_INVOKE_SUPER_QUICK_RANGE: { 3474 /* Grab the method ptr directly from what the interpreter sees */ 3475 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3476 assert(calleeMethod == 3477 cUnit->method->clazz->super->vtable[dInsn->vB]); 3478 3479 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER_QUICK) 3480 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3481 else 3482 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3483 3484 /* r0 = calleeMethod */ 3485 loadConstant(cUnit, r0, (int) calleeMethod); 3486 3487 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 3488 calleeMethod); 3489 break; 3490 } 3491 default: 3492 return true; 3493 } 3494 return false; 3495 } 3496 3497 /* 3498 * This operation is complex enough that we'll do it partly inline 3499 * and partly with a handler. NOTE: the handler uses hardcoded 3500 * values for string object offsets and must be revisitied if the 3501 * layout changes. 3502 */ 3503 static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir) 3504 { 3505 #if defined(USE_GLOBAL_STRING_DEFS) 3506 return handleExecuteInlineC(cUnit, mir); 3507 #else 3508 ArmLIR *rollback; 3509 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0); 3510 RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1); 3511 3512 loadValueDirectFixed(cUnit, rlThis, r0); 3513 loadValueDirectFixed(cUnit, rlComp, r1); 3514 /* Test objects for NULL */ 3515 rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL); 3516 genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback); 3517 /* 3518 * TUNING: we could check for object pointer equality before invoking 3519 * handler. Unclear whether the gain would be worth the added code size 3520 * expansion. 3521 */ 3522 genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO); 3523 storeValue(cUnit, inlinedTarget(cUnit, mir, false), 3524 dvmCompilerGetReturn(cUnit)); 3525 return false; 3526 #endif 3527 } 3528 3529 static bool genInlinedFastIndexOf(CompilationUnit *cUnit, MIR *mir) 3530 { 3531 #if defined(USE_GLOBAL_STRING_DEFS) 3532 return handleExecuteInlineC(cUnit, mir); 3533 #else 3534 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0); 3535 RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1); 3536 3537 loadValueDirectFixed(