CodegenDriver.cpp revision 2d0c1c2dbe44458ebb199c47ce1047f266db5349
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 */ 30static 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 47static 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 81static 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 127static 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 176static 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) 208static 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 */ 244static 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 */ 283static 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 */ 293static 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 */ 301static 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 */ 325static 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 */ 348static 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 */ 375static 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 */ 405static 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 */ 474static 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 */ 549static 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 632static 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 665static 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 bool checkZero = false; 674 void *callTgt; 675 int retReg = r0; 676 677 switch (mir->dalvikInsn.opcode) { 678 case OP_NOT_LONG: 679 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); 680 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 681 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg); 682 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg); 683 storeValueWide(cUnit, rlDest, rlResult); 684 return false; 685 break; 686 case OP_ADD_LONG: 687 case OP_ADD_LONG_2ADDR: 688 firstOp = kOpAdd; 689 secondOp = kOpAdc; 690 break; 691 case OP_SUB_LONG: 692 case OP_SUB_LONG_2ADDR: 693 firstOp = kOpSub; 694 secondOp = kOpSbc; 695 break; 696 case OP_MUL_LONG: 697 case OP_MUL_LONG_2ADDR: 698 genMulLong(cUnit, rlDest, rlSrc1, rlSrc2); 699 return false; 700 case OP_DIV_LONG: 701 case OP_DIV_LONG_2ADDR: 702 callOut = true; 703 retReg = r0; 704 checkZero = true; 705 callTgt = (void*)__aeabi_ldivmod; 706 break; 707 /* NOTE - result is in r2/r3 instead of r0/r1 */ 708 case OP_REM_LONG: 709 case OP_REM_LONG_2ADDR: 710 callOut = true; 711 callTgt = (void*)__aeabi_ldivmod; 712 retReg = r2; 713 checkZero = true; 714 break; 715 case OP_AND_LONG_2ADDR: 716 case OP_AND_LONG: 717 firstOp = kOpAnd; 718 secondOp = kOpAnd; 719 break; 720 case OP_OR_LONG: 721 case OP_OR_LONG_2ADDR: 722 firstOp = kOpOr; 723 secondOp = kOpOr; 724 break; 725 case OP_XOR_LONG: 726 case OP_XOR_LONG_2ADDR: 727 firstOp = kOpXor; 728 secondOp = kOpXor; 729 break; 730 case OP_NEG_LONG: { 731 //TUNING: can improve this using Thumb2 code 732 int tReg = dvmCompilerAllocTemp(cUnit); 733 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); 734 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 735 loadConstantNoClobber(cUnit, tReg, 0); 736 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, 737 tReg, rlSrc2.lowReg); 738 opRegReg(cUnit, kOpSbc, tReg, rlSrc2.highReg); 739 genRegCopy(cUnit, rlResult.highReg, tReg); 740 storeValueWide(cUnit, rlDest, rlResult); 741 return false; 742 } 743 default: 744 ALOGE("Invalid long arith op"); 745 dvmCompilerAbort(cUnit); 746 } 747 if (!callOut) { 748 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2); 749 } else { 750 // Adjust return regs in to handle case of rem returning r2/r3 751 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */ 752 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); 753 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); 754 LOAD_FUNC_ADDR(cUnit, r14lr, (int) callTgt); 755 if (checkZero) { 756 int tReg = r12; // Using fixed registers during call sequence 757 opRegRegReg(cUnit, kOpOr, tReg, r2, r3); 758 genRegImmCheck(cUnit, kArmCondEq, tReg, 0, mir->offset, NULL); 759 } 760 opReg(cUnit, kOpBlx, r14lr); 761 dvmCompilerClobberCallRegs(cUnit); 762 if (retReg == r0) 763 rlResult = dvmCompilerGetReturnWide(cUnit); 764 else 765 rlResult = dvmCompilerGetReturnWideAlt(cUnit); 766 storeValueWide(cUnit, rlDest, rlResult); 767#if defined(WITH_SELF_VERIFICATION) 768 cUnit->usesLinkRegister = true; 769#endif 770 } 771 return false; 772} 773 774static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, 775 RegLocation rlDest, RegLocation rlSrc1, 776 RegLocation rlSrc2) 777{ 778 OpKind op = kOpBkpt; 779 bool callOut = false; 780 bool checkZero = false; 781 bool unary = false; 782 int retReg = r0; 783 int (*callTgt)(int, int); 784 RegLocation rlResult; 785 bool shiftOp = false; 786 787 switch (mir->dalvikInsn.opcode) { 788 case OP_NEG_INT: 789 op = kOpNeg; 790 unary = true; 791 break; 792 case OP_NOT_INT: 793 op = kOpMvn; 794 unary = true; 795 break; 796 case OP_ADD_INT: 797 case OP_ADD_INT_2ADDR: 798 op = kOpAdd; 799 break; 800 case OP_SUB_INT: 801 case OP_SUB_INT_2ADDR: 802 op = kOpSub; 803 break; 804 case OP_MUL_INT: 805 case OP_MUL_INT_2ADDR: 806 op = kOpMul; 807 break; 808 case OP_DIV_INT: 809 case OP_DIV_INT_2ADDR: 810 callOut = true; 811 checkZero = true; 812 callTgt = __aeabi_idiv; 813 retReg = r0; 814 break; 815 /* NOTE: returns in r1 */ 816 case OP_REM_INT: 817 case OP_REM_INT_2ADDR: 818 callOut = true; 819 checkZero = true; 820 callTgt = __aeabi_idivmod; 821 retReg = r1; 822 break; 823 case OP_AND_INT: 824 case OP_AND_INT_2ADDR: 825 op = kOpAnd; 826 break; 827 case OP_OR_INT: 828 case OP_OR_INT_2ADDR: 829 op = kOpOr; 830 break; 831 case OP_XOR_INT: 832 case OP_XOR_INT_2ADDR: 833 op = kOpXor; 834 break; 835 case OP_SHL_INT: 836 case OP_SHL_INT_2ADDR: 837 shiftOp = true; 838 op = kOpLsl; 839 break; 840 case OP_SHR_INT: 841 case OP_SHR_INT_2ADDR: 842 shiftOp = true; 843 op = kOpAsr; 844 break; 845 case OP_USHR_INT: 846 case OP_USHR_INT_2ADDR: 847 shiftOp = true; 848 op = kOpLsr; 849 break; 850 default: 851 ALOGE("Invalid word arith op: %#x(%d)", 852 mir->dalvikInsn.opcode, mir->dalvikInsn.opcode); 853 dvmCompilerAbort(cUnit); 854 } 855 if (!callOut) { 856 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); 857 if (unary) { 858 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 859 opRegReg(cUnit, op, rlResult.lowReg, 860 rlSrc1.lowReg); 861 } else { 862 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); 863 if (shiftOp) { 864 int tReg = dvmCompilerAllocTemp(cUnit); 865 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31); 866 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 867 opRegRegReg(cUnit, op, rlResult.lowReg, 868 rlSrc1.lowReg, tReg); 869 dvmCompilerFreeTemp(cUnit, tReg); 870 } else { 871 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 872 opRegRegReg(cUnit, op, rlResult.lowReg, 873 rlSrc1.lowReg, rlSrc2.lowReg); 874 } 875 } 876 storeValue(cUnit, rlDest, rlResult); 877 } else { 878 RegLocation rlResult; 879 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */ 880 loadValueDirectFixed(cUnit, rlSrc2, r1); 881 LOAD_FUNC_ADDR(cUnit, r2, (int) callTgt); 882 loadValueDirectFixed(cUnit, rlSrc1, r0); 883 if (checkZero) { 884 genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL); 885 } 886 opReg(cUnit, kOpBlx, r2); 887 dvmCompilerClobberCallRegs(cUnit); 888 if (retReg == r0) 889 rlResult = dvmCompilerGetReturn(cUnit); 890 else 891 rlResult = dvmCompilerGetReturnAlt(cUnit); 892 storeValue(cUnit, rlDest, rlResult); 893 } 894 return false; 895} 896 897static bool genArithOp(CompilationUnit *cUnit, MIR *mir) 898{ 899 Opcode opcode = mir->dalvikInsn.opcode; 900 RegLocation rlDest; 901 RegLocation rlSrc1; 902 RegLocation rlSrc2; 903 /* Deduce sizes of operands */ 904 if (mir->ssaRep->numUses == 2) { 905 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0); 906 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1); 907 } else if (mir->ssaRep->numUses == 3) { 908 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 909 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2); 910 } else { 911 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 912 rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3); 913 assert(mir->ssaRep->numUses == 4); 914 } 915 if (mir->ssaRep->numDefs == 1) { 916 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 917 } else { 918 assert(mir->ssaRep->numDefs == 2); 919 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 920 } 921 922 if ((opcode >= OP_ADD_LONG_2ADDR) && (opcode <= OP_XOR_LONG_2ADDR)) { 923 return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2); 924 } 925 if ((opcode >= OP_ADD_LONG) && (opcode <= OP_XOR_LONG)) { 926 return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2); 927 } 928 if ((opcode >= OP_SHL_LONG_2ADDR) && (opcode <= OP_USHR_LONG_2ADDR)) { 929 return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2); 930 } 931 if ((opcode >= OP_SHL_LONG) && (opcode <= OP_USHR_LONG)) { 932 return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2); 933 } 934 if ((opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_USHR_INT_2ADDR)) { 935 return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2); 936 } 937 if ((opcode >= OP_ADD_INT) && (opcode <= OP_USHR_INT)) { 938 return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2); 939 } 940 if ((opcode >= OP_ADD_FLOAT_2ADDR) && (opcode <= OP_REM_FLOAT_2ADDR)) { 941 return genArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2); 942 } 943 if ((opcode >= OP_ADD_FLOAT) && (opcode <= OP_REM_FLOAT)) { 944 return genArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2); 945 } 946 if ((opcode >= OP_ADD_DOUBLE_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) { 947 return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2); 948 } 949 if ((opcode >= OP_ADD_DOUBLE) && (opcode <= OP_REM_DOUBLE)) { 950 return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2); 951 } 952 return true; 953} 954 955/* Generate unconditional branch instructions */ 956static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target) 957{ 958 ArmLIR *branch = opNone(cUnit, kOpUncondBr); 959 branch->generic.target = (LIR *) target; 960 return branch; 961} 962 963/* Perform the actual operation for OP_RETURN_* */ 964static void genReturnCommon(CompilationUnit *cUnit, MIR *mir) 965{ 966 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 967 TEMPLATE_RETURN_PROF : TEMPLATE_RETURN); 968#if defined(WITH_JIT_TUNING) 969 gDvmJit.returnOp++; 970#endif 971 int dPC = (int) (cUnit->method->insns + mir->offset); 972 /* Insert branch, but defer setting of target */ 973 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL); 974 /* Set up the place holder to reconstruct this Dalvik PC */ 975 ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); 976 pcrLabel->opcode = kArmPseudoPCReconstructionCell; 977 pcrLabel->operands[0] = dPC; 978 pcrLabel->operands[1] = mir->offset; 979 /* Insert the place holder to the growable list */ 980 dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel); 981 /* Branch to the PC reconstruction code */ 982 branch->generic.target = (LIR *) pcrLabel; 983} 984 985static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir, 986 DecodedInstruction *dInsn, 987 ArmLIR **pcrLabel) 988{ 989 unsigned int i; 990 unsigned int regMask = 0; 991 RegLocation rlArg; 992 int numDone = 0; 993 994 /* 995 * Load arguments to r0..r4. Note that these registers may contain 996 * live values, so we clobber them immediately after loading to prevent 997 * them from being used as sources for subsequent loads. 998 */ 999 dvmCompilerLockAllTemps(cUnit); 1000 for (i = 0; i < dInsn->vA; i++) { 1001 regMask |= 1 << i; 1002 rlArg = dvmCompilerGetSrc(cUnit, mir, numDone++); 1003 loadValueDirectFixed(cUnit, rlArg, i); 1004 } 1005 if (regMask) { 1006 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */ 1007 opRegRegImm(cUnit, kOpSub, r7, r5FP, 1008 sizeof(StackSaveArea) + (dInsn->vA << 2)); 1009 /* generate null check */ 1010 if (pcrLabel) { 1011 *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0, 1012 mir->offset, NULL); 1013 } 1014 storeMultiple(cUnit, r7, regMask); 1015 } 1016} 1017 1018static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir, 1019 DecodedInstruction *dInsn, 1020 ArmLIR **pcrLabel) 1021{ 1022 int srcOffset = dInsn->vC << 2; 1023 int numArgs = dInsn->vA; 1024 int regMask; 1025 1026 /* 1027 * Note: here, all promoted registers will have been flushed 1028 * back to the Dalvik base locations, so register usage restrictins 1029 * are lifted. All parms loaded from original Dalvik register 1030 * region - even though some might conceivably have valid copies 1031 * cached in a preserved register. 1032 */ 1033 dvmCompilerLockAllTemps(cUnit); 1034 1035 /* 1036 * r4PC : &r5FP[vC] 1037 * r7: &newFP[0] 1038 */ 1039 opRegRegImm(cUnit, kOpAdd, r4PC, r5FP, srcOffset); 1040 /* load [r0 .. min(numArgs,4)] */ 1041 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1; 1042 /* 1043 * Protect the loadMultiple instruction from being reordered with other 1044 * Dalvik stack accesses. 1045 */ 1046 if (numArgs != 0) loadMultiple(cUnit, r4PC, regMask); 1047 1048 opRegRegImm(cUnit, kOpSub, r7, r5FP, 1049 sizeof(StackSaveArea) + (numArgs << 2)); 1050 /* generate null check */ 1051 if (pcrLabel) { 1052 *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0, 1053 mir->offset, NULL); 1054 } 1055 1056 /* 1057 * Handle remaining 4n arguments: 1058 * store previously loaded 4 values and load the next 4 values 1059 */ 1060 if (numArgs >= 8) { 1061 ArmLIR *loopLabel = NULL; 1062 /* 1063 * r0 contains "this" and it will be used later, so push it to the stack 1064 * first. Pushing r5FP is just for stack alignment purposes. 1065 */ 1066 opImm(cUnit, kOpPush, (1 << r0 | 1 << r5FP)); 1067 /* No need to generate the loop structure if numArgs <= 11 */ 1068 if (numArgs > 11) { 1069 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2); 1070 loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel); 1071 loopLabel->defMask = ENCODE_ALL; 1072 } 1073 storeMultiple(cUnit, r7, regMask); 1074 /* 1075 * Protect the loadMultiple instruction from being reordered with other 1076 * Dalvik stack accesses. 1077 */ 1078 loadMultiple(cUnit, r4PC, regMask); 1079 /* No need to generate the loop structure if numArgs <= 11 */ 1080 if (numArgs > 11) { 1081 opRegImm(cUnit, kOpSub, r5FP, 4); 1082 genConditionalBranch(cUnit, kArmCondNe, loopLabel); 1083 } 1084 } 1085 1086 /* Save the last batch of loaded values */ 1087 if (numArgs != 0) storeMultiple(cUnit, r7, regMask); 1088 1089 /* Generate the loop epilogue - don't use r0 */ 1090 if ((numArgs > 4) && (numArgs % 4)) { 1091 regMask = ((1 << (numArgs & 0x3)) - 1) << 1; 1092 /* 1093 * Protect the loadMultiple instruction from being reordered with other 1094 * Dalvik stack accesses. 1095 */ 1096 loadMultiple(cUnit, r4PC, regMask); 1097 } 1098 if (numArgs >= 8) 1099 opImm(cUnit, kOpPop, (1 << r0 | 1 << r5FP)); 1100 1101 /* Save the modulo 4 arguments */ 1102 if ((numArgs > 4) && (numArgs % 4)) { 1103 storeMultiple(cUnit, r7, regMask); 1104 } 1105} 1106 1107/* 1108 * Generate code to setup the call stack then jump to the chaining cell if it 1109 * is not a native method. 1110 */ 1111static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir, 1112 BasicBlock *bb, ArmLIR *labelList, 1113 ArmLIR *pcrLabel, 1114 const Method *calleeMethod) 1115{ 1116 /* 1117 * Note: all Dalvik register state should be flushed to 1118 * memory by the point, so register usage restrictions no 1119 * longer apply. All temp & preserved registers may be used. 1120 */ 1121 dvmCompilerLockAllTemps(cUnit); 1122 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id]; 1123 1124 /* r1 = &retChainingCell */ 1125 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0); 1126 1127 /* r4PC = dalvikCallsite */ 1128 loadConstant(cUnit, r4PC, 1129 (int) (cUnit->method->insns + mir->offset)); 1130 addrRetChain->generic.target = (LIR *) retChainingCell; 1131 1132 /* r7 = calleeMethod->registersSize */ 1133 loadConstant(cUnit, r7, calleeMethod->registersSize); 1134 /* 1135 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon) 1136 * r1 = &ChainingCell 1137 * r2 = calleeMethod->outsSize (to be loaded later for Java callees) 1138 * r4PC = callsiteDPC 1139 * r7 = calleeMethod->registersSize 1140 */ 1141 if (dvmIsNativeMethod(calleeMethod)) { 1142 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 1143 TEMPLATE_INVOKE_METHOD_NATIVE_PROF : 1144 TEMPLATE_INVOKE_METHOD_NATIVE); 1145#if defined(WITH_JIT_TUNING) 1146 gDvmJit.invokeNative++; 1147#endif 1148 } else { 1149 /* For Java callees, set up r2 to be calleeMethod->outsSize */ 1150 loadConstant(cUnit, r2, calleeMethod->outsSize); 1151 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 1152 TEMPLATE_INVOKE_METHOD_CHAIN_PROF : 1153 TEMPLATE_INVOKE_METHOD_CHAIN); 1154#if defined(WITH_JIT_TUNING) 1155 gDvmJit.invokeMonomorphic++; 1156#endif 1157 /* Branch to the chaining cell */ 1158 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]); 1159 } 1160 /* Handle exceptions using the interpreter */ 1161 genTrap(cUnit, mir->offset, pcrLabel); 1162} 1163 1164/* 1165 * Generate code to check the validity of a predicted chain and take actions 1166 * based on the result. 1167 * 1168 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke 1169 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell 1170 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell 1171 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN 1172 * 0x426a99b2 : blx_2 see above --+ 1173 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain 1174 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter 1175 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx] 1176 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0 1177 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain 1178 * 0x426a99be : ldr r7, [pc, #off]--+ dvmJitToPatchPredictedChain 1179 * 0x426a99c0 : blx r7 --+ 1180 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell 1181 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT 1182 * 0x426a99c6 : blx_2 see above --+ 1183 */ 1184static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir, 1185 int methodIndex, 1186 ArmLIR *retChainingCell, 1187 ArmLIR *predChainingCell, 1188 ArmLIR *pcrLabel) 1189{ 1190 /* 1191 * Note: all Dalvik register state should be flushed to 1192 * memory by the point, so register usage restrictions no 1193 * longer apply. Lock temps to prevent them from being 1194 * allocated by utility routines. 1195 */ 1196 dvmCompilerLockAllTemps(cUnit); 1197 1198 /* 1199 * For verbose printing, store the method pointer in operands[1] first as 1200 * operands[0] will be clobbered in dvmCompilerMIR2LIR. 1201 */ 1202 predChainingCell->operands[1] = (int) mir->meta.callsiteInfo->method; 1203 1204 /* "this" is already left in r0 by genProcessArgs* */ 1205 1206 /* r4PC = dalvikCallsite */ 1207 loadConstant(cUnit, r4PC, 1208 (int) (cUnit->method->insns + mir->offset)); 1209 1210 /* r1 = &retChainingCell */ 1211 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0); 1212 addrRetChain->generic.target = (LIR *) retChainingCell; 1213 1214 /* r2 = &predictedChainingCell */ 1215 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, r15pc, 0); 1216 predictedChainingCell->generic.target = (LIR *) predChainingCell; 1217 1218 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 1219 TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF : 1220 TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN); 1221 1222 /* return through lr - jump to the chaining cell */ 1223 genUnconditionalBranch(cUnit, predChainingCell); 1224 1225 /* 1226 * null-check on "this" may have been eliminated, but we still need a PC- 1227 * reconstruction label for stack overflow bailout. 1228 */ 1229 if (pcrLabel == NULL) { 1230 int dPC = (int) (cUnit->method->insns + mir->offset); 1231 pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); 1232 pcrLabel->opcode = kArmPseudoPCReconstructionCell; 1233 pcrLabel->operands[0] = dPC; 1234 pcrLabel->operands[1] = mir->offset; 1235 /* Insert the place holder to the growable list */ 1236 dvmInsertGrowableList(&cUnit->pcReconstructionList, 1237 (intptr_t) pcrLabel); 1238 } 1239 1240 /* return through lr+2 - punt to the interpreter */ 1241 genUnconditionalBranch(cUnit, pcrLabel); 1242 1243 /* 1244 * return through lr+4 - fully resolve the callee method. 1245 * r1 <- count 1246 * r2 <- &predictedChainCell 1247 * r3 <- this->class 1248 * r4 <- dPC 1249 * r7 <- this->class->vtable 1250 */ 1251 1252 /* r0 <- calleeMethod */ 1253 loadWordDisp(cUnit, r7, methodIndex * 4, r0); 1254 1255 /* Check if rechain limit is reached */ 1256 ArmLIR *bypassRechaining = genCmpImmBranch(cUnit, kArmCondGt, r1, 0); 1257 1258 LOAD_FUNC_ADDR(cUnit, r7, (int) dvmJitToPatchPredictedChain); 1259 1260 genRegCopy(cUnit, r1, r6SELF); 1261 1262 /* 1263 * r0 = calleeMethod 1264 * r2 = &predictedChainingCell 1265 * r3 = class 1266 * 1267 * &returnChainingCell has been loaded into r1 but is not needed 1268 * when patching the chaining cell and will be clobbered upon 1269 * returning so it will be reconstructed again. 1270 */ 1271 opReg(cUnit, kOpBlx, r7); 1272 1273 /* r1 = &retChainingCell */ 1274 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0); 1275 addrRetChain->generic.target = (LIR *) retChainingCell; 1276 1277 bypassRechaining->generic.target = (LIR *) addrRetChain; 1278 /* 1279 * r0 = calleeMethod, 1280 * r1 = &ChainingCell, 1281 * r4PC = callsiteDPC, 1282 */ 1283 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 1284 TEMPLATE_INVOKE_METHOD_NO_OPT_PROF : 1285 TEMPLATE_INVOKE_METHOD_NO_OPT); 1286#if defined(WITH_JIT_TUNING) 1287 gDvmJit.invokePolymorphic++; 1288#endif 1289 /* Handle exceptions using the interpreter */ 1290 genTrap(cUnit, mir->offset, pcrLabel); 1291} 1292 1293/* "this" pointer is already in r0 */ 1294static void genInvokeVirtualWholeMethod(CompilationUnit *cUnit, 1295 MIR *mir, 1296 void *calleeAddr, 1297 ArmLIR *retChainingCell) 1298{ 1299 CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo; 1300 dvmCompilerLockAllTemps(cUnit); 1301 1302 loadClassPointer(cUnit, r1, (int) callsiteInfo); 1303 1304 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r2); 1305 /* Branch to the slow path if classes are not equal */ 1306 opRegReg(cUnit, kOpCmp, r1, r2); 1307 /* 1308 * Set the misPredBranchOver target so that it will be generated when the 1309 * code for the non-optimized invoke is generated. 1310 */ 1311 ArmLIR *classCheck = opCondBranch(cUnit, kArmCondNe); 1312 1313 /* r0 = the Dalvik PC of the callsite */ 1314 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset)); 1315 1316 newLIR2(cUnit, kThumbBl1, (int) calleeAddr, (int) calleeAddr); 1317 newLIR2(cUnit, kThumbBl2, (int) calleeAddr, (int) calleeAddr); 1318 genUnconditionalBranch(cUnit, retChainingCell); 1319 1320 /* Target of slow path */ 1321 ArmLIR *slowPathLabel = newLIR0(cUnit, kArmPseudoTargetLabel); 1322 1323 slowPathLabel->defMask = ENCODE_ALL; 1324 classCheck->generic.target = (LIR *) slowPathLabel; 1325 1326 // FIXME 1327 cUnit->printMe = true; 1328} 1329 1330static void genInvokeSingletonWholeMethod(CompilationUnit *cUnit, 1331 MIR *mir, 1332 void *calleeAddr, 1333 ArmLIR *retChainingCell) 1334{ 1335 /* r0 = the Dalvik PC of the callsite */ 1336 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset)); 1337 1338 newLIR2(cUnit, kThumbBl1, (int) calleeAddr, (int) calleeAddr); 1339 newLIR2(cUnit, kThumbBl2, (int) calleeAddr, (int) calleeAddr); 1340 genUnconditionalBranch(cUnit, retChainingCell); 1341 1342 // FIXME 1343 cUnit->printMe = true; 1344} 1345 1346/* Geneate a branch to go back to the interpreter */ 1347static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset) 1348{ 1349 /* r0 = dalvik pc */ 1350 dvmCompilerFlushAllRegs(cUnit); 1351 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset)); 1352 loadWordDisp(cUnit, r6SELF, offsetof(Thread, 1353 jitToInterpEntries.dvmJitToInterpPunt), r1); 1354 opReg(cUnit, kOpBlx, r1); 1355} 1356 1357/* 1358 * Attempt to single step one instruction using the interpreter and return 1359 * to the compiled code for the next Dalvik instruction 1360 */ 1361static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir) 1362{ 1363 int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode); 1364 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn; 1365 1366 // Single stepping is considered loop mode breaker 1367 if (cUnit->jitMode == kJitLoop) { 1368 cUnit->quitLoopMode = true; 1369 return; 1370 } 1371 1372 //If already optimized out, just ignore 1373 if (mir->dalvikInsn.opcode == OP_NOP) 1374 return; 1375 1376 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them 1377 dvmCompilerFlushAllRegs(cUnit); 1378 1379 if ((mir->next == NULL) || (flags & flagsToCheck)) { 1380 genPuntToInterp(cUnit, mir->offset); 1381 return; 1382 } 1383 int entryAddr = offsetof(Thread, 1384 jitToInterpEntries.dvmJitToInterpSingleStep); 1385 loadWordDisp(cUnit, r6SELF, entryAddr, r2); 1386 /* r0 = dalvik pc */ 1387 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset)); 1388 /* r1 = dalvik pc of following instruction */ 1389 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset)); 1390 opReg(cUnit, kOpBlx, r2); 1391} 1392 1393#if defined(_ARMV5TE) || defined(_ARMV5TE_VFP) 1394/* 1395 * To prevent a thread in a monitor wait from blocking the Jit from 1396 * resetting the code cache, heavyweight monitor lock will not 1397 * be allowed to return to an existing translation. Instead, we will 1398 * handle them by branching to a handler, which will in turn call the 1399 * runtime lock routine and then branch directly back to the 1400 * interpreter main loop. Given the high cost of the heavyweight 1401 * lock operation, this additional cost should be slight (especially when 1402 * considering that we expect the vast majority of lock operations to 1403 * use the fast-path thin lock bypass). 1404 */ 1405static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir) 1406{ 1407 bool isEnter = (mir->dalvikInsn.opcode == OP_MONITOR_ENTER); 1408 genExportPC(cUnit, mir); 1409 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */ 1410 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1411 loadValueDirectFixed(cUnit, rlSrc, r1); 1412 genRegCopy(cUnit, r0, r6SELF); 1413 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL); 1414 if (isEnter) { 1415 /* Get dPC of next insn */ 1416 loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset + 1417 dexGetWidthFromOpcode(OP_MONITOR_ENTER))); 1418 genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER); 1419 } else { 1420 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmUnlockObject); 1421 /* Do the call */ 1422 opReg(cUnit, kOpBlx, r2); 1423 /* Did we throw? */ 1424 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 1425 loadConstant(cUnit, r0, 1426 (int) (cUnit->method->insns + mir->offset + 1427 dexGetWidthFromOpcode(OP_MONITOR_EXIT))); 1428 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 1429 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 1430 target->defMask = ENCODE_ALL; 1431 branchOver->generic.target = (LIR *) target; 1432 dvmCompilerClobberCallRegs(cUnit); 1433 } 1434} 1435#endif 1436 1437/* 1438 * Fetch *self->info.breakFlags. If the breakFlags are non-zero, 1439 * punt to the interpreter. 1440 */ 1441static void genSuspendPoll(CompilationUnit *cUnit, MIR *mir) 1442{ 1443 int rTemp = dvmCompilerAllocTemp(cUnit); 1444 ArmLIR *ld; 1445 ld = loadBaseDisp(cUnit, NULL, r6SELF, 1446 offsetof(Thread, interpBreak.ctl.breakFlags), 1447 rTemp, kUnsignedByte, INVALID_SREG); 1448 setMemRefType(ld, true /* isLoad */, kMustNotAlias); 1449 genRegImmCheck(cUnit, kArmCondNe, rTemp, 0, mir->offset, NULL); 1450} 1451 1452/* 1453 * The following are the first-level codegen routines that analyze the format 1454 * of each bytecode then either dispatch special purpose codegen routines 1455 * or produce corresponding Thumb instructions directly. 1456 */ 1457 1458static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir, 1459 BasicBlock *bb, ArmLIR *labelList) 1460{ 1461 /* backward branch? */ 1462 bool backwardBranch = (bb->taken->startOffset <= mir->offset); 1463 1464 if (backwardBranch && 1465 (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) { 1466 genSuspendPoll(cUnit, mir); 1467 } 1468 1469 int numPredecessors = dvmCountSetBits(bb->taken->predecessors); 1470 /* 1471 * Things could be hoisted out of the taken block into the predecessor, so 1472 * make sure it is dominated by the predecessor. 1473 */ 1474 if (numPredecessors == 1 && bb->taken->visited == false && 1475 bb->taken->blockType == kDalvikByteCode) { 1476 cUnit->nextCodegenBlock = bb->taken; 1477 } else { 1478 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */ 1479 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]); 1480 } 1481 return false; 1482} 1483 1484static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir) 1485{ 1486 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 1487 if ((dalvikOpcode >= OP_UNUSED_3E) && (dalvikOpcode <= OP_UNUSED_43)) { 1488 ALOGE("Codegen: got unused opcode %#x",dalvikOpcode); 1489 return true; 1490 } 1491 switch (dalvikOpcode) { 1492 case OP_RETURN_VOID_BARRIER: 1493 dvmCompilerGenMemBarrier(cUnit, kST); 1494 // Intentional fallthrough 1495 case OP_RETURN_VOID: 1496 genReturnCommon(cUnit,mir); 1497 break; 1498 case OP_UNUSED_73: 1499 case OP_UNUSED_79: 1500 case OP_UNUSED_7A: 1501 case OP_UNUSED_FF: 1502 ALOGE("Codegen: got unused opcode %#x",dalvikOpcode); 1503 return true; 1504 case OP_NOP: 1505 break; 1506 default: 1507 return true; 1508 } 1509 return false; 1510} 1511 1512static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir) 1513{ 1514 RegLocation rlDest; 1515 RegLocation rlResult; 1516 if (mir->ssaRep->numDefs == 2) { 1517 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1518 } else { 1519 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1520 } 1521 1522 switch (mir->dalvikInsn.opcode) { 1523 case OP_CONST: 1524 case OP_CONST_4: { 1525 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1526 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB); 1527 storeValue(cUnit, rlDest, rlResult); 1528 break; 1529 } 1530 case OP_CONST_WIDE_32: { 1531 //TUNING: single routine to load constant pair for support doubles 1532 //TUNING: load 0/-1 separately to avoid load dependency 1533 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1534 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB); 1535 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, 1536 rlResult.lowReg, 31); 1537 storeValueWide(cUnit, rlDest, rlResult); 1538 break; 1539 } 1540 default: 1541 return true; 1542 } 1543 return false; 1544} 1545 1546static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir) 1547{ 1548 RegLocation rlDest; 1549 RegLocation rlResult; 1550 if (mir->ssaRep->numDefs == 2) { 1551 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1552 } else { 1553 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1554 } 1555 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1556 1557 switch (mir->dalvikInsn.opcode) { 1558 case OP_CONST_HIGH16: { 1559 loadConstantNoClobber(cUnit, rlResult.lowReg, 1560 mir->dalvikInsn.vB << 16); 1561 storeValue(cUnit, rlDest, rlResult); 1562 break; 1563 } 1564 case OP_CONST_WIDE_HIGH16: { 1565 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg, 1566 0, mir->dalvikInsn.vB << 16); 1567 storeValueWide(cUnit, rlDest, rlResult); 1568 break; 1569 } 1570 default: 1571 return true; 1572 } 1573 return false; 1574} 1575 1576static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir) 1577{ 1578 /* For OP_THROW_VERIFICATION_ERROR */ 1579 genInterpSingleStep(cUnit, mir); 1580 return false; 1581} 1582 1583static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir) 1584{ 1585 RegLocation rlResult; 1586 RegLocation rlDest; 1587 RegLocation rlSrc; 1588 1589 switch (mir->dalvikInsn.opcode) { 1590 case OP_CONST_STRING_JUMBO: 1591 case OP_CONST_STRING: { 1592 void *strPtr = (void*) 1593 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]); 1594 1595 if (strPtr == NULL) { 1596 BAIL_LOOP_COMPILATION(); 1597 ALOGE("Unexpected null string"); 1598 dvmAbort(); 1599 } 1600 1601 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1602 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1603 loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr ); 1604 storeValue(cUnit, rlDest, rlResult); 1605 break; 1606 } 1607 case OP_CONST_CLASS: { 1608 void *classPtr = (void*) 1609 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]); 1610 1611 if (classPtr == NULL) { 1612 BAIL_LOOP_COMPILATION(); 1613 ALOGE("Unexpected null class"); 1614 dvmAbort(); 1615 } 1616 1617 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1618 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1619 loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr ); 1620 storeValue(cUnit, rlDest, rlResult); 1621 break; 1622 } 1623 case OP_SGET: 1624 case OP_SGET_VOLATILE: 1625 case OP_SGET_OBJECT: 1626 case OP_SGET_OBJECT_VOLATILE: 1627 case OP_SGET_BOOLEAN: 1628 case OP_SGET_CHAR: 1629 case OP_SGET_BYTE: 1630 case OP_SGET_SHORT: { 1631 int valOffset = OFFSETOF_MEMBER(StaticField, value); 1632 int tReg = dvmCompilerAllocTemp(cUnit); 1633 bool isVolatile; 1634 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1635 mir->meta.calleeMethod : cUnit->method; 1636 void *fieldPtr = (void*) 1637 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1638 1639 if (fieldPtr == NULL) { 1640 BAIL_LOOP_COMPILATION(); 1641 ALOGE("Unexpected null static field"); 1642 dvmAbort(); 1643 } 1644 1645 /* 1646 * On SMP systems, Dalvik opcodes found to be referencing 1647 * volatile fields are rewritten to their _VOLATILE variant. 1648 * However, this does not happen on non-SMP systems. The JIT 1649 * still needs to know about volatility to avoid unsafe 1650 * optimizations so we determine volatility based on either 1651 * the opcode or the field access flags. 1652 */ 1653#if ANDROID_SMP != 0 1654 Opcode opcode = mir->dalvikInsn.opcode; 1655 isVolatile = (opcode == OP_SGET_VOLATILE) || 1656 (opcode == OP_SGET_OBJECT_VOLATILE); 1657 assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr)); 1658#else 1659 isVolatile = dvmIsVolatileField((Field *) fieldPtr); 1660#endif 1661 1662 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1663 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1664 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset); 1665 1666 if (isVolatile) { 1667 dvmCompilerGenMemBarrier(cUnit, kSY); 1668 } 1669 HEAP_ACCESS_SHADOW(true); 1670 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg); 1671 HEAP_ACCESS_SHADOW(false); 1672 1673 storeValue(cUnit, rlDest, rlResult); 1674 break; 1675 } 1676 case OP_SGET_WIDE: { 1677 int valOffset = OFFSETOF_MEMBER(StaticField, value); 1678 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1679 mir->meta.calleeMethod : cUnit->method; 1680 void *fieldPtr = (void*) 1681 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1682 1683 if (fieldPtr == NULL) { 1684 BAIL_LOOP_COMPILATION(); 1685 ALOGE("Unexpected null static field"); 1686 dvmAbort(); 1687 } 1688 1689 int tReg = dvmCompilerAllocTemp(cUnit); 1690 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1691 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1692 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset); 1693 1694 HEAP_ACCESS_SHADOW(true); 1695 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg); 1696 HEAP_ACCESS_SHADOW(false); 1697 1698 storeValueWide(cUnit, rlDest, rlResult); 1699 break; 1700 } 1701 case OP_SPUT: 1702 case OP_SPUT_VOLATILE: 1703 case OP_SPUT_OBJECT: 1704 case OP_SPUT_OBJECT_VOLATILE: 1705 case OP_SPUT_BOOLEAN: 1706 case OP_SPUT_CHAR: 1707 case OP_SPUT_BYTE: 1708 case OP_SPUT_SHORT: { 1709 int valOffset = OFFSETOF_MEMBER(StaticField, value); 1710 int tReg = dvmCompilerAllocTemp(cUnit); 1711 int objHead; 1712 bool isVolatile; 1713 bool isSputObject; 1714 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1715 mir->meta.calleeMethod : cUnit->method; 1716 void *fieldPtr = (void*) 1717 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1718 Opcode opcode = mir->dalvikInsn.opcode; 1719 1720 if (fieldPtr == NULL) { 1721 BAIL_LOOP_COMPILATION(); 1722 ALOGE("Unexpected null static field"); 1723 dvmAbort(); 1724 } 1725 1726#if ANDROID_SMP != 0 1727 isVolatile = (opcode == OP_SPUT_VOLATILE) || 1728 (opcode == OP_SPUT_OBJECT_VOLATILE); 1729 assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr)); 1730#else 1731 isVolatile = dvmIsVolatileField((Field *) fieldPtr); 1732#endif 1733 1734 isSputObject = (opcode == OP_SPUT_OBJECT) || 1735 (opcode == OP_SPUT_OBJECT_VOLATILE); 1736 1737 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1738 rlSrc = loadValue(cUnit, rlSrc, kAnyReg); 1739 loadConstant(cUnit, tReg, (int) fieldPtr); 1740 if (isSputObject) { 1741 objHead = dvmCompilerAllocTemp(cUnit); 1742 loadWordDisp(cUnit, tReg, OFFSETOF_MEMBER(Field, clazz), objHead); 1743 } 1744 if (isVolatile) { 1745 dvmCompilerGenMemBarrier(cUnit, kST); 1746 } 1747 HEAP_ACCESS_SHADOW(true); 1748 storeWordDisp(cUnit, tReg, valOffset ,rlSrc.lowReg); 1749 dvmCompilerFreeTemp(cUnit, tReg); 1750 HEAP_ACCESS_SHADOW(false); 1751 if (isVolatile) { 1752 dvmCompilerGenMemBarrier(cUnit, kSY); 1753 } 1754 if (isSputObject) { 1755 /* NOTE: marking card based sfield->clazz */ 1756 markCard(cUnit, rlSrc.lowReg, objHead); 1757 dvmCompilerFreeTemp(cUnit, objHead); 1758 } 1759 1760 break; 1761 } 1762 case OP_SPUT_WIDE: { 1763 int tReg = dvmCompilerAllocTemp(cUnit); 1764 int valOffset = OFFSETOF_MEMBER(StaticField, value); 1765 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1766 mir->meta.calleeMethod : cUnit->method; 1767 void *fieldPtr = (void*) 1768 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1769 1770 if (fieldPtr == NULL) { 1771 BAIL_LOOP_COMPILATION(); 1772 ALOGE("Unexpected null static field"); 1773 dvmAbort(); 1774 } 1775 1776 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 1777 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg); 1778 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset); 1779 1780 HEAP_ACCESS_SHADOW(true); 1781 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg); 1782 HEAP_ACCESS_SHADOW(false); 1783 break; 1784 } 1785 case OP_NEW_INSTANCE: { 1786 /* 1787 * Obey the calling convention and don't mess with the register 1788 * usage. 1789 */ 1790 ClassObject *classPtr = (ClassObject *) 1791 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]); 1792 1793 if (classPtr == NULL) { 1794 BAIL_LOOP_COMPILATION(); 1795 ALOGE("Unexpected null class"); 1796 dvmAbort(); 1797 } 1798 1799 /* 1800 * If it is going to throw, it should not make to the trace to begin 1801 * with. However, Alloc might throw, so we need to genExportPC() 1802 */ 1803 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0); 1804 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 1805 genExportPC(cUnit, mir); 1806 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmAllocObject); 1807 loadConstant(cUnit, r0, (int) classPtr); 1808 loadConstant(cUnit, r1, ALLOC_DONT_TRACK); 1809 opReg(cUnit, kOpBlx, r2); 1810 dvmCompilerClobberCallRegs(cUnit); 1811 /* generate a branch over if allocation is successful */ 1812 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 1813 /* 1814 * OOM exception needs to be thrown here and cannot re-execute 1815 */ 1816 loadConstant(cUnit, r0, 1817 (int) (cUnit->method->insns + mir->offset)); 1818 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 1819 /* noreturn */ 1820 1821 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 1822 target->defMask = ENCODE_ALL; 1823 branchOver->generic.target = (LIR *) target; 1824 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1825 rlResult = dvmCompilerGetReturn(cUnit); 1826 storeValue(cUnit, rlDest, rlResult); 1827 break; 1828 } 1829 case OP_CHECK_CAST: { 1830 /* 1831 * Obey the calling convention and don't mess with the register 1832 * usage. 1833 */ 1834 ClassObject *classPtr = 1835 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]); 1836 /* 1837 * Note: It is possible that classPtr is NULL at this point, 1838 * even though this instruction has been successfully interpreted. 1839 * If the previous interpretation had a null source, the 1840 * interpreter would not have bothered to resolve the clazz. 1841 * Bail out to the interpreter in this case, and log it 1842 * so that we can tell if it happens frequently. 1843 */ 1844 if (classPtr == NULL) { 1845 BAIL_LOOP_COMPILATION(); 1846 LOGVV("null clazz in OP_CHECK_CAST, single-stepping"); 1847 genInterpSingleStep(cUnit, mir); 1848 return false; 1849 } 1850 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 1851 loadConstant(cUnit, r1, (int) classPtr ); 1852 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1853 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 1854 /* Null? */ 1855 ArmLIR *branch1 = genCmpImmBranch(cUnit, kArmCondEq, 1856 rlSrc.lowReg, 0); 1857 /* 1858 * rlSrc.lowReg now contains object->clazz. Note that 1859 * it could have been allocated r0, but we're okay so long 1860 * as we don't do anything desctructive until r0 is loaded 1861 * with clazz. 1862 */ 1863 /* r0 now contains object->clazz */ 1864 loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0); 1865 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInstanceofNonTrivial); 1866 opRegReg(cUnit, kOpCmp, r0, r1); 1867 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq); 1868 opReg(cUnit, kOpBlx, r2); 1869 dvmCompilerClobberCallRegs(cUnit); 1870 /* 1871 * If null, check cast failed - punt to the interpreter. Because 1872 * interpreter will be the one throwing, we don't need to 1873 * genExportPC() here. 1874 */ 1875 genZeroCheck(cUnit, r0, mir->offset, NULL); 1876 /* check cast passed - branch target here */ 1877 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 1878 target->defMask = ENCODE_ALL; 1879 branch1->generic.target = (LIR *)target; 1880 branch2->generic.target = (LIR *)target; 1881 break; 1882 } 1883 case OP_SGET_WIDE_VOLATILE: 1884 case OP_SPUT_WIDE_VOLATILE: 1885 genInterpSingleStep(cUnit, mir); 1886 break; 1887 default: 1888 return true; 1889 } 1890 return false; 1891} 1892 1893/* 1894 * A typical example of inlined getter/setter from a monomorphic callsite: 1895 * 1896 * D/dalvikvm( 289): -------- dalvik offset: 0x0000 @ invoke-static (I) 1897 * D/dalvikvm( 289): -------- dalvik offset: 0x0000 @ sget-object (C) v0, ... 1898 * D/dalvikvm( 289): 0x4427fc22 (0002): ldr r0, [pc, #56] 1899 * D/dalvikvm( 289): 0x4427fc24 (0004): ldr r1, [r0, #0] 1900 * D/dalvikvm( 289): 0x4427fc26 (0006): str r1, [r5, #0] 1901 * D/dalvikvm( 289): 0x4427fc28 (0008): .align4 1902 * D/dalvikvm( 289): L0x0003: 1903 * D/dalvikvm( 289): -------- dalvik offset: 0x0003 @ move-result-object (I) v0 1904 * 1905 * Note the invoke-static and move-result-object with the (I) notation are 1906 * turned into no-op. 1907 */ 1908static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir) 1909{ 1910 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 1911 RegLocation rlResult; 1912 switch (dalvikOpcode) { 1913 case OP_MOVE_EXCEPTION: { 1914 int exOffset = offsetof(Thread, exception); 1915 int resetReg = dvmCompilerAllocTemp(cUnit); 1916 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1917 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1918 loadWordDisp(cUnit, r6SELF, exOffset, rlResult.lowReg); 1919 loadConstant(cUnit, resetReg, 0); 1920 storeWordDisp(cUnit, r6SELF, exOffset, resetReg); 1921 storeValue(cUnit, rlDest, rlResult); 1922 break; 1923 } 1924 case OP_MOVE_RESULT: 1925 case OP_MOVE_RESULT_OBJECT: { 1926 /* An inlined move result is effectively no-op */ 1927 if (mir->OptimizationFlags & MIR_INLINED) 1928 break; 1929 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1930 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL; 1931 rlSrc.fp = rlDest.fp; 1932 storeValue(cUnit, rlDest, rlSrc); 1933 break; 1934 } 1935 case OP_MOVE_RESULT_WIDE: { 1936 /* An inlined move result is effectively no-op */ 1937 if (mir->OptimizationFlags & MIR_INLINED) 1938 break; 1939 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1940 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE; 1941 rlSrc.fp = rlDest.fp; 1942 storeValueWide(cUnit, rlDest, rlSrc); 1943 break; 1944 } 1945 case OP_RETURN_WIDE: { 1946 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 1947 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE; 1948 rlDest.fp = rlSrc.fp; 1949 storeValueWide(cUnit, rlDest, rlSrc); 1950 genReturnCommon(cUnit,mir); 1951 break; 1952 } 1953 case OP_RETURN: 1954 case OP_RETURN_OBJECT: { 1955 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1956 RegLocation rlDest = LOC_DALVIK_RETURN_VAL; 1957 rlDest.fp = rlSrc.fp; 1958 storeValue(cUnit, rlDest, rlSrc); 1959 genReturnCommon(cUnit, mir); 1960 break; 1961 } 1962 case OP_MONITOR_EXIT: 1963 case OP_MONITOR_ENTER: 1964 genMonitor(cUnit, mir); 1965 break; 1966 case OP_THROW: 1967 genInterpSingleStep(cUnit, mir); 1968 break; 1969 default: 1970 return true; 1971 } 1972 return false; 1973} 1974 1975static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir) 1976{ 1977 Opcode opcode = mir->dalvikInsn.opcode; 1978 RegLocation rlDest; 1979 RegLocation rlSrc; 1980 RegLocation rlResult; 1981 1982 if ( (opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) { 1983 return genArithOp( cUnit, mir ); 1984 } 1985 1986 if (mir->ssaRep->numUses == 2) 1987 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 1988 else 1989 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1990 if (mir->ssaRep->numDefs == 2) 1991 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1992 else 1993 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1994 1995 switch (opcode) { 1996 case OP_DOUBLE_TO_INT: 1997 case OP_INT_TO_FLOAT: 1998 case OP_FLOAT_TO_INT: 1999 case OP_DOUBLE_TO_FLOAT: 2000 case OP_FLOAT_TO_DOUBLE: 2001 case OP_INT_TO_DOUBLE: 2002 case OP_FLOAT_TO_LONG: 2003 case OP_LONG_TO_FLOAT: 2004 case OP_DOUBLE_TO_LONG: 2005 case OP_LONG_TO_DOUBLE: 2006 return genConversion(cUnit, mir); 2007 case OP_NEG_INT: 2008 case OP_NOT_INT: 2009 return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc); 2010 case OP_NEG_LONG: 2011 case OP_NOT_LONG: 2012 return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc); 2013 case OP_NEG_FLOAT: 2014 return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc); 2015 case OP_NEG_DOUBLE: 2016 return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc); 2017 case OP_MOVE_WIDE: 2018 storeValueWide(cUnit, rlDest, rlSrc); 2019 break; 2020 case OP_INT_TO_LONG: 2021 rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc); 2022 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2023 //TUNING: shouldn't loadValueDirect already check for phys reg? 2024 if (rlSrc.location == kLocPhysReg) { 2025 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); 2026 } else { 2027 loadValueDirect(cUnit, rlSrc, rlResult.lowReg); 2028 } 2029 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, 2030 rlResult.lowReg, 31); 2031 storeValueWide(cUnit, rlDest, rlResult); 2032 break; 2033 case OP_LONG_TO_INT: 2034 rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc); 2035 rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc); 2036 // Intentional fallthrough 2037 case OP_MOVE: 2038 case OP_MOVE_OBJECT: 2039 storeValue(cUnit, rlDest, rlSrc); 2040 break; 2041 case OP_INT_TO_BYTE: 2042 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2043 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2044 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg); 2045 storeValue(cUnit, rlDest, rlResult); 2046 break; 2047 case OP_INT_TO_SHORT: 2048 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2049 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2050 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg); 2051 storeValue(cUnit, rlDest, rlResult); 2052 break; 2053 case OP_INT_TO_CHAR: 2054 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2055 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2056 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg); 2057 storeValue(cUnit, rlDest, rlResult); 2058 break; 2059 case OP_ARRAY_LENGTH: { 2060 int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); 2061 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2062 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg, 2063 mir->offset, NULL); 2064 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2065 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset, 2066 rlResult.lowReg); 2067 storeValue(cUnit, rlDest, rlResult); 2068 break; 2069 } 2070 default: 2071 return true; 2072 } 2073 return false; 2074} 2075 2076static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir) 2077{ 2078 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2079 RegLocation rlDest; 2080 RegLocation rlResult; 2081 int BBBB = mir->dalvikInsn.vB; 2082 if (dalvikOpcode == OP_CONST_WIDE_16) { 2083 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 2084 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2085 loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB); 2086 //TUNING: do high separately to avoid load dependency 2087 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31); 2088 storeValueWide(cUnit, rlDest, rlResult); 2089 } else if (dalvikOpcode == OP_CONST_16) { 2090 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2091 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 2092 loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB); 2093 storeValue(cUnit, rlDest, rlResult); 2094 } else 2095 return true; 2096 return false; 2097} 2098 2099/* Compare agaist zero */ 2100static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 2101 ArmLIR *labelList) 2102{ 2103 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2104 ArmConditionCode cond; 2105 /* backward branch? */ 2106 bool backwardBranch = (bb->taken->startOffset <= mir->offset); 2107 2108 if (backwardBranch && 2109 (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) { 2110 genSuspendPoll(cUnit, mir); 2111 } 2112 2113 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2114 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2115 2116 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); 2117 2118//TUNING: break this out to allow use of Thumb2 CB[N]Z 2119 switch (dalvikOpcode) { 2120 case OP_IF_EQZ: 2121 cond = kArmCondEq; 2122 break; 2123 case OP_IF_NEZ: 2124 cond = kArmCondNe; 2125 break; 2126 case OP_IF_LTZ: 2127 cond = kArmCondLt; 2128 break; 2129 case OP_IF_GEZ: 2130 cond = kArmCondGe; 2131 break; 2132 case OP_IF_GTZ: 2133 cond = kArmCondGt; 2134 break; 2135 case OP_IF_LEZ: 2136 cond = kArmCondLe; 2137 break; 2138 default: 2139 cond = (ArmConditionCode)0; 2140 ALOGE("Unexpected opcode (%d) for Fmt21t", dalvikOpcode); 2141 dvmCompilerAbort(cUnit); 2142 } 2143 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]); 2144 /* This mostly likely will be optimized away in a later phase */ 2145 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); 2146 return false; 2147} 2148 2149static bool isPowerOfTwo(int x) 2150{ 2151 return (x & (x - 1)) == 0; 2152} 2153 2154// Returns true if no more than two bits are set in 'x'. 2155static bool isPopCountLE2(unsigned int x) 2156{ 2157 x &= x - 1; 2158 return (x & (x - 1)) == 0; 2159} 2160 2161// Returns the index of the lowest set bit in 'x'. 2162static int lowestSetBit(unsigned int x) { 2163 int bit_posn = 0; 2164 while ((x & 0xf) == 0) { 2165 bit_posn += 4; 2166 x >>= 4; 2167 } 2168 while ((x & 1) == 0) { 2169 bit_posn++; 2170 x >>= 1; 2171 } 2172 return bit_posn; 2173} 2174 2175// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit' 2176// and store the result in 'rlDest'. 2177static bool handleEasyDivide(CompilationUnit *cUnit, Opcode dalvikOpcode, 2178 RegLocation rlSrc, RegLocation rlDest, int lit) 2179{ 2180 if (lit < 2 || !isPowerOfTwo(lit)) { 2181 return false; 2182 } 2183 int k = lowestSetBit(lit); 2184 if (k >= 30) { 2185 // Avoid special cases. 2186 return false; 2187 } 2188 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 || dalvikOpcode == OP_DIV_INT_LIT16); 2189 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2190 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2191 if (div) { 2192 int tReg = dvmCompilerAllocTemp(cUnit); 2193 if (lit == 2) { 2194 // Division by 2 is by far the most common division by constant. 2195 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k); 2196 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg); 2197 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k); 2198 } else { 2199 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31); 2200 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k); 2201 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg); 2202 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k); 2203 } 2204 } else { 2205 int cReg = dvmCompilerAllocTemp(cUnit); 2206 loadConstant(cUnit, cReg, lit - 1); 2207 int tReg1 = dvmCompilerAllocTemp(cUnit); 2208 int tReg2 = dvmCompilerAllocTemp(cUnit); 2209 if (lit == 2) { 2210 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k); 2211 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg); 2212 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg); 2213 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1); 2214 } else { 2215 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31); 2216 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k); 2217 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg); 2218 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg); 2219 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1); 2220 } 2221 } 2222 storeValue(cUnit, rlDest, rlResult); 2223 return true; 2224} 2225 2226// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit' 2227// and store the result in 'rlDest'. 2228static bool handleEasyMultiply(CompilationUnit *cUnit, 2229 RegLocation rlSrc, RegLocation rlDest, int lit) 2230{ 2231 // Can we simplify this multiplication? 2232 bool powerOfTwo = false; 2233 bool popCountLE2 = false; 2234 bool powerOfTwoMinusOne = false; 2235 if (lit < 2) { 2236 // Avoid special cases. 2237 return false; 2238 } else if (isPowerOfTwo(lit)) { 2239 powerOfTwo = true; 2240 } else if (isPopCountLE2(lit)) { 2241 popCountLE2 = true; 2242 } else if (isPowerOfTwo(lit + 1)) { 2243 powerOfTwoMinusOne = true; 2244 } else { 2245 return false; 2246 } 2247 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2248 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2249 if (powerOfTwo) { 2250 // Shift. 2251 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg, 2252 lowestSetBit(lit)); 2253 } else if (popCountLE2) { 2254 // Shift and add and shift. 2255 int firstBit = lowestSetBit(lit); 2256 int secondBit = lowestSetBit(lit ^ (1 << firstBit)); 2257 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit, 2258 firstBit, secondBit); 2259 } else { 2260 // Reverse subtract: (src << (shift + 1)) - src. 2261 assert(powerOfTwoMinusOne); 2262 // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1) 2263 int tReg = dvmCompilerAllocTemp(cUnit); 2264 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1)); 2265 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg); 2266 } 2267 storeValue(cUnit, rlDest, rlResult); 2268 return true; 2269} 2270 2271static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir) 2272{ 2273 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2274 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2275 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2276 RegLocation rlResult; 2277 int lit = mir->dalvikInsn.vC; 2278 OpKind op = (OpKind)0; /* Make gcc happy */ 2279 int shiftOp = false; 2280 bool isDiv = false; 2281 2282 switch (dalvikOpcode) { 2283 case OP_RSUB_INT_LIT8: 2284 case OP_RSUB_INT: { 2285 int tReg; 2286 //TUNING: add support for use of Arm rsub op 2287 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2288 tReg = dvmCompilerAllocTemp(cUnit); 2289 loadConstant(cUnit, tReg, lit); 2290 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2291 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, 2292 tReg, rlSrc.lowReg); 2293 storeValue(cUnit, rlDest, rlResult); 2294 return false; 2295 break; 2296 } 2297 2298 case OP_ADD_INT_LIT8: 2299 case OP_ADD_INT_LIT16: 2300 op = kOpAdd; 2301 break; 2302 case OP_MUL_INT_LIT8: 2303 case OP_MUL_INT_LIT16: { 2304 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) { 2305 return false; 2306 } 2307 op = kOpMul; 2308 break; 2309 } 2310 case OP_AND_INT_LIT8: 2311 case OP_AND_INT_LIT16: 2312 op = kOpAnd; 2313 break; 2314 case OP_OR_INT_LIT8: 2315 case OP_OR_INT_LIT16: 2316 op = kOpOr; 2317 break; 2318 case OP_XOR_INT_LIT8: 2319 case OP_XOR_INT_LIT16: 2320 op = kOpXor; 2321 break; 2322 case OP_SHL_INT_LIT8: 2323 lit &= 31; 2324 shiftOp = true; 2325 op = kOpLsl; 2326 break; 2327 case OP_SHR_INT_LIT8: 2328 lit &= 31; 2329 shiftOp = true; 2330 op = kOpAsr; 2331 break; 2332 case OP_USHR_INT_LIT8: 2333 lit &= 31; 2334 shiftOp = true; 2335 op = kOpLsr; 2336 break; 2337 2338 case OP_DIV_INT_LIT8: 2339 case OP_DIV_INT_LIT16: 2340 case OP_REM_INT_LIT8: 2341 case OP_REM_INT_LIT16: 2342 if (lit == 0) { 2343 /* Let the interpreter deal with div by 0 */ 2344 genInterpSingleStep(cUnit, mir); 2345 return false; 2346 } 2347 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) { 2348 return false; 2349 } 2350 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2351 loadValueDirectFixed(cUnit, rlSrc, r0); 2352 dvmCompilerClobber(cUnit, r0); 2353 if ((dalvikOpcode == OP_DIV_INT_LIT8) || 2354 (dalvikOpcode == OP_DIV_INT_LIT16)) { 2355 LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idiv); 2356 isDiv = true; 2357 } else { 2358 LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idivmod); 2359 isDiv = false; 2360 } 2361 loadConstant(cUnit, r1, lit); 2362 opReg(cUnit, kOpBlx, r2); 2363 dvmCompilerClobberCallRegs(cUnit); 2364 if (isDiv) 2365 rlResult = dvmCompilerGetReturn(cUnit); 2366 else 2367 rlResult = dvmCompilerGetReturnAlt(cUnit); 2368 storeValue(cUnit, rlDest, rlResult); 2369 return false; 2370 break; 2371 default: 2372 return true; 2373 } 2374 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2375 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2376 // Avoid shifts by literal 0 - no support in Thumb. Change to copy 2377 if (shiftOp && (lit == 0)) { 2378 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); 2379 } else { 2380 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit); 2381 } 2382 storeValue(cUnit, rlDest, rlResult); 2383 return false; 2384} 2385 2386static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir) 2387{ 2388 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2389 int fieldOffset = -1; 2390 bool isVolatile = false; 2391 switch (dalvikOpcode) { 2392 /* 2393 * Wide volatiles currently handled via single step. 2394 * Add them here if generating in-line code. 2395 * case OP_IGET_WIDE_VOLATILE: 2396 * case OP_IPUT_WIDE_VOLATILE: 2397 */ 2398 case OP_IGET_VOLATILE: 2399 case OP_IGET_OBJECT_VOLATILE: 2400 case OP_IPUT_VOLATILE: 2401 case OP_IPUT_OBJECT_VOLATILE: 2402#if ANDROID_SMP != 0 2403 isVolatile = true; 2404 // NOTE: intentional fallthrough 2405#endif 2406 case OP_IGET: 2407 case OP_IGET_WIDE: 2408 case OP_IGET_OBJECT: 2409 case OP_IGET_BOOLEAN: 2410 case OP_IGET_BYTE: 2411 case OP_IGET_CHAR: 2412 case OP_IGET_SHORT: 2413 case OP_IPUT: 2414 case OP_IPUT_WIDE: 2415 case OP_IPUT_OBJECT: 2416 case OP_IPUT_BOOLEAN: 2417 case OP_IPUT_BYTE: 2418 case OP_IPUT_CHAR: 2419 case OP_IPUT_SHORT: { 2420 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 2421 mir->meta.calleeMethod : cUnit->method; 2422 Field *fieldPtr = 2423 method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC]; 2424 2425 if (fieldPtr == NULL) { 2426 BAIL_LOOP_COMPILATION(); 2427 ALOGE("Unexpected null instance field"); 2428 dvmAbort(); 2429 } 2430 2431#if ANDROID_SMP != 0 2432 assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr)); 2433#else 2434 isVolatile = dvmIsVolatileField((Field *) fieldPtr); 2435#endif 2436 fieldOffset = ((InstField *)fieldPtr)->byteOffset; 2437 break; 2438 } 2439 default: 2440 break; 2441 } 2442 2443 switch (dalvikOpcode) { 2444 case OP_NEW_ARRAY: { 2445 // Generates a call - use explicit registers 2446 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2447 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2448 RegLocation rlResult; 2449 void *classPtr = (void*) 2450 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]); 2451 2452 if (classPtr == NULL) { 2453 BAIL_LOOP_COMPILATION(); 2454 ALOGE("Unexpected null class"); 2455 dvmAbort(); 2456 } 2457 2458 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2459 genExportPC(cUnit, mir); 2460 loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */ 2461 loadConstant(cUnit, r0, (int) classPtr ); 2462 LOAD_FUNC_ADDR(cUnit, r3, (int)dvmAllocArrayByClass); 2463 /* 2464 * "len < 0": bail to the interpreter to re-execute the 2465 * instruction 2466 */ 2467 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL); 2468 loadConstant(cUnit, r2, ALLOC_DONT_TRACK); 2469 opReg(cUnit, kOpBlx, r3); 2470 dvmCompilerClobberCallRegs(cUnit); 2471 /* generate a branch over if allocation is successful */ 2472 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 2473 /* 2474 * OOM exception needs to be thrown here and cannot re-execute 2475 */ 2476 loadConstant(cUnit, r0, 2477 (int) (cUnit->method->insns + mir->offset)); 2478 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 2479 /* noreturn */ 2480 2481 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2482 target->defMask = ENCODE_ALL; 2483 branchOver->generic.target = (LIR *) target; 2484 rlResult = dvmCompilerGetReturn(cUnit); 2485 storeValue(cUnit, rlDest, rlResult); 2486 break; 2487 } 2488 case OP_INSTANCE_OF: { 2489 // May generate a call - use explicit registers 2490 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2491 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2492 RegLocation rlResult; 2493 ClassObject *classPtr = 2494 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]); 2495 /* 2496 * Note: It is possible that classPtr is NULL at this point, 2497 * even though this instruction has been successfully interpreted. 2498 * If the previous interpretation had a null source, the 2499 * interpreter would not have bothered to resolve the clazz. 2500 * Bail out to the interpreter in this case, and log it 2501 * so that we can tell if it happens frequently. 2502 */ 2503 if (classPtr == NULL) { 2504 BAIL_LOOP_COMPILATION(); 2505 ALOGD("null clazz in OP_INSTANCE_OF, single-stepping"); 2506 genInterpSingleStep(cUnit, mir); 2507 break; 2508 } 2509 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2510 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */ 2511 loadConstant(cUnit, r2, (int) classPtr ); 2512 /* When taken r0 has NULL which can be used for store directly */ 2513 ArmLIR *branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0); 2514 /* r1 now contains object->clazz */ 2515 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1); 2516 /* r1 now contains object->clazz */ 2517 LOAD_FUNC_ADDR(cUnit, r3, (int)dvmInstanceofNonTrivial); 2518 loadConstant(cUnit, r0, 1); /* Assume true */ 2519 opRegReg(cUnit, kOpCmp, r1, r2); 2520 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq); 2521 genRegCopy(cUnit, r0, r1); 2522 genRegCopy(cUnit, r1, r2); 2523 opReg(cUnit, kOpBlx, r3); 2524 dvmCompilerClobberCallRegs(cUnit); 2525 /* branch target here */ 2526 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2527 target->defMask = ENCODE_ALL; 2528 rlResult = dvmCompilerGetReturn(cUnit); 2529 storeValue(cUnit, rlDest, rlResult); 2530 branch1->generic.target = (LIR *)target; 2531 branch2->generic.target = (LIR *)target; 2532 break; 2533 } 2534 case OP_IGET_WIDE: 2535 genIGetWide(cUnit, mir, fieldOffset); 2536 break; 2537 case OP_IGET_VOLATILE: 2538 case OP_IGET_OBJECT_VOLATILE: 2539 case OP_IGET: 2540 case OP_IGET_OBJECT: 2541 case OP_IGET_BOOLEAN: 2542 case OP_IGET_BYTE: 2543 case OP_IGET_CHAR: 2544 case OP_IGET_SHORT: 2545 genIGet(cUnit, mir, kWord, fieldOffset, isVolatile); 2546 break; 2547 case OP_IPUT_WIDE: 2548 genIPutWide(cUnit, mir, fieldOffset); 2549 break; 2550 case OP_IPUT_VOLATILE: 2551 case OP_IPUT: 2552 case OP_IPUT_BOOLEAN: 2553 case OP_IPUT_BYTE: 2554 case OP_IPUT_CHAR: 2555 case OP_IPUT_SHORT: 2556 genIPut(cUnit, mir, kWord, fieldOffset, false, isVolatile); 2557 break; 2558 case OP_IPUT_OBJECT_VOLATILE: 2559 case OP_IPUT_OBJECT: 2560 genIPut(cUnit, mir, kWord, fieldOffset, true, isVolatile); 2561 break; 2562 case OP_IGET_WIDE_VOLATILE: 2563 case OP_IPUT_WIDE_VOLATILE: 2564 genInterpSingleStep(cUnit, mir); 2565 break; 2566 default: 2567 return true; 2568 } 2569 return false; 2570} 2571 2572static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir) 2573{ 2574 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2575 int fieldOffset = mir->dalvikInsn.vC; 2576 switch (dalvikOpcode) { 2577 case OP_IGET_QUICK: 2578 case OP_IGET_OBJECT_QUICK: 2579 genIGet(cUnit, mir, kWord, fieldOffset, false); 2580 break; 2581 case OP_IPUT_QUICK: 2582 genIPut(cUnit, mir, kWord, fieldOffset, false, false); 2583 break; 2584 case OP_IPUT_OBJECT_QUICK: 2585 genIPut(cUnit, mir, kWord, fieldOffset, true, false); 2586 break; 2587 case OP_IGET_WIDE_QUICK: 2588 genIGetWide(cUnit, mir, fieldOffset); 2589 break; 2590 case OP_IPUT_WIDE_QUICK: 2591 genIPutWide(cUnit, mir, fieldOffset); 2592 break; 2593 default: 2594 return true; 2595 } 2596 return false; 2597 2598} 2599 2600/* Compare agaist zero */ 2601static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 2602 ArmLIR *labelList) 2603{ 2604 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2605 ArmConditionCode cond; 2606 /* backward branch? */ 2607 bool backwardBranch = (bb->taken->startOffset <= mir->offset); 2608 2609 if (backwardBranch && 2610 (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) { 2611 genSuspendPoll(cUnit, mir); 2612 } 2613 2614 RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0); 2615 RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1); 2616 2617 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); 2618 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); 2619 2620 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); 2621 2622 switch (dalvikOpcode) { 2623 case OP_IF_EQ: 2624 cond = kArmCondEq; 2625 break; 2626 case OP_IF_NE: 2627 cond = kArmCondNe; 2628 break; 2629 case OP_IF_LT: 2630 cond = kArmCondLt; 2631 break; 2632 case OP_IF_GE: 2633 cond = kArmCondGe; 2634 break; 2635 case OP_IF_GT: 2636 cond = kArmCondGt; 2637 break; 2638 case OP_IF_LE: 2639 cond = kArmCondLe; 2640 break; 2641 default: 2642 cond = (ArmConditionCode)0; 2643 ALOGE("Unexpected opcode (%d) for Fmt22t", dalvikOpcode); 2644 dvmCompilerAbort(cUnit); 2645 } 2646 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]); 2647 /* This mostly likely will be optimized away in a later phase */ 2648 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); 2649 return false; 2650} 2651 2652static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir) 2653{ 2654 Opcode opcode = mir->dalvikInsn.opcode; 2655 2656 switch (opcode) { 2657 case OP_MOVE_16: 2658 case OP_MOVE_OBJECT_16: 2659 case OP_MOVE_FROM16: 2660 case OP_MOVE_OBJECT_FROM16: { 2661 storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0), 2662 dvmCompilerGetSrc(cUnit, mir, 0)); 2663 break; 2664 } 2665 case OP_MOVE_WIDE_16: 2666 case OP_MOVE_WIDE_FROM16: { 2667 storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1), 2668 dvmCompilerGetSrcWide(cUnit, mir, 0, 1)); 2669 break; 2670 } 2671 default: 2672 return true; 2673 } 2674 return false; 2675} 2676 2677static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir) 2678{ 2679 Opcode opcode = mir->dalvikInsn.opcode; 2680 RegLocation rlSrc1; 2681 RegLocation rlSrc2; 2682 RegLocation rlDest; 2683 2684 if ( (opcode >= OP_ADD_INT) && (opcode <= OP_REM_DOUBLE)) { 2685 return genArithOp( cUnit, mir ); 2686 } 2687 2688 /* APUTs have 3 sources and no targets */ 2689 if (mir->ssaRep->numDefs == 0) { 2690 if (mir->ssaRep->numUses == 3) { 2691 rlDest = dvmCompilerGetSrc(cUnit, mir, 0); 2692 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1); 2693 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2); 2694 } else { 2695 assert(mir->ssaRep->numUses == 4); 2696 rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 2697 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2); 2698 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3); 2699 } 2700 } else { 2701 /* Two sources and 1 dest. Deduce the operand sizes */ 2702 if (mir->ssaRep->numUses == 4) { 2703 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 2704 rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3); 2705 } else { 2706 assert(mir->ssaRep->numUses == 2); 2707 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0); 2708 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1); 2709 } 2710 if (mir->ssaRep->numDefs == 2) { 2711 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 2712 } else { 2713 assert(mir->ssaRep->numDefs == 1); 2714 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2715 } 2716 } 2717 2718 2719 switch (opcode) { 2720 case OP_CMPL_FLOAT: 2721 case OP_CMPG_FLOAT: 2722 case OP_CMPL_DOUBLE: 2723 case OP_CMPG_DOUBLE: 2724 return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2); 2725 case OP_CMP_LONG: 2726 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2); 2727 break; 2728 case OP_AGET_WIDE: 2729 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3); 2730 break; 2731 case OP_AGET: 2732 case OP_AGET_OBJECT: 2733 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2); 2734 break; 2735 case OP_AGET_BOOLEAN: 2736 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0); 2737 break; 2738 case OP_AGET_BYTE: 2739 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0); 2740 break; 2741 case OP_AGET_CHAR: 2742 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1); 2743 break; 2744 case OP_AGET_SHORT: 2745 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1); 2746 break; 2747 case OP_APUT_WIDE: 2748 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3); 2749 break; 2750 case OP_APUT: 2751 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2); 2752 break; 2753 case OP_APUT_OBJECT: 2754 genArrayObjectPut(cUnit, mir, rlSrc1, rlSrc2, rlDest, 2); 2755 break; 2756 case OP_APUT_SHORT: 2757 case OP_APUT_CHAR: 2758 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1); 2759 break; 2760 case OP_APUT_BYTE: 2761 case OP_APUT_BOOLEAN: 2762 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0); 2763 break; 2764 default: 2765 return true; 2766 } 2767 return false; 2768} 2769 2770/* 2771 * Find the matching case. 2772 * 2773 * return values: 2774 * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case, 2775 * including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES). 2776 * r1 (high 32-bit): the branch offset of the matching case (only for indexes 2777 * above MAX_CHAINED_SWITCH_CASES). 2778 * 2779 * Instructions around the call are: 2780 * 2781 * mov r2, pc 2782 * blx &findPackedSwitchIndex 2783 * mov pc, r0 2784 * .align4 2785 * chaining cell for case 0 [12 bytes] 2786 * chaining cell for case 1 [12 bytes] 2787 * : 2788 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [12 bytes] 2789 * chaining cell for case default [8 bytes] 2790 * noChain exit 2791 */ 2792static u8 findPackedSwitchIndex(const u2* switchData, int testVal, uintptr_t pc) 2793{ 2794 int size; 2795 int firstKey; 2796 const int *entries; 2797 int index; 2798 int jumpIndex; 2799 uintptr_t caseDPCOffset = 0; 2800 /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */ 2801 uintptr_t chainingPC = (pc + 4) & ~3; 2802 2803 /* 2804 * Packed switch data format: 2805 * ushort ident = 0x0100 magic value 2806 * ushort size number of entries in the table 2807 * int first_key first (and lowest) switch case value 2808 * int targets[size] branch targets, relative to switch opcode 2809 * 2810 * Total size is (4+size*2) 16-bit code units. 2811 */ 2812 size = switchData[1]; 2813 assert(size > 0); 2814 2815 firstKey = switchData[2]; 2816 firstKey |= switchData[3] << 16; 2817 2818 2819 /* The entries are guaranteed to be aligned on a 32-bit boundary; 2820 * we can treat them as a native int array. 2821 */ 2822 entries = (const int*) &switchData[4]; 2823 assert(((u4)entries & 0x3) == 0); 2824 2825 index = testVal - firstKey; 2826 2827 /* Jump to the default cell */ 2828 if (index < 0 || index >= size) { 2829 jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES); 2830 /* Jump to the non-chaining exit point */ 2831 } else if (index >= MAX_CHAINED_SWITCH_CASES) { 2832 jumpIndex = MAX_CHAINED_SWITCH_CASES + 1; 2833 caseDPCOffset = entries[index]; 2834 /* Jump to the inline chaining cell */ 2835 } else { 2836 jumpIndex = index; 2837 } 2838 2839 chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE; 2840 return (((u8) caseDPCOffset) << 32) | (u8) chainingPC; 2841} 2842 2843/* See comments for findPackedSwitchIndex */ 2844static u8 findSparseSwitchIndex(const u2* switchData, int testVal, uintptr_t pc) 2845{ 2846 int size; 2847 const int *keys; 2848 const int *entries; 2849 uintptr_t chainingPC = (pc + 4) & ~3; 2850 int i; 2851 2852 /* 2853 * Sparse switch data format: 2854 * ushort ident = 0x0200 magic value 2855 * ushort size number of entries in the table; > 0 2856 * int keys[size] keys, sorted low-to-high; 32-bit aligned 2857 * int targets[size] branch targets, relative to switch opcode 2858 * 2859 * Total size is (2+size*4) 16-bit code units. 2860 */ 2861 2862 size = switchData[1]; 2863 assert(size > 0); 2864 2865 /* The keys are guaranteed to be aligned on a 32-bit boundary; 2866 * we can treat them as a native int array. 2867 */ 2868 keys = (const int*) &switchData[2]; 2869 assert(((u4)keys & 0x3) == 0); 2870 2871 /* The entries are guaranteed to be aligned on a 32-bit boundary; 2872 * we can treat them as a native int array. 2873 */ 2874 entries = keys + size; 2875 assert(((u4)entries & 0x3) == 0); 2876 2877 /* 2878 * Run through the list of keys, which are guaranteed to 2879 * be sorted low-to-high. 2880 * 2881 * Most tables have 3-4 entries. Few have more than 10. A binary 2882 * search here is probably not useful. 2883 */ 2884 for (i = 0; i < size; i++) { 2885 int k = keys[i]; 2886 if (k == testVal) { 2887 /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */ 2888 int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ? 2889 i : MAX_CHAINED_SWITCH_CASES + 1; 2890 chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE; 2891 return (((u8) entries[i]) << 32) | (u8) chainingPC; 2892 } else if (k > testVal) { 2893 break; 2894 } 2895 } 2896 return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 2897 CHAIN_CELL_NORMAL_SIZE; 2898} 2899 2900static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir) 2901{ 2902 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 2903 switch (dalvikOpcode) { 2904 case OP_FILL_ARRAY_DATA: { 2905 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2906 // Making a call - use explicit registers 2907 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2908 genExportPC(cUnit, mir); 2909 loadValueDirectFixed(cUnit, rlSrc, r0); 2910 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInterpHandleFillArrayData); 2911 loadConstant(cUnit, r1, 2912 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB)); 2913 opReg(cUnit, kOpBlx, r2); 2914 dvmCompilerClobberCallRegs(cUnit); 2915 /* generate a branch over if successful */ 2916 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 2917 loadConstant(cUnit, r0, 2918 (int) (cUnit->method->insns + mir->offset)); 2919 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 2920 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2921 target->defMask = ENCODE_ALL; 2922 branchOver->generic.target = (LIR *) target; 2923 break; 2924 } 2925 /* 2926 * Compute the goto target of up to 2927 * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells. 2928 * See the comment before findPackedSwitchIndex for the code layout. 2929 */ 2930 case OP_PACKED_SWITCH: 2931 case OP_SPARSE_SWITCH: { 2932 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2933 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2934 loadValueDirectFixed(cUnit, rlSrc, r1); 2935 dvmCompilerLockAllTemps(cUnit); 2936 if (dalvikOpcode == OP_PACKED_SWITCH) { 2937 LOAD_FUNC_ADDR(cUnit, r4PC, (int)findPackedSwitchIndex); 2938 } else { 2939 LOAD_FUNC_ADDR(cUnit, r4PC, (int)findSparseSwitchIndex); 2940 } 2941 /* r0 <- Addr of the switch data */ 2942 loadConstant(cUnit, r0, 2943 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB)); 2944 /* r2 <- pc of the instruction following the blx */ 2945 opRegReg(cUnit, kOpMov, r2, r15pc); 2946 opReg(cUnit, kOpBlx, r4PC); 2947 dvmCompilerClobberCallRegs(cUnit); 2948 /* pc <- computed goto target */ 2949 opRegReg(cUnit, kOpMov, r15pc, r0); 2950 break; 2951 } 2952 default: 2953 return true; 2954 } 2955 return false; 2956} 2957 2958/* 2959 * See the example of predicted inlining listed before the 2960 * genValidationForPredictedInline function. The function here takes care the 2961 * branch over at 0x4858de78 and the misprediction target at 0x4858de7a. 2962 */ 2963static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir, 2964 BasicBlock *bb, 2965 ArmLIR *labelList) 2966{ 2967 BasicBlock *fallThrough = bb->fallThrough; 2968 2969 /* Bypass the move-result block if there is one */ 2970 if (fallThrough->firstMIRInsn) { 2971 assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED); 2972 fallThrough = fallThrough->fallThrough; 2973 } 2974 /* Generate a branch over if the predicted inlining is correct */ 2975 genUnconditionalBranch(cUnit, &labelList[fallThrough->id]); 2976 2977 /* Reset the register state */ 2978 dvmCompilerResetRegPool(cUnit); 2979 dvmCompilerClobberAllRegs(cUnit); 2980 dvmCompilerResetNullCheck(cUnit); 2981 2982 /* Target for the slow invoke path */ 2983 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2984 target->defMask = ENCODE_ALL; 2985 /* Hook up the target to the verification branch */ 2986 mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target; 2987} 2988 2989static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, 2990 BasicBlock *bb, ArmLIR *labelList) 2991{ 2992 ArmLIR *retChainingCell = NULL; 2993 ArmLIR *pcrLabel = NULL; 2994 2995 /* An invoke with the MIR_INLINED is effectively a no-op */ 2996 if (mir->OptimizationFlags & MIR_INLINED) 2997 return false; 2998 2999 if (bb->fallThrough != NULL) 3000 retChainingCell = &labelList[bb->fallThrough->id]; 3001 3002 DecodedInstruction *dInsn = &mir->dalvikInsn; 3003 switch (mir->dalvikInsn.opcode) { 3004 /* 3005 * calleeMethod = this->clazz->vtable[ 3006 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex 3007 * ] 3008 */ 3009 case OP_INVOKE_VIRTUAL: 3010 case OP_INVOKE_VIRTUAL_RANGE: { 3011 ArmLIR *predChainingCell = &labelList[bb->taken->id]; 3012 int methodIndex = 3013 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]-> 3014 methodIndex; 3015 3016 /* 3017 * If the invoke has non-null misPredBranchOver, we need to generate 3018 * the non-inlined version of the invoke here to handle the 3019 * mispredicted case. 3020 */ 3021 if (mir->meta.callsiteInfo->misPredBranchOver) { 3022 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList); 3023 } 3024 3025 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL) 3026 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3027 else 3028 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3029 3030 genInvokeVirtualCommon(cUnit, mir, methodIndex, 3031 retChainingCell, 3032 predChainingCell, 3033 pcrLabel); 3034 break; 3035 } 3036 /* 3037 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex 3038 * ->pResMethods[BBBB]->methodIndex] 3039 */ 3040 case OP_INVOKE_SUPER: 3041 case OP_INVOKE_SUPER_RANGE: { 3042 /* Grab the method ptr directly from what the interpreter sees */ 3043 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3044 assert(calleeMethod == cUnit->method->clazz->super->vtable[ 3045 cUnit->method->clazz->pDvmDex-> 3046 pResMethods[dInsn->vB]->methodIndex]); 3047 3048 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER) 3049 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3050 else 3051 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3052 3053 if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) { 3054 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3055 void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns); 3056 assert(calleeAddr); 3057 genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr, 3058 retChainingCell); 3059 } else { 3060 /* r0 = calleeMethod */ 3061 loadConstant(cUnit, r0, (int) calleeMethod); 3062 3063 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 3064 calleeMethod); 3065 } 3066 break; 3067 } 3068 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */ 3069 case OP_INVOKE_DIRECT: 3070 case OP_INVOKE_DIRECT_RANGE: { 3071 /* Grab the method ptr directly from what the interpreter sees */ 3072 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3073 assert(calleeMethod == 3074 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]); 3075 3076 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) 3077 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3078 else 3079 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3080 3081 /* r0 = calleeMethod */ 3082 loadConstant(cUnit, r0, (int) calleeMethod); 3083 3084 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 3085 calleeMethod); 3086 break; 3087 } 3088 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */ 3089 case OP_INVOKE_STATIC: 3090 case OP_INVOKE_STATIC_RANGE: { 3091 /* Grab the method ptr directly from what the interpreter sees */ 3092 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3093 assert(calleeMethod == 3094 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]); 3095 3096 if (mir->dalvikInsn.opcode == OP_INVOKE_STATIC) 3097 genProcessArgsNoRange(cUnit, mir, dInsn, 3098 NULL /* no null check */); 3099 else 3100 genProcessArgsRange(cUnit, mir, dInsn, 3101 NULL /* no null check */); 3102 3103 if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) { 3104 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3105 void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns); 3106 assert(calleeAddr); 3107 genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr, 3108 retChainingCell); 3109 } else { 3110 /* r0 = calleeMethod */ 3111 loadConstant(cUnit, r0, (int) calleeMethod); 3112 3113 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 3114 calleeMethod); 3115 } 3116 break; 3117 } 3118 /* 3119 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz, 3120 * BBBB, method, method->clazz->pDvmDex) 3121 * 3122 * The following is an example of generated code for 3123 * "invoke-interface v0" 3124 * 3125 * -------- dalvik offset: 0x0008 @ invoke-interface v0 3126 * 0x47357e36 : ldr r0, [r5, #0] --+ 3127 * 0x47357e38 : sub r7,r5,#24 | 3128 * 0x47357e3c : cmp r0, #0 | genProcessArgsNoRange 3129 * 0x47357e3e : beq 0x47357e82 | 3130 * 0x47357e40 : stmia r7, <r0> --+ 3131 * 0x47357e42 : ldr r4, [pc, #120] --> r4 <- dalvikPC of this invoke 3132 * 0x47357e44 : add r1, pc, #64 --> r1 <- &retChainingCell 3133 * 0x47357e46 : add r2, pc, #72 --> r2 <- &predictedChainingCell 3134 * 0x47357e48 : blx_1 0x47348190 --+ TEMPLATE_INVOKE_METHOD_ 3135 * 0x47357e4a : blx_2 see above --+ PREDICTED_CHAIN 3136 * 0x47357e4c : b 0x47357e90 --> off to the predicted chain 3137 * 0x47357e4e : b 0x47357e82 --> punt to the interpreter 3138 * 0x47357e50 : mov r8, r1 --+ 3139 * 0x47357e52 : mov r9, r2 | 3140 * 0x47357e54 : ldr r2, [pc, #96] | 3141 * 0x47357e56 : mov r10, r3 | 3142 * 0x47357e58 : movs r0, r3 | dvmFindInterfaceMethodInCache 3143 * 0x47357e5a : ldr r3, [pc, #88] | 3144 * 0x47357e5c : ldr r7, [pc, #80] | 3145 * 0x47357e5e : mov r1, #1452 | 3146 * 0x47357e62 : blx r7 --+ 3147 * 0x47357e64 : cmp r0, #0 --> calleeMethod == NULL? 3148 * 0x47357e66 : bne 0x47357e6e --> branch over the throw if !r0 3149 * 0x47357e68 : ldr r0, [pc, #80] --> load Dalvik PC of the invoke 3150 * 0x47357e6a : blx_1 0x47348494 --+ TEMPLATE_THROW_EXCEPTION_ 3151 * 0x47357e6c : blx_2 see above --+ COMMON 3152 * 0x47357e6e : mov r1, r8 --> r1 <- &retChainingCell 3153 * 0x47357e70 : cmp r1, #0 --> compare against 0 3154 * 0x47357e72 : bgt 0x47357e7c --> >=0? don't rechain 3155 * 0x47357e74 : ldr r7, [pc, #off] --+ 3156 * 0x47357e76 : mov r2, r9 | dvmJitToPatchPredictedChain 3157 * 0x47357e78 : mov r3, r10 | 3158 * 0x47357e7a : blx r7 --+ 3159 * 0x47357e7c : add r1, pc, #8 --> r1 <- &retChainingCell 3160 * 0x47357e7e : blx_1 0x4734809c --+ TEMPLATE_INVOKE_METHOD_NO_OPT 3161 * 0x47357e80 : blx_2 see above --+ 3162 * -------- reconstruct dalvik PC : 0x425719dc @ +0x0008 3163 * 0x47357e82 : ldr r0, [pc, #56] 3164 * Exception_Handling: 3165 * 0x47357e84 : ldr r1, [r6, #92] 3166 * 0x47357e86 : blx r1 3167 * 0x47357e88 : .align4 3168 * -------- chaining cell (hot): 0x000b 3169 * 0x47357e88 : ldr r0, [r6, #104] 3170 * 0x47357e8a : blx r0 3171 * 0x47357e8c : data 0x19e2(6626) 3172 * 0x47357e8e : data 0x4257(16983) 3173 * 0x47357e90 : .align4 3174 * -------- chaining cell (predicted) 3175 * 0x47357e90 : data 0xe7fe(59390) --> will be patched into bx 3176 * 0x47357e92 : data 0x0000(0) 3177 * 0x47357e94 : data 0x0000(0) --> class 3178 * 0x47357e96 : data 0x0000(0) 3179 * 0x47357e98 : data 0x0000(0) --> method 3180 * 0x47357e9a : data 0x0000(0) 3181 * 0x47357e9c : data 0x0000(0) --> rechain count 3182 * 0x47357e9e : data 0x0000(0) 3183 * -------- end of chaining cells (0x006c) 3184 * 0x47357eb0 : .word (0xad03e369) 3185 * 0x47357eb4 : .word (0x28a90) 3186 * 0x47357eb8 : .word (0x41a63394) 3187 * 0x47357ebc : .word (0x425719dc) 3188 */ 3189 case OP_INVOKE_INTERFACE: 3190 case OP_INVOKE_INTERFACE_RANGE: { 3191 ArmLIR *predChainingCell = &labelList[bb->taken->id]; 3192 3193 /* 3194 * If the invoke has non-null misPredBranchOver, we need to generate 3195 * the non-inlined version of the invoke here to handle the 3196 * mispredicted case. 3197 */ 3198 if (mir->meta.callsiteInfo->misPredBranchOver) { 3199 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList); 3200 } 3201 3202 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE) 3203 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3204 else 3205 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3206 3207 /* "this" is already left in r0 by genProcessArgs* */ 3208 3209 /* r4PC = dalvikCallsite */ 3210 loadConstant(cUnit, r4PC, 3211 (int) (cUnit->method->insns + mir->offset)); 3212 3213 /* r1 = &retChainingCell */ 3214 ArmLIR *addrRetChain = 3215 opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0); 3216 addrRetChain->generic.target = (LIR *) retChainingCell; 3217 3218 /* r2 = &predictedChainingCell */ 3219 ArmLIR *predictedChainingCell = 3220 opRegRegImm(cUnit, kOpAdd, r2, r15pc, 0); 3221 predictedChainingCell->generic.target = (LIR *) predChainingCell; 3222 3223 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 3224 TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF : 3225 TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN); 3226 3227 /* return through lr - jump to the chaining cell */ 3228 genUnconditionalBranch(cUnit, predChainingCell); 3229 3230 /* 3231 * null-check on "this" may have been eliminated, but we still need 3232 * a PC-reconstruction label for stack overflow bailout. 3233 */ 3234 if (pcrLabel == NULL) { 3235 int dPC = (int) (cUnit->method->insns + mir->offset); 3236 pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); 3237 pcrLabel->opcode = kArmPseudoPCReconstructionCell; 3238 pcrLabel->operands[0] = dPC; 3239 pcrLabel->operands[1] = mir->offset; 3240 /* Insert the place holder to the growable list */ 3241 dvmInsertGrowableList(&cUnit->pcReconstructionList, 3242 (intptr_t) pcrLabel); 3243 } 3244 3245 /* return through lr+2 - punt to the interpreter */ 3246 genUnconditionalBranch(cUnit, pcrLabel); 3247 3248 /* 3249 * return through lr+4 - fully resolve the callee method. 3250 * r1 <- count 3251 * r2 <- &predictedChainCell 3252 * r3 <- this->class 3253 * r4 <- dPC 3254 * r7 <- this->class->vtable 3255 */ 3256 3257 /* Save count, &predictedChainCell, and class to high regs first */ 3258 genRegCopy(cUnit, r8, r1); 3259 genRegCopy(cUnit, r9, r2); 3260 genRegCopy(cUnit, r10, r3); 3261 3262 /* r0 now contains this->clazz */ 3263 genRegCopy(cUnit, r0, r3); 3264 3265 /* r1 = BBBB */ 3266 loadConstant(cUnit, r1, dInsn->vB); 3267 3268 /* r2 = method (caller) */ 3269 loadConstant(cUnit, r2, (int) cUnit->method); 3270 3271 /* r3 = pDvmDex */ 3272 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex); 3273 3274 LOAD_FUNC_ADDR(cUnit, r7, 3275 (intptr_t) dvmFindInterfaceMethodInCache); 3276 opReg(cUnit, kOpBlx, r7); 3277 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */ 3278 3279 dvmCompilerClobberCallRegs(cUnit); 3280 /* generate a branch over if the interface method is resolved */ 3281 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 3282 /* 3283 * calleeMethod == NULL -> throw 3284 */ 3285 loadConstant(cUnit, r0, 3286 (int) (cUnit->method->insns + mir->offset)); 3287 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 3288 /* noreturn */ 3289 3290 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 3291 target->defMask = ENCODE_ALL; 3292 branchOver->generic.target = (LIR *) target; 3293 3294 genRegCopy(cUnit, r1, r8); 3295 3296 /* Check if rechain limit is reached */ 3297 ArmLIR *bypassRechaining = genCmpImmBranch(cUnit, kArmCondGt, 3298 r1, 0); 3299 3300 LOAD_FUNC_ADDR(cUnit, r7, (int) dvmJitToPatchPredictedChain); 3301 3302 genRegCopy(cUnit, r1, r6SELF); 3303 genRegCopy(cUnit, r2, r9); 3304 genRegCopy(cUnit, r3, r10); 3305 3306 /* 3307 * r0 = calleeMethod 3308 * r2 = &predictedChainingCell 3309 * r3 = class 3310 * 3311 * &returnChainingCell has been loaded into r1 but is not needed 3312 * when patching the chaining cell and will be clobbered upon 3313 * returning so it will be reconstructed again. 3314 */ 3315 opReg(cUnit, kOpBlx, r7); 3316 3317 /* r1 = &retChainingCell */ 3318 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0); 3319 addrRetChain->generic.target = (LIR *) retChainingCell; 3320 3321 bypassRechaining->generic.target = (LIR *) addrRetChain; 3322 3323 /* 3324 * r0 = this, r1 = calleeMethod, 3325 * r1 = &ChainingCell, 3326 * r4PC = callsiteDPC, 3327 */ 3328 genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ? 3329 TEMPLATE_INVOKE_METHOD_NO_OPT_PROF : 3330 TEMPLATE_INVOKE_METHOD_NO_OPT); 3331#if defined(WITH_JIT_TUNING) 3332 gDvmJit.invokePolymorphic++; 3333#endif 3334 /* Handle exceptions using the interpreter */ 3335 genTrap(cUnit, mir->offset, pcrLabel); 3336 break; 3337 } 3338 case OP_INVOKE_OBJECT_INIT_RANGE: 3339 case OP_FILLED_NEW_ARRAY: 3340 case OP_FILLED_NEW_ARRAY_RANGE: { 3341 /* Just let the interpreter deal with these */ 3342 genInterpSingleStep(cUnit, mir); 3343 break; 3344 } 3345 default: 3346 return true; 3347 } 3348 return false; 3349} 3350 3351static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir, 3352 BasicBlock *bb, ArmLIR *labelList) 3353{ 3354 ArmLIR *pcrLabel = NULL; 3355 3356 /* An invoke with the MIR_INLINED is effectively a no-op */ 3357 if (mir->OptimizationFlags & MIR_INLINED) 3358 return false; 3359 3360 DecodedInstruction *dInsn = &mir->dalvikInsn; 3361 switch (mir->dalvikInsn.opcode) { 3362 /* calleeMethod = this->clazz->vtable[BBBB] */ 3363 case OP_INVOKE_VIRTUAL_QUICK_RANGE: 3364 case OP_INVOKE_VIRTUAL_QUICK: { 3365 int methodIndex = dInsn->vB; 3366 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id]; 3367 ArmLIR *predChainingCell = &labelList[bb->taken->id]; 3368 3369 /* 3370 * If the invoke has non-null misPredBranchOver, we need to generate 3371 * the non-inlined version of the invoke here to handle the 3372 * mispredicted case. 3373 */ 3374 if (mir->meta.callsiteInfo->misPredBranchOver) { 3375 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList); 3376 } 3377 3378 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL_QUICK) 3379 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3380 else 3381 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3382 3383 3384 if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) { 3385 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3386 void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns); 3387 assert(calleeAddr); 3388 genInvokeVirtualWholeMethod(cUnit, mir, calleeAddr, 3389 retChainingCell); 3390 } 3391 3392 genInvokeVirtualCommon(cUnit, mir, methodIndex, 3393 retChainingCell, 3394 predChainingCell, 3395 pcrLabel); 3396 break; 3397 } 3398 /* calleeMethod = method->clazz->super->vtable[BBBB] */ 3399 case OP_INVOKE_SUPER_QUICK: 3400 case OP_INVOKE_SUPER_QUICK_RANGE: { 3401 /* Grab the method ptr directly from what the interpreter sees */ 3402 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3403 assert(calleeMethod == 3404 cUnit->method->clazz->super->vtable[dInsn->vB]); 3405 3406 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER_QUICK) 3407 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3408 else 3409 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3410 3411 /* r0 = calleeMethod */ 3412 loadConstant(cUnit, r0, (int) calleeMethod); 3413 3414 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 3415 calleeMethod); 3416 break; 3417 } 3418 default: 3419 return true; 3420 } 3421 return false; 3422} 3423 3424/* 3425 * This operation is complex enough that we'll do it partly inline 3426 * and partly with a handler. NOTE: the handler uses hardcoded 3427 * values for string object offsets and must be revisitied if the 3428 * layout changes. 3429 */ 3430static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir) 3431{ 3432#if defined(USE_GLOBAL_STRING_DEFS) 3433 return handleExecuteInlineC(cUnit, mir); 3434#else 3435 ArmLIR *rollback; 3436 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0); 3437 RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1); 3438 3439 loadValueDirectFixed(cUnit, rlThis, r0); 3440 loadValueDirectFixed(cUnit, rlComp, r1); 3441 /* Test objects for NULL */ 3442 rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL); 3443 genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback); 3444 /* 3445 * TUNING: we could check for object pointer equality before invoking 3446 * handler. Unclear whether the gain would be worth the added code size 3447 * expansion. 3448 */ 3449 genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO); 3450 storeValue(cUnit, inlinedTarget(cUnit, mir, false), 3451 dvmCompilerGetReturn(cUnit)); 3452 return false; 3453#endif 3454} 3455 3456static bool genInlinedFastIndexOf(CompilationUnit *cUnit, MIR *mir) 3457{ 3458#if defined(USE_GLOBAL_STRING_DEFS) 3459 return handleExecuteInlineC(cUnit, mir); 3460#else 3461 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0); 3462 RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1); 3463 3464 loadValueDirectFixed(cUnit, rlThis, r0); 3465 loadValueDirectFixed(cUnit, rlChar, r1); 3466 RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2); 3467 loadValueDirectFixed(cUnit, rlStart, r2); 3468 /* Test objects for NULL */ 3469 genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL); 3470 genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF); 3471 storeValue(cUnit, inlinedTarget(cUnit, mir, false), 3472 dvmCompilerGetReturn(cUnit)); 3473 return false; 3474#endif 3475} 3476 3477// Generates an inlined String.isEmpty or String.length. 3478static bool genInlinedStringIsEmptyOrLength(CompilationUnit *cUnit, MIR *mir, 3479 bool isEmpty) 3480{ 3481 // dst = src.length(); 3482 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0); 3483 RegLocation rlDest = inlinedTarget(cUnit, mir, false); 3484 rlObj = loadValue(cUnit, rlObj, kCoreReg); 3485 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 3486 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL); 3487 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, 3488 rlResult.lowReg); 3489 if (isEmpty) { 3490 // dst = (dst == 0); 3491 int tReg = dvmCompilerAllocTemp(cUnit); 3492 opRegReg(cUnit, kOpNeg, tReg, rlResult.lowReg); 3493 opRegRegReg(cUnit, kOpAdc, rlResult.lowReg, rlResult.lowReg, tReg); 3494 } 3495 storeValue(cUnit, rlDest, rlResult); 3496 return false; 3497} 3498 3499static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir) 3500{ 3501 return genInlinedStringIsEmptyOrLength(cUnit, mir, false); 3502} 3503 3504static bool genInlinedStringIsEmpty(CompilationUnit *cUnit, MIR *mir) 3505{ 3506 return genInlinedStringIsEmptyOrLength(cUnit, mir, true); 3507} 3508 3509static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir) 3510{ 3511 int contents = OFFSETOF_MEMBER(ArrayObject, contents); 3512 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0); 3513 RegLocation rlIdx = dvmCompilerGetSrc(cUnit, mir, 1); 3514 RegLocation rlDest = inlinedTarget(cUnit, mir, false); 3515 RegLocation rlResult; 3516 rlObj = loadValue(cUnit, rlObj, kCoreReg); 3517 rlIdx = loadValue(cUnit, rlIdx, kCoreReg); 3518 int regMax = dvmCompilerAllocTemp(cUnit); 3519 int regOff = dvmCompilerAllocTemp(cUnit); 3520 int regPtr = dvmCompilerAllocTemp(cUnit); 3521 ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, 3522 mir->offset, NULL); 3523 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax); 3524 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff); 3525 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr); 3526 genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel); 3527 dvmCompilerFreeTemp(cUnit, regMax); 3528 opRegImm(cUnit, kOpAdd, regPtr, contents); 3529 opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg); 3530 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 3531 loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf); 3532 storeValue(cUnit, rlDest, rlResult); 3533 return false; 3534} 3535 3536static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir) 3537{ 3538 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 3539 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 3540 RegLocation rlDest = inlinedTarget(cUnit, mir, false); 3541 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 3542 int signReg = dvmCompilerAllocTemp(cUnit); 3543 /* 3544 * abs(x) = y<=x>>31, (x+y)^y. 3545 * Thumb2's IT block also yields 3 instructions, but imposes 3546 * scheduling constraints. 3547 */ 3548 opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31); 3549 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg); 3550 opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg); 3551 storeValue(cUnit, rlDest, rlResult); 3552 return false; 3553} 3554 3555static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir) 3556{ 3557 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 3558 RegLocation rlDest = inlinedTargetWide(cUnit, mir, false); 3559 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); 3560 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 3561 int signReg = dvmCompilerAllocTemp(cUnit); 3562 /* 3563 * abs(x) = y<=x>>31, (x+y)^y. 3564 * Thumb2 IT block allows slightly shorter sequence, 3565 * but introduces a scheduling barrier. Stick with this 3566 * mechanism for now. 3567 */ 3568 opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31); 3569 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg); 3570 opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg); 3571 opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg); 3572 opRegReg(cUnit, kOpXor, rlResult.highReg, signReg); 3573 storeValueWide(cUnit, rlDest, rlResult); 3574 return false; 3575} 3576 3577static bool genInlinedIntFloatConversion(CompilationUnit *cUnit, MIR *mir) 3578{ 3579 // Just move from source to destination... 3580 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 3581 RegLocation rlDest = inlinedTarget(cUnit, mir, false); 3582 storeValue(cUnit, rlDest, rlSrc); 3583 return false; 3584} 3585 3586static bool genInlinedLongDoubleConversion(CompilationUnit *cUnit, MIR *mir) 3587{ 3588 // Just move from source to destination... 3589 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 3590 RegLocation rlDest = inlinedTargetWide(cUnit, mir, false); 3591 storeValueWide(cUnit, rlDest, rlSrc); 3592 return false; 3593} 3594 3595/* 3596 * JITs a call to a C function. 3597 * TODO: use this for faster native method invocation for simple native 3598 * methods (http://b/3069458). 3599 */ 3600static bool handleExecuteInlineC(CompilationUnit *cUnit, MIR *mir) 3601{ 3602 DecodedInstruction *dInsn = &mir->dalvikInsn; 3603 int operation = dInsn->vB; 3604 unsigned int i; 3605 const InlineOperation* inLineTable = dvmGetInlineOpsTable(); 3606 uintptr_t fn = (int) inLineTable[operation].func; 3607 if (fn == 0) { 3608 dvmCompilerAbort(cUnit); 3609 } 3610 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 3611 dvmCompilerClobberCallRegs(cUnit); 3612 dvmCompilerClobber(cUnit, r4PC); 3613 dvmCompilerClobber(cUnit, r7); 3614 int offset = offsetof(Thread, interpSave.retval); 3615 opRegRegImm(cUnit, kOpAdd, r4PC, r6SELF, offset); 3616 opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7)); 3617 LOAD_FUNC_ADDR(cUnit, r4PC, fn); 3618 genExportPC(cUnit, mir); 3619 for (i=0; i < dInsn->vA; i++) { 3620 loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i); 3621 } 3622 opReg(cUnit, kOpBlx, r4PC); 3623 opRegImm(cUnit, kOpAdd, r13sp, 8); 3624 /* NULL? */ 3625 ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0); 3626 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset)); 3627 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 3628 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 3629 target->defMask = ENCODE_ALL; 3630 branchOver->generic.target = (LIR *) target; 3631 return false; 3632} 3633 3634/* 3635 * NOTE: Handles both range and non-range versions (arguments 3636 * have already been normalized by this point). 3637 */ 3638static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir) 3639{ 3640 DecodedInstruction *dInsn = &mir->dalvikInsn; 3641 assert(dInsn->opcode == OP_EXECUTE_INLINE_RANGE || 3642 dInsn->opcode == OP_EXECUTE_INLINE); 3643 switch (dInsn->vB) { 3644 case INLINE_EMPTYINLINEMETHOD: 3645 return false; /* Nop */ 3646 3647 /* These ones we potentially JIT inline. */ 3648 case INLINE_STRING_LENGTH: 3649 return genInlinedStringLength(cUnit, mir); 3650 case INLINE_STRING_IS_EMPTY: 3651 return genInlinedStringIsEmpty(cUnit, mir); 3652 case INLINE_MATH_ABS_INT: 3653 return genInlinedAbsInt(cUnit, mir); 3654 case INLINE_MATH_ABS_LONG: 3655 return genInlinedAbsLong(cUnit, mir); 3656 case INLINE_MATH_MIN_INT: 3657 return genInlinedMinMaxInt(cUnit, mir, true); 3658 case INLINE_MATH_MAX_INT: 3659 return genInlinedMinMaxInt(cUnit, mir, false); 3660 case INLINE_STRING_CHARAT: 3661 return genInlinedStringCharAt(cUnit, mir); 3662 case INLINE_MATH_SQRT: 3663 return genInlineSqrt(cUnit, mir); 3664 case INLINE_MATH_ABS_FLOAT: 3665 return genInlinedAbsFloat(cUnit, mir); 3666 case INLINE_MATH_ABS_DOUBLE: 3667 return genInlinedAbsDouble(cUnit, mir); 3668 case INLINE_STRING_COMPARETO: 3669 return genInlinedCompareTo(cUnit, mir); 3670 case INLINE_STRING_FASTINDEXOF_II: 3671 return genInlinedFastIndexOf(cUnit, mir); 3672 case INLINE_FLOAT_TO_RAW_INT_BITS: 3673 case INLINE_INT_BITS_TO_FLOAT: 3674 return genInlinedIntFloatConversion(cUnit, mir); 3675 case INLINE_DOUBLE_TO_RAW_LONG_BITS: 3676 case INLINE_LONG_BITS_TO_DOUBLE: 3677 return genInlinedLongDoubleConversion(cUnit, mir); 3678 3679 /* 3680 * These ones we just JIT a call to a C function for. 3681 * TODO: special-case these in the other "invoke" call paths. 3682 */ 3683 case INLINE_STRING_EQUALS: 3684 case INLINE_MATH_COS: 3685 case INLINE_MATH_SIN: 3686 case INLINE_FLOAT_TO_INT_BITS: 3687 case INLINE_DOUBLE_TO_LONG_BITS: 3688 return handleExecuteInlineC(cUnit, mir); 3689 } 3690 dvmCompilerAbort(cUnit); 3691 return false; // Not reachable; keeps compiler happy. 3692} 3693 3694static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir) 3695{ 3696 //TUNING: We're using core regs here - not optimal when target is a double 3697 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 3698 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 3699 loadConstantNoClobber(cUnit, rlResult.lowReg, 3700 mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL); 3701 loadConstantNoClobber(cUnit, rlResult.highReg, 3702 (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL); 3703 storeValueWide(cUnit, rlDest, rlResult); 3704 return false; 3705} 3706 3707/* 3708 * The following are special processing routines that handle transfer of 3709 * controls between compiled code and the interpreter. Certain VM states like 3710 * Dalvik PC and special-purpose registers are reconstructed here. 3711 */ 3712 3713/* 3714 * Insert a 3715 * b .+4 3716 * nop 3717 * pair at the beginning of a chaining cell. This serves as the 3718 * switch branch that selects between reverting to the interpreter or 3719 * not. Once the cell is chained to a translation, the cell will 3720 * contain a 32-bit branch. Subsequent chain/unchain operations will 3721 * then only alter that first 16-bits - the "b .+4" for unchaining, 3722 * and the restoration of the first half of the 32-bit branch for 3723 * rechaining. 3724 */ 3725static void insertChainingSwitch(CompilationUnit *cUnit) 3726{ 3727 ArmLIR *branch = newLIR0(cUnit, kThumbBUncond); 3728 newLIR2(cUnit, kThumbOrr, r0, r0); 3729 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 3730 target->defMask = ENCODE_ALL; 3731 branch->generic.target = (LIR *) target; 3732} 3733 3734/* Chaining cell for code that may need warmup. */ 3735static void handleNormalChainingCell(CompilationUnit *cUnit, 3736 unsigned int offset) 3737{ 3738 /* 3739 * Use raw instruction constructors to guarantee that the generated 3740 * instructions fit the predefined cell size. 3741 */ 3742 insertChainingSwitch(cUnit); 3743 newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF, 3744 offsetof(Thread, 3745 jitToInterpEntries.dvmJitToInterpNormal) >> 2); 3746 newLIR1(cUnit, kThumbBlxR, r0); 3747 addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset)); 3748} 3749 3750/* 3751 * Chaining cell for instructions that immediately following already translated 3752 * code. 3753 */ 3754static void handleHotChainingCell(CompilationUnit *cUnit, 3755 unsigned int offset) 3756{ 3757 /* 3758 * Use raw instruction constructors to guarantee that the generated 3759 * instructions fit the predefined cell size. 3760 */ 3761 insertChainingSwitch(cUnit); 3762 newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF, 3763 offsetof(Thread, 3764 jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2); 3765 newLIR1(cUnit, kThumbBlxR, r0); 3766 addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset)); 3767} 3768 3769/* Chaining cell for branches that branch back into the same basic block */ 3770static void handleBackwardBranchChainingCell(CompilationUnit *cUnit, 3771 unsigned int offset) 3772{ 3773 /* 3774 * Use raw instruction constructors to guarantee that the generated 3775 * instructions fit the predefined cell size. 3776 */ 3777 insertChainingSwitch(cUnit); 3778#if defined(WITH_SELF_VERIFICATION) 3779 newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF, 3780 offsetof(Thread, 3781 jitToInterpEntries.dvmJitToInterpBackwardBranch) >> 2); 3782#else 3783 newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF, 3784 offsetof(Thread, jitToInterpEntries.dvmJitToInterpNormal) >> 2); 3785#endif 3786 newLIR1(cUnit, kThumbBlxR, r0); 3787 addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset)); 3788} 3789 3790/* Chaining cell for monomorphic method invocations. */ 3791static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit, 3792 const Method *callee) 3793{ 3794 /* 3795 * Use raw instruction constructors to guarantee that the generated 3796 * instructions fit the predefined cell size. 3797 */ 3798 insertChainingSwitch(cUnit); 3799 newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF, 3800 offsetof(Thread, 3801 jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2); 3802 newLIR1(cUnit, kThumbBlxR, r0); 3803 addWordData(cUnit, NULL, (int) (callee->insns)); 3804} 3805 3806/* Chaining cell for monomorphic method invocations. */ 3807static void handleInvokePredictedChainingCell(CompilationUnit *cUnit) 3808{ 3809 3810 /* Should not be executed in the initial state */ 3811 addWordData(cUnit, NULL, PREDICTED_CHAIN_BX_PAIR_INIT); 3812 /* To be filled: class */ 3813 addWordData(cUnit, NULL, PREDICTED_CHAIN_CLAZZ_INIT); 3814 /* To be filled: method */ 3815 addWordData(cUnit, NULL, PREDICTED_CHAIN_METHOD_INIT); 3816 /* 3817 * Rechain count. The initial value of 0 here will trigger chaining upon 3818 * the first invocation of this callsite. 3819 */ 3820 addWordData(cUnit, NULL, PREDICTED_CHAIN_COUNTER_INIT); 3821} 3822 3823/* Load the Dalvik PC into r0 and jump to the specified target */ 3824static void handlePCReconstruction(CompilationUnit *cUnit, 3825 ArmLIR *targetLabel) 3826{ 3827 ArmLIR **pcrLabel = 3828 (ArmLIR **) cUnit->pcReconstructionList.elemList; 3829 int numElems = cUnit->pcReconstructionList.numUsed; 3830 int i; 3831 3832 /* 3833 * We should never reach here through fall-through code, so insert 3834 * a bomb to signal troubles immediately. 3835 */ 3836 if (numElems) { 3837 newLIR0(cUnit, kThumbUndefined); 3838 } 3839 3840 for (i = 0; i < numElems; i++) { 3841 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]); 3842 /* r0 = dalvik PC */ 3843 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]); 3844 genUnconditionalBranch(cUnit, targetLabel); 3845 } 3846} 3847 3848static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = { 3849 "kMirOpPhi", 3850 "kMirOpNullNRangeUpCheck", 3851 "kMirOpNullNRangeDownCheck", 3852 "kMirOpLowerBound", 3853 "kMirOpPunt", 3854 "kMirOpCheckInlinePrediction", 3855}; 3856 3857/* 3858 * vA = arrayReg; 3859 * vB = idxReg; 3860 * vC = endConditionReg; 3861 * arg[0] = maxC 3862 * arg[1] = minC 3863 * arg[2] = loopBranchConditionCode 3864 */ 3865static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir) 3866{ 3867 /* 3868 * NOTE: these synthesized blocks don't have ssa names assigned 3869 * for Dalvik registers. However, because they dominate the following 3870 * blocks we can simply use the Dalvik name w/ subscript 0 as the 3871 * ssa name. 3872 */ 3873 DecodedInstruction *dInsn = &mir->dalvikInsn; 3874 const int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); 3875 const int maxC = dInsn->arg[0]; 3876 int regLength; 3877 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA]; 3878 RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC]; 3879 3880 /* regArray <- arrayRef */ 3881 rlArray = loadValue(cUnit, rlArray, kCoreReg); 3882 rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg); 3883 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0, 3884 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3885 3886 /* regLength <- len(arrayRef) */ 3887 regLength = dvmCompilerAllocTemp(cUnit); 3888 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength); 3889 3890 int delta = maxC; 3891 /* 3892 * If the loop end condition is ">=" instead of ">", then the largest value 3893 * of the index is "endCondition - 1". 3894 */ 3895 if (dInsn->arg[2] == OP_IF_GE) { 3896 delta--; 3897 } 3898 3899 if (delta) { 3900 int tReg = dvmCompilerAllocTemp(cUnit); 3901 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta); 3902 rlIdxEnd.lowReg = tReg; 3903 dvmCompilerFreeTemp(cUnit, tReg); 3904 } 3905 /* Punt if "regIdxEnd < len(Array)" is false */ 3906 genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0, 3907 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3908} 3909 3910/* 3911 * vA = arrayReg; 3912 * vB = idxReg; 3913 * vC = endConditionReg; 3914 * arg[0] = maxC 3915 * arg[1] = minC 3916 * arg[2] = loopBranchConditionCode 3917 */ 3918static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir) 3919{ 3920 DecodedInstruction *dInsn = &mir->dalvikInsn; 3921 const int lenOffset = OFFSETOF_MEMBER(ArrayObject, length); 3922 const int regLength = dvmCompilerAllocTemp(cUnit); 3923 const int maxC = dInsn->arg[0]; 3924 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA]; 3925 RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB]; 3926 3927 /* regArray <- arrayRef */ 3928 rlArray = loadValue(cUnit, rlArray, kCoreReg); 3929 rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg); 3930 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0, 3931 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3932 3933 /* regLength <- len(arrayRef) */ 3934 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength); 3935 3936 if (maxC) { 3937 int tReg = dvmCompilerAllocTemp(cUnit); 3938 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC); 3939 rlIdxInit.lowReg = tReg; 3940 dvmCompilerFreeTemp(cUnit, tReg); 3941 } 3942 3943 /* Punt if "regIdxInit < len(Array)" is false */ 3944 genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0, 3945 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3946} 3947 3948/* 3949 * vA = idxReg; 3950 * vB = minC; 3951 */ 3952static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir) 3953{ 3954 DecodedInstruction *dInsn = &mir->dalvikInsn; 3955 const int minC = dInsn->vB; 3956 RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA]; 3957 3958 /* regIdx <- initial index value */ 3959 rlIdx = loadValue(cUnit, rlIdx, kCoreReg); 3960 3961 /* Punt if "regIdxInit + minC >= 0" is false */ 3962 genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0, 3963 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3964} 3965 3966/* 3967 * vC = this 3968 * 3969 * A predicted inlining target looks like the following, where instructions 3970 * between 0x4858de66 and 0x4858de72 are checking if the predicted class 3971 * matches "this", and the verificaion code is generated by this routine. 3972 * 3973 * (C) means the instruction is inlined from the callee, and (PI) means the 3974 * instruction is the predicted inlined invoke, whose corresponding 3975 * instructions are still generated to handle the mispredicted case. 3976 * 3977 * D/dalvikvm( 86): -------- kMirOpCheckInlinePrediction 3978 * D/dalvikvm( 86): 0x4858de66 (0002): ldr r0, [r5, #68] 3979 * D/dalvikvm( 86): 0x4858de68 (0004): ldr r1, [pc, #140] 3980 * D/dalvikvm( 86): 0x4858de6a (0006): cmp r0, #0 3981 * D/dalvikvm( 86): 0x4858de6c (0008): beq 0x4858deb2 3982 * D/dalvikvm( 86): 0x4858de6e (000a): ldr r2, [r0, #0] 3983 * D/dalvikvm( 86): 0x4858de70 (000c): cmp r1, r2 3984 * D/dalvikvm( 86): 0x4858de72 (000e): bne 0x4858de7a 3985 * D/dalvikvm( 86): -------- dalvik offset: 0x004c @ +iget-object-quick (C) 3986 * v4, v17, (#8) 3987 * D/dalvikvm( 86): 0x4858de74 (0010): ldr r3, [r0, #8] 3988 * D/dalvikvm( 86): 0x4858de76 (0012): str r3, [r5, #16] 3989 * D/dalvikvm( 86): -------- dalvik offset: 0x004c @ 3990 * +invoke-virtual-quick/range (PI) v17..v17 3991 * D/dalvikvm( 86): 0x4858de78 (0014): b 0x4858debc 3992 * D/dalvikvm( 86): 0x4858de7a (0016): add r4,r5,#68 3993 * D/dalvikvm( 86): -------- BARRIER 3994 * D/dalvikvm( 86): 0x4858de7e (001a): ldmia r4, <r0> 3995 * D/dalvikvm( 86): -------- BARRIER 3996 * D/dalvikvm( 86): 0x4858de80 (001c): sub r7,r5,#24 3997 * D/dalvikvm( 86): 0x4858de84 (0020): cmp r0, #0 3998 * D/dalvikvm( 86): 0x4858de86 (0022): beq 0x4858deb6 3999 * D/dalvikvm( 86): -------- BARRIER 4000 * D/dalvikvm( 86): 0x4858de88 (0024): stmia r7, <r0> 4001 * D/dalvikvm( 86): -------- BARRIER 4002 * D/dalvikvm( 86): 0x4858de8a (0026): ldr r4, [pc, #104] 4003 * D/dalvikvm( 86): 0x4858de8c (0028): add r1, pc, #28 4004 * D/dalvikvm( 86): 0x4858de8e (002a): add r2, pc, #56 4005 * D/dalvikvm( 86): 0x4858de90 (002c): blx_1 0x48589198 4006 * D/dalvikvm( 86): 0x4858de92 (002e): blx_2 see above 4007 * D/dalvikvm( 86): 0x4858de94 (0030): b 0x4858dec8 4008 * D/dalvikvm( 86): 0x4858de96 (0032): b 0x4858deb6 4009 * D/dalvikvm( 86): 0x4858de98 (0034): ldr r0, [r7, #72] 4010 * D/dalvikvm( 86): 0x4858de9a (0036): cmp r1, #0 4011 * D/dalvikvm( 86): 0x4858de9c (0038): bgt 0x4858dea4 4012 * D/dalvikvm( 86): 0x4858de9e (003a): ldr r7, [r6, #116] 4013 * D/dalvikvm( 86): 0x4858dea0 (003c): movs r1, r6 4014 * D/dalvikvm( 86): 0x4858dea2 (003e): blx r7 4015 * D/dalvikvm( 86): 0x4858dea4 (0040): add r1, pc, #4 4016 * D/dalvikvm( 86): 0x4858dea6 (0042): blx_1 0x485890a0 4017 * D/dalvikvm( 86): 0x4858dea8 (0044): blx_2 see above 4018 * D/dalvikvm( 86): 0x4858deaa (0046): b 0x4858deb6 4019 * D/dalvikvm( 86): 0x4858deac (0048): .align4 4020 * D/dalvikvm( 86): L0x004f: 4021 * D/dalvikvm( 86): -------- dalvik offset: 0x004f @ move-result-object (PI) 4022 * v4, (#0), (#0) 4023 * D/dalvikvm( 86): 0x4858deac (0048): ldr r4, [r6, #8] 4024 * D/dalvikvm( 86): 0x4858deae (004a): str r4, [r5, #16] 4025 * D/dalvikvm( 86): 0x4858deb0 (004c): b 0x4858debc 4026 * D/dalvikvm( 86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c 4027 * D/dalvikvm( 86): 0x4858deb2 (004e): ldr r0, [pc, #64] 4028 * D/dalvikvm( 86): 0x4858deb4 (0050): b 0x4858deb8 4029 * D/dalvikvm( 86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c 4030 * D/dalvikvm( 86): 0x4858deb6 (0052): ldr r0, [pc, #60] 4031 * D/dalvikvm( 86): Exception_Handling: 4032 * D/dalvikvm( 86): 0x4858deb8 (0054): ldr r1, [r6, #100] 4033 * D/dalvikvm( 86): 0x4858deba (0056): blx r1 4034 * D/dalvikvm( 86): 0x4858debc (0058): .align4 4035 * D/dalvikvm( 86): -------- chaining cell (hot): 0x0050 4036 * D/dalvikvm( 86): 0x4858debc (0058): b 0x4858dec0 4037 * D/dalvikvm( 86): 0x4858debe (005a): orrs r0, r0 4038 * D/dalvikvm( 86): 0x4858dec0 (005c): ldr r0, [r6, #112] 4039 * D/dalvikvm( 86): 0x4858dec2 (005e): blx r0 4040 * D/dalvikvm( 86): 0x4858dec4 (0060): data 0xefd4(61396) 4041 * D/dalvikvm( 86): 0x4858dec6 (0062): data 0x42be(17086) 4042 * D/dalvikvm( 86): 0x4858dec8 (0064): .align4 4043 * D/dalvikvm( 86): -------- chaining cell (predicted) 4044 * D/dalvikvm( 86): 0x4858dec8 (0064): data 0xe7fe(59390) 4045 * D/dalvikvm( 86): 0x4858deca (0066): data 0x0000(0) 4046 * D/dalvikvm( 86): 0x4858decc (0068): data 0x0000(0) 4047 * D/dalvikvm( 86): 0x4858dece (006a): data 0x0000(0) 4048 * : 4049 */ 4050static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir) 4051{ 4052 CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo; 4053 RegLocation rlThis = cUnit->regLocation[mir->dalvikInsn.vC]; 4054 4055 rlThis = loadValue(cUnit, rlThis, kCoreReg); 4056 int regPredictedClass = dvmCompilerAllocTemp(cUnit); 4057 loadClassPointer(cUnit, regPredictedClass, (int) callsiteInfo); 4058 genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset, 4059 NULL);/* null object? */ 4060 int regActualClass = dvmCompilerAllocTemp(cUnit); 4061 loadWordDisp(cUnit, rlThis.lowReg, offsetof(Object, clazz), regActualClass); 4062 opRegReg(cUnit, kOpCmp, regPredictedClass, regActualClass); 4063 /* 4064 * Set the misPredBranchOver target so that it will be generated when the 4065 * code for the non-optimized invoke is generated. 4066 */ 4067 callsiteInfo->misPredBranchOver = (LIR *) opCondBranch(cUnit, kArmCondNe); 4068} 4069 4070/* Extended MIR instructions like PHI */ 4071static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir) 4072{ 4073 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst; 4074 char *msg = (char *)dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1, 4075 false); 4076 strcpy(msg, extendedMIROpNames[opOffset]); 4077 newLIR1(cUnit, kArmPseudoExtended, (int) msg); 4078 4079 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) { 4080 case kMirOpPhi: { 4081 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep); 4082 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString); 4083 break; 4084 } 4085 case kMirOpNullNRangeUpCheck: { 4086 genHoistedChecksForCountUpLoop(cUnit, mir); 4087 break; 4088 } 4089 case kMirOpNullNRangeDownCheck: { 4090 genHoistedChecksForCountDownLoop(cUnit, mir); 4091 break; 4092 } 4093 case kMirOpLowerBound: { 4094 genHoistedLowerBoundCheck(cUnit, mir); 4095 break; 4096 } 4097 case kMirOpPunt: { 4098 genUnconditionalBranch(cUnit, 4099 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 4100 break; 4101 } 4102 case kMirOpCheckInlinePrediction: { 4103 genValidationForPredictedInline(cUnit, mir); 4104 break; 4105 } 4106 default: 4107 break; 4108 } 4109} 4110 4111/* 4112 * Create a PC-reconstruction cell for the starting offset of this trace. 4113 * Since the PCR cell is placed near the end of the compiled code which is 4114 * usually out of range for a conditional branch, we put two branches (one 4115 * branch over to the loop body and one layover branch to the actual PCR) at the 4116 * end of the entry block. 4117 */ 4118static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry, 4119 ArmLIR *bodyLabel) 4120{ 4121 /* Set up the place holder to reconstruct this Dalvik PC */ 4122 ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); 4123 pcrLabel->opcode = kArmPseudoPCReconstructionCell; 4124 pcrLabel->operands[0] = 4125 (int) (cUnit->method->insns + entry->startOffset); 4126 pcrLabel->operands[1] = entry->startOffset; 4127 /* Insert the place holder to the growable list */ 4128 dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel); 4129 4130 /* 4131 * Next, create two branches - one branch over to the loop body and the 4132 * other branch to the PCR cell to punt. 4133 */ 4134 ArmLIR *branchToBody = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); 4135 branchToBody->opcode = kThumbBUncond; 4136 branchToBody->generic.target = (LIR *) bodyLabel; 4137 setupResourceMasks(branchToBody); 4138 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody; 4139 4140 ArmLIR *branchToPCR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); 4141 branchToPCR->opcode = kThumbBUncond; 4142 branchToPCR->generic.target = (LIR *) pcrLabel; 4143 setupResourceMasks(branchToPCR); 4144 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR; 4145} 4146 4147#if defined(WITH_SELF_VERIFICATION) 4148static bool selfVerificationPuntOps(MIR *mir) 4149{ 4150 DecodedInstruction *decInsn = &mir->dalvikInsn; 4151 4152 /* 4153 * All opcodes that can throw exceptions and use the 4154 * TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace 4155 * under self-verification mode. 4156 */ 4157 switch (decInsn->opcode) { 4158 case OP_MONITOR_ENTER: 4159 case OP_MONITOR_EXIT: 4160 case OP_NEW_INSTANCE: 4161 case OP_NEW_ARRAY: 4162 case OP_CHECK_CAST: 4163 case OP_MOVE_EXCEPTION: 4164 case OP_FILL_ARRAY_DATA: 4165 case OP_EXECUTE_INLINE: 4166 case OP_EXECUTE_INLINE_RANGE: 4167 return true; 4168 default: 4169 return false; 4170 } 4171} 4172#endif 4173 4174void dvmCompilerMIR2LIR(CompilationUnit *cUnit) 4175{ 4176 /* Used to hold the labels of each block */ 4177 ArmLIR *labelList = 4178 (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true); 4179 ArmLIR *headLIR = NULL; 4180 GrowableList chainingListByType[kChainingCellGap]; 4181 int i; 4182 4183 /* 4184 * Initialize various types chaining lists. 4185 */ 4186 for (i = 0; i < kChainingCellGap; i++) { 4187 dvmInitGrowableList(&chainingListByType[i], 2); 4188 } 4189 4190 /* Clear the visited flag for each block */ 4191 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerClearVisitedFlag, 4192 kAllNodes, false /* isIterative */); 4193 4194 GrowableListIterator iterator; 4195 dvmGrowableListIteratorInit(&cUnit->blockList, &iterator); 4196 4197 /* Traces start with a profiling entry point. Generate it here */ 4198 cUnit->profileCodeSize = genTraceProfileEntry(cUnit); 4199 4200 /* Handle the content in each basic block */ 4201 for (i = 0; ; i++) { 4202 MIR *mir; 4203 BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator); 4204 if (bb == NULL) break; 4205 if (bb->visited == true) continue; 4206 4207 labelList[i].operands[0] = bb->startOffset; 4208 4209 if (bb->blockType >= kChainingCellGap) { 4210 if (bb->isFallThroughFromInvoke == true) { 4211 /* Align this block first since it is a return chaining cell */ 4212 newLIR0(cUnit, kArmPseudoPseudoAlign4); 4213 } 4214 /* 4215 * Append the label pseudo LIR first. Chaining cells will be handled 4216 * separately afterwards. 4217 */ 4218 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]); 4219 } 4220 4221 if (bb->blockType == kEntryBlock) { 4222 labelList[i].opcode = kArmPseudoEntryBlock; 4223 if (bb->firstMIRInsn == NULL) { 4224 continue; 4225 } else { 4226 setupLoopEntryBlock(cUnit, bb, 4227 &labelList[bb->fallThrough->id]); 4228 } 4229 } else if (bb->blockType == kExitBlock) { 4230 labelList[i].opcode = kArmPseudoExitBlock; 4231 goto gen_fallthrough; 4232 } else if (bb->blockType == kDalvikByteCode) { 4233 if (bb->hidden == true) continue; 4234 labelList[i].opcode = kArmPseudoNormalBlockLabel; 4235 /* Reset the register state */ 4236 dvmCompilerResetRegPool(cUnit); 4237 dvmCompilerClobberAllRegs(cUnit); 4238 dvmCompilerResetNullCheck(cUnit); 4239 } else { 4240 switch (bb->blockType) { 4241 case kChainingCellNormal: 4242 labelList[i].opcode = kArmPseudoChainingCellNormal; 4243 /* handle the codegen later */ 4244 dvmInsertGrowableList( 4245 &chainingListByType[kChainingCellNormal], i); 4246 break; 4247 case kChainingCellInvokeSingleton: 4248 labelList[i].opcode = 4249 kArmPseudoChainingCellInvokeSingleton; 4250 labelList[i].operands[0] = 4251 (int) bb->containingMethod; 4252 /* handle the codegen later */ 4253 dvmInsertGrowableList( 4254 &chainingListByType[kChainingCellInvokeSingleton], i); 4255 break; 4256 case kChainingCellInvokePredicted: 4257 labelList[i].opcode = 4258 kArmPseudoChainingCellInvokePredicted; 4259 /* 4260 * Move the cached method pointer from operand 1 to 0. 4261 * Operand 0 was clobbered earlier in this routine to store 4262 * the block starting offset, which is not applicable to 4263 * predicted chaining cell. 4264 */ 4265 labelList[i].operands[0] = labelList[i].operands[1]; 4266 /* handle the codegen later */ 4267 dvmInsertGrowableList( 4268 &chainingListByType[kChainingCellInvokePredicted], i); 4269 break; 4270 case kChainingCellHot: 4271 labelList[i].opcode = 4272 kArmPseudoChainingCellHot; 4273 /* handle the codegen later */ 4274 dvmInsertGrowableList( 4275 &chainingListByType[kChainingCellHot], i); 4276 break; 4277 case kPCReconstruction: 4278 /* Make sure exception handling block is next */ 4279 labelList[i].opcode = 4280 kArmPseudoPCReconstructionBlockLabel; 4281 handlePCReconstruction(cUnit, 4282 &labelList[cUnit->puntBlock->id]); 4283 break; 4284 case kExceptionHandling: 4285 labelList[i].opcode = kArmPseudoEHBlockLabel; 4286 if (cUnit->pcReconstructionList.numUsed) { 4287 loadWordDisp(cUnit, r6SELF, offsetof(Thread, 4288 jitToInterpEntries.dvmJitToInterpPunt), 4289 r1); 4290 opReg(cUnit, kOpBlx, r1); 4291 } 4292 break; 4293 case kChainingCellBackwardBranch: 4294 labelList[i].opcode = 4295 kArmPseudoChainingCellBackwardBranch; 4296 /* handle the codegen later */ 4297 dvmInsertGrowableList( 4298 &chainingListByType[kChainingCellBackwardBranch], 4299 i); 4300 break; 4301 default: 4302 break; 4303 } 4304 continue; 4305 } 4306 4307 /* 4308 * Try to build a longer optimization unit. Currently if the previous 4309 * block ends with a goto, we continue adding instructions and don't 4310 * reset the register allocation pool. 4311 */ 4312 for (BasicBlock *nextBB = bb; nextBB != NULL; nextBB = cUnit->nextCodegenBlock) { 4313 bb = nextBB; 4314 bb->visited = true; 4315 cUnit->nextCodegenBlock = NULL; 4316 4317 for (mir = bb->firstMIRInsn; mir; mir = mir->next) { 4318 4319 dvmCompilerResetRegPool(cUnit); 4320 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) { 4321 dvmCompilerClobberAllRegs(cUnit); 4322 } 4323 4324 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) { 4325 dvmCompilerResetDefTracking(cUnit); 4326 } 4327 4328 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) { 4329 handleExtendedMIR(cUnit, mir); 4330 continue; 4331 } 4332 4333 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 4334 InstructionFormat dalvikFormat = 4335 dexGetFormatFromOpcode(dalvikOpcode); 4336 const char *note; 4337 if (mir->OptimizationFlags & MIR_INLINED) { 4338 note = " (I)"; 4339 } else if (mir->OptimizationFlags & MIR_INLINED_PRED) { 4340 note = " (PI)"; 4341 } else if (mir->OptimizationFlags & MIR_CALLEE) { 4342 note = " (C)"; 4343 } else { 4344 note = NULL; 4345 } 4346 4347 ArmLIR *boundaryLIR; 4348 4349 /* 4350 * Don't generate the boundary LIR unless we are debugging this 4351 * trace or we need a scheduling barrier. 4352 */ 4353 if (headLIR == NULL || cUnit->printMe == true) { 4354 boundaryLIR = 4355 newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary, 4356 mir->offset, 4357 (int) dvmCompilerGetDalvikDisassembly( 4358 &mir->dalvikInsn, note)); 4359 /* Remember the first LIR for this block */ 4360 if (headLIR == NULL) { 4361 headLIR = boundaryLIR; 4362 /* Set the first boundaryLIR as a scheduling barrier */ 4363 headLIR->defMask = ENCODE_ALL; 4364 } 4365 } 4366 4367 /* 4368 * Don't generate the SSA annotation unless verbose mode is on 4369 */ 4370 if (cUnit->printMe && mir->ssaRep) { 4371 char *ssaString = dvmCompilerGetSSAString(cUnit, 4372 mir->ssaRep); 4373 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString); 4374 } 4375 4376 bool notHandled; 4377 /* 4378 * Debugging: screen the opcode first to see if it is in the 4379 * do[-not]-compile list 4380 */ 4381 bool singleStepMe = SINGLE_STEP_OP(dalvikOpcode); 4382#if defined(WITH_SELF_VERIFICATION) 4383 if (singleStepMe == false) { 4384 singleStepMe = selfVerificationPuntOps(mir); 4385 } 4386#endif 4387 if (singleStepMe || cUnit->allSingleStep) { 4388 notHandled = false; 4389 genInterpSingleStep(cUnit, mir); 4390 } else { 4391 opcodeCoverage[dalvikOpcode]++; 4392 switch (dalvikFormat) { 4393 case kFmt10t: 4394 case kFmt20t: 4395 case kFmt30t: 4396 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit, 4397 mir, bb, labelList); 4398 break; 4399 case kFmt10x: 4400 notHandled = handleFmt10x(cUnit, mir); 4401 break; 4402 case kFmt11n: 4403 case kFmt31i: 4404 notHandled = handleFmt11n_Fmt31i(cUnit, mir); 4405 break; 4406 case kFmt11x: 4407 notHandled = handleFmt11x(cUnit, mir); 4408 break; 4409 case kFmt12x: 4410 notHandled = handleFmt12x(cUnit, mir); 4411 break; 4412 case kFmt20bc: 4413 notHandled = handleFmt20bc(cUnit, mir); 4414 break; 4415 case kFmt21c: 4416 case kFmt31c: 4417 notHandled = handleFmt21c_Fmt31c(cUnit, mir); 4418 break; 4419 case kFmt21h: 4420 notHandled = handleFmt21h(cUnit, mir); 4421 break; 4422 case kFmt21s: 4423 notHandled = handleFmt21s(cUnit, mir); 4424 break; 4425 case kFmt21t: 4426 notHandled = handleFmt21t(cUnit, mir, bb, 4427 labelList); 4428 break; 4429 case kFmt22b: 4430 case kFmt22s: 4431 notHandled = handleFmt22b_Fmt22s(cUnit, mir); 4432 break; 4433 case kFmt22c: 4434 notHandled = handleFmt22c(cUnit, mir); 4435 break; 4436 case kFmt22cs: 4437 notHandled = handleFmt22cs(cUnit, mir); 4438 break; 4439 case kFmt22t: 4440 notHandled = handleFmt22t(cUnit, mir, bb, 4441 labelList); 4442 break; 4443 case kFmt22x: 4444 case kFmt32x: 4445 notHandled = handleFmt22x_Fmt32x(cUnit, mir); 4446 break; 4447 case kFmt23x: 4448 notHandled = handleFmt23x(cUnit, mir); 4449 break; 4450 case kFmt31t: 4451 notHandled = handleFmt31t(cUnit, mir); 4452 break; 4453 case kFmt3rc: 4454 case kFmt35c: 4455 notHandled = handleFmt35c_3rc(cUnit, mir, bb, 4456 labelList); 4457 break; 4458 case kFmt3rms: 4459 case kFmt35ms: 4460 notHandled = handleFmt35ms_3rms(cUnit, mir, bb, 4461 labelList); 4462 break; 4463 case kFmt35mi: 4464 case kFmt3rmi: 4465 notHandled = handleExecuteInline(cUnit, mir); 4466 break; 4467 case kFmt51l: 4468 notHandled = handleFmt51l(cUnit, mir); 4469 break; 4470 default: 4471 notHandled = true; 4472 break; 4473 } 4474 } 4475 if (notHandled) { 4476 ALOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled", 4477 mir->offset, 4478 dalvikOpcode, dexGetOpcodeName(dalvikOpcode), 4479 dalvikFormat); 4480 dvmCompilerAbort(cUnit); 4481 break; 4482 } 4483 } 4484 } 4485 4486 if (bb->blockType == kEntryBlock) { 4487 dvmCompilerAppendLIR(cUnit, 4488 (LIR *) cUnit->loopAnalysis->branchToBody); 4489 dvmCompilerAppendLIR(cUnit, 4490 (LIR *) cUnit->loopAnalysis->branchToPCR); 4491 } 4492 4493 if (headLIR) { 4494 /* 4495 * Eliminate redundant loads/stores and delay stores into later 4496 * slots 4497 */ 4498 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR, 4499 cUnit->lastLIRInsn); 4500 /* Reset headLIR which is also the optimization boundary */ 4501 headLIR = NULL; 4502 } 4503 4504gen_fallthrough: 4505 /* 4506 * Check if the block is terminated due to trace length constraint - 4507 * insert an unconditional branch to the chaining cell. 4508 */ 4509 if (bb->needFallThroughBranch) { 4510 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); 4511 } 4512 } 4513 4514 /* Handle the chaining cells in predefined order */ 4515 for (i = 0; i < kChainingCellGap; i++) { 4516 size_t j; 4517 int *blockIdList = (int *) chainingListByType[i].elemList; 4518 4519 cUnit->numChainingCells[i] = chainingListByType[i].numUsed; 4520 4521 /* No chaining cells of this type */ 4522 if (cUnit->numChainingCells[i] == 0) 4523 continue; 4524 4525 /* Record the first LIR for a new type of chaining cell */ 4526 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]]; 4527 4528 for (j = 0; j < chainingListByType[i].numUsed; j++) { 4529 int blockId = blockIdList[j]; 4530 BasicBlock *chainingBlock = 4531 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 4532 blockId); 4533 4534 /* Align this chaining cell first */ 4535 newLIR0(cUnit, kArmPseudoPseudoAlign4); 4536 4537 /* Insert the pseudo chaining instruction */ 4538 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]); 4539 4540 4541 switch (chainingBlock->blockType) { 4542 case kChainingCellNormal: 4543 handleNormalChainingCell(cUnit, chainingBlock->startOffset); 4544 break; 4545 case kChainingCellInvokeSingleton: 4546 handleInvokeSingletonChainingCell(cUnit, 4547 chainingBlock->containingMethod); 4548 break; 4549 case kChainingCellInvokePredicted: 4550 handleInvokePredictedChainingCell(cUnit); 4551 break; 4552 case kChainingCellHot: 4553 handleHotChainingCell(cUnit, chainingBlock->startOffset); 4554 break; 4555 case kChainingCellBackwardBranch: 4556 handleBackwardBranchChainingCell(cUnit, 4557 chainingBlock->startOffset); 4558 break; 4559 default: 4560 ALOGE("Bad blocktype %d", chainingBlock->blockType); 4561 dvmCompilerAbort(cUnit); 4562 } 4563 } 4564 } 4565 4566 /* Mark the bottom of chaining cells */ 4567 cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kArmChainingCellBottom); 4568 4569 /* 4570 * Generate the branch to the dvmJitToInterpNoChain entry point at the end 4571 * of all chaining cells for the overflow cases. 4572 */ 4573 if (cUnit->switchOverflowPad) { 4574 loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad); 4575 loadWordDisp(cUnit, r6SELF, offsetof(Thread, 4576 jitToInterpEntries.dvmJitToInterpNoChain), r2); 4577 opRegReg(cUnit, kOpAdd, r1, r1); 4578 opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1); 4579#if defined(WITH_JIT_TUNING) 4580 loadConstant(cUnit, r0, kSwitchOverflow); 4581#endif 4582 opReg(cUnit, kOpBlx, r2); 4583 } 4584 4585 dvmCompilerApplyGlobalOptimizations(cUnit); 4586 4587#if defined(WITH_SELF_VERIFICATION) 4588 selfVerificationBranchInsertPass(cUnit); 4589#endif 4590} 4591 4592/* 4593 * Accept the work and start compiling. Returns true if compilation 4594 * is attempted. 4595 */ 4596bool dvmCompilerDoWork(CompilerWorkOrder *work) 4597{ 4598 JitTraceDescription *desc; 4599 bool isCompile; 4600 bool success = true; 4601 4602 if (gDvmJit.codeCacheFull) { 4603 return false; 4604 } 4605 4606 switch (work->kind) { 4607 case kWorkOrderTrace: 4608 isCompile = true; 4609 /* Start compilation with maximally allowed trace length */ 4610 desc = (JitTraceDescription *)work->info; 4611 success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result, 4612 work->bailPtr, 0 /* no hints */); 4613 break; 4614 case kWorkOrderTraceDebug: { 4615 bool oldPrintMe = gDvmJit.printMe; 4616 gDvmJit.printMe = true; 4617 isCompile = true; 4618 /* Start compilation with maximally allowed trace length */ 4619 desc = (JitTraceDescription *)work->info; 4620 success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result, 4621 work->bailPtr, 0 /* no hints */); 4622 gDvmJit.printMe = oldPrintMe; 4623 break; 4624 } 4625 case kWorkOrderProfileMode: 4626 dvmJitChangeProfileMode((TraceProfilingModes)(int)work->info); 4627 isCompile = false; 4628 break; 4629 default: 4630 isCompile = false; 4631 ALOGE("Jit: unknown work order type"); 4632 assert(0); // Bail if debug build, discard otherwise 4633 } 4634 if (!success) 4635 work->result.codeAddress = NULL; 4636 return isCompile; 4637} 4638 4639/* Architectural-specific debugging helpers go here */ 4640void dvmCompilerArchDump(void) 4641{ 4642 /* Print compiled opcode in this VM instance */ 4643 int i, start, streak; 4644 char buf[1024]; 4645 4646 streak = i = 0; 4647 buf[0] = 0; 4648 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) { 4649 i++; 4650 } 4651 if (i == kNumPackedOpcodes) { 4652 return; 4653 } 4654 for (start = i++, streak = 1; i < kNumPackedOpcodes; i++) { 4655 if (opcodeCoverage[i]) { 4656 streak++; 4657 } else { 4658 if (streak == 1) { 4659 sprintf(buf+strlen(buf), "%x,", start); 4660 } else { 4661 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1); 4662 } 4663 streak = 0; 4664 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) { 4665 i++; 4666 } 4667 if (i < kNumPackedOpcodes) { 4668 streak = 1; 4669 start = i; 4670 } 4671 } 4672 } 4673 if (streak) { 4674 if (streak == 1) { 4675 sprintf(buf+strlen(buf), "%x", start); 4676 } else { 4677 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1); 4678 } 4679 } 4680 if (strlen(buf)) { 4681 ALOGD("dalvik.vm.jit.op = %s", buf); 4682 } 4683} 4684 4685/* Common initialization routine for an architecture family */ 4686bool dvmCompilerArchInit() 4687{ 4688 int i; 4689 4690 for (i = 0; i < kArmLast; i++) { 4691 if (EncodingMap[i].opcode != i) { 4692 ALOGE("Encoding order for %s is wrong: expecting %d, seeing %d", 4693 EncodingMap[i].name, i, EncodingMap[i].opcode); 4694 dvmAbort(); // OK to dvmAbort - build error 4695 } 4696 } 4697 4698 return dvmCompilerArchVariantInit(); 4699} 4700 4701void *dvmCompilerGetInterpretTemplate() 4702{ 4703 return (void*) ((int)gDvmJit.codeCache + 4704 templateEntryOffsets[TEMPLATE_INTERPRET]); 4705} 4706 4707JitInstructionSetType dvmCompilerGetInterpretTemplateSet() 4708{ 4709 return DALVIK_JIT_ARM; 4710} 4711 4712/* Needed by the Assembler */ 4713void dvmCompilerSetupResourceMasks(ArmLIR *lir) 4714{ 4715 setupResourceMasks(lir); 4716} 4717 4718/* Needed by the ld/st optmizatons */ 4719ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc) 4720{ 4721 return genRegCopyNoInsert(cUnit, rDest, rSrc); 4722} 4723 4724/* Needed by the register allocator */ 4725ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) 4726{ 4727 return genRegCopy(cUnit, rDest, rSrc); 4728} 4729 4730/* Needed by the register allocator */ 4731void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, 4732 int srcLo, int srcHi) 4733{ 4734 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi); 4735} 4736 4737void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase, 4738 int displacement, int rSrc, OpSize size) 4739{ 4740 storeBaseDisp(cUnit, rBase, displacement, rSrc, size); 4741} 4742 4743void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase, 4744 int displacement, int rSrcLo, int rSrcHi) 4745{ 4746 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi); 4747} 4748