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