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