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