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