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