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