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