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, r0, offsetof(Object, clazz), r3); 1223 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, 1224 jitToInterpEntries.dvmJitToInterpPunt), r1); 1225 opReg(cUnit, kOpBlx, r1); 1226 } 1227 1228 /* 1229 * Attempt to single step one instruction using the interpreter and return 1230 * to the compiled code for the next Dalvik instruction 1231 */ 1232 static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir) 1233 { 1234 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode); 1235 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn | 1236 kInstrCanThrow; 1237 1238 //If already optimized out, just ignore 1239 if (mir->dalvikInsn.opCode == OP_NOP) 1240 return; 1241 1242 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them 1243 dvmCompilerFlushAllRegs(cUnit); 1244 1245 if ((mir->next == NULL) || (flags & flagsToCheck)) { 1246 genPuntToInterp(cUnit, mir->offset); 1247 return; 1248 } 1249 int entryAddr = offsetof(InterpState, 1250 jitToInterpEntries.dvmJitToInterpSingleStep); 1251 loadWordDisp(cUnit, rGLUE, entryAddr, r2); 1252 /* r0 = dalvik pc */ 1253 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset)); 1254 /* r1 = dalvik pc of following instruction */ 1255 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset)); 1256 opReg(cUnit, kOpBlx, r2); 1257 } 1258 1259 #if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING) || \ 1260 defined(_ARMV5TE) || defined(_ARMV5TE_VFP) 1261 /* 1262 * To prevent a thread in a monitor wait from blocking the Jit from 1263 * resetting the code cache, heavyweight monitor lock will not 1264 * be allowed to return to an existing translation. Instead, we will 1265 * handle them by branching to a handler, which will in turn call the 1266 * runtime lock routine and then branch directly back to the 1267 * interpreter main loop. Given the high cost of the heavyweight 1268 * lock operation, this additional cost should be slight (especially when 1269 * considering that we expect the vast majority of lock operations to 1270 * use the fast-path thin lock bypass). 1271 */ 1272 static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir) 1273 { 1274 bool isEnter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER); 1275 genExportPC(cUnit, mir); 1276 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */ 1277 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1278 loadValueDirectFixed(cUnit, rlSrc, r1); 1279 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0); 1280 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL); 1281 if (isEnter) { 1282 /* Get dPC of next insn */ 1283 loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset + 1284 dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_ENTER))); 1285 #if defined(WITH_DEADLOCK_PREDICTION) 1286 genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER_DEBUG); 1287 #else 1288 genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER); 1289 #endif 1290 } else { 1291 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmUnlockObject); 1292 /* Do the call */ 1293 opReg(cUnit, kOpBlx, r2); 1294 opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */ 1295 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe); 1296 loadConstant(cUnit, r0, 1297 (int) (cUnit->method->insns + mir->offset + 1298 dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_EXIT))); 1299 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 1300 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 1301 target->defMask = ENCODE_ALL; 1302 branchOver->generic.target = (LIR *) target; 1303 dvmCompilerClobberCallRegs(cUnit); 1304 } 1305 } 1306 #endif 1307 1308 /* 1309 * The following are the first-level codegen routines that analyze the format 1310 * of each bytecode then either dispatch special purpose codegen routines 1311 * or produce corresponding Thumb instructions directly. 1312 */ 1313 1314 static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir, 1315 BasicBlock *bb, ArmLIR *labelList) 1316 { 1317 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */ 1318 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]); 1319 return false; 1320 } 1321 1322 static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir) 1323 { 1324 OpCode dalvikOpCode = mir->dalvikInsn.opCode; 1325 if ((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) { 1326 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode); 1327 return true; 1328 } 1329 switch (dalvikOpCode) { 1330 case OP_RETURN_VOID: 1331 genReturnCommon(cUnit,mir); 1332 break; 1333 case OP_UNUSED_73: 1334 case OP_UNUSED_79: 1335 case OP_UNUSED_7A: 1336 case OP_UNUSED_F1: 1337 case OP_UNUSED_FF: 1338 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode); 1339 return true; 1340 case OP_NOP: 1341 break; 1342 default: 1343 return true; 1344 } 1345 return false; 1346 } 1347 1348 static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir) 1349 { 1350 RegLocation rlDest; 1351 RegLocation rlResult; 1352 if (mir->ssaRep->numDefs == 2) { 1353 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1354 } else { 1355 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1356 } 1357 1358 switch (mir->dalvikInsn.opCode) { 1359 case OP_CONST: 1360 case OP_CONST_4: { 1361 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1362 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB); 1363 storeValue(cUnit, rlDest, rlResult); 1364 break; 1365 } 1366 case OP_CONST_WIDE_32: { 1367 //TUNING: single routine to load constant pair for support doubles 1368 //TUNING: load 0/-1 separately to avoid load dependency 1369 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1370 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB); 1371 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, 1372 rlResult.lowReg, 31); 1373 storeValueWide(cUnit, rlDest, rlResult); 1374 break; 1375 } 1376 default: 1377 return true; 1378 } 1379 return false; 1380 } 1381 1382 static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir) 1383 { 1384 RegLocation rlDest; 1385 RegLocation rlResult; 1386 if (mir->ssaRep->numDefs == 2) { 1387 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1388 } else { 1389 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1390 } 1391 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1392 1393 switch (mir->dalvikInsn.opCode) { 1394 case OP_CONST_HIGH16: { 1395 loadConstantNoClobber(cUnit, rlResult.lowReg, 1396 mir->dalvikInsn.vB << 16); 1397 storeValue(cUnit, rlDest, rlResult); 1398 break; 1399 } 1400 case OP_CONST_WIDE_HIGH16: { 1401 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg, 1402 0, mir->dalvikInsn.vB << 16); 1403 storeValueWide(cUnit, rlDest, rlResult); 1404 break; 1405 } 1406 default: 1407 return true; 1408 } 1409 return false; 1410 } 1411 1412 static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir) 1413 { 1414 /* For OP_THROW_VERIFICATION_ERROR */ 1415 genInterpSingleStep(cUnit, mir); 1416 return false; 1417 } 1418 1419 static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir) 1420 { 1421 RegLocation rlResult; 1422 RegLocation rlDest; 1423 RegLocation rlSrc; 1424 1425 switch (mir->dalvikInsn.opCode) { 1426 case OP_CONST_STRING_JUMBO: 1427 case OP_CONST_STRING: { 1428 void *strPtr = (void*) 1429 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]); 1430 1431 if (strPtr == NULL) { 1432 LOGE("Unexpected null string"); 1433 dvmAbort(); 1434 } 1435 1436 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1437 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1438 loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr ); 1439 storeValue(cUnit, rlDest, rlResult); 1440 break; 1441 } 1442 case OP_CONST_CLASS: { 1443 void *classPtr = (void*) 1444 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]); 1445 1446 if (classPtr == NULL) { 1447 LOGE("Unexpected null class"); 1448 dvmAbort(); 1449 } 1450 1451 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1452 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1453 loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr ); 1454 storeValue(cUnit, rlDest, rlResult); 1455 break; 1456 } 1457 case OP_SGET_VOLATILE: 1458 case OP_SGET_OBJECT_VOLATILE: 1459 case OP_SGET_OBJECT: 1460 case OP_SGET_BOOLEAN: 1461 case OP_SGET_CHAR: 1462 case OP_SGET_BYTE: 1463 case OP_SGET_SHORT: 1464 case OP_SGET: { 1465 int valOffset = offsetof(StaticField, value); 1466 int tReg = dvmCompilerAllocTemp(cUnit); 1467 bool isVolatile; 1468 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1469 mir->meta.calleeMethod : cUnit->method; 1470 void *fieldPtr = (void*) 1471 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1472 1473 if (fieldPtr == NULL) { 1474 LOGE("Unexpected null static field"); 1475 dvmAbort(); 1476 } 1477 1478 isVolatile = (mir->dalvikInsn.opCode == OP_SGET_VOLATILE) || 1479 (mir->dalvikInsn.opCode == OP_SGET_OBJECT_VOLATILE) || 1480 dvmIsVolatileField(fieldPtr); 1481 1482 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1483 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1484 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset); 1485 1486 if (isVolatile) { 1487 dvmCompilerGenMemBarrier(cUnit); 1488 } 1489 HEAP_ACCESS_SHADOW(true); 1490 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg); 1491 HEAP_ACCESS_SHADOW(false); 1492 1493 storeValue(cUnit, rlDest, rlResult); 1494 break; 1495 } 1496 case OP_SGET_WIDE: { 1497 int valOffset = offsetof(StaticField, value); 1498 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1499 mir->meta.calleeMethod : cUnit->method; 1500 void *fieldPtr = (void*) 1501 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1502 1503 if (fieldPtr == NULL) { 1504 LOGE("Unexpected null static field"); 1505 dvmAbort(); 1506 } 1507 1508 int tReg = dvmCompilerAllocTemp(cUnit); 1509 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1510 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1511 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset); 1512 1513 HEAP_ACCESS_SHADOW(true); 1514 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg); 1515 HEAP_ACCESS_SHADOW(false); 1516 1517 storeValueWide(cUnit, rlDest, rlResult); 1518 break; 1519 } 1520 case OP_SPUT_OBJECT: 1521 case OP_SPUT_OBJECT_VOLATILE: 1522 case OP_SPUT_VOLATILE: 1523 case OP_SPUT_BOOLEAN: 1524 case OP_SPUT_CHAR: 1525 case OP_SPUT_BYTE: 1526 case OP_SPUT_SHORT: 1527 case OP_SPUT: { 1528 int valOffset = offsetof(StaticField, value); 1529 int tReg = dvmCompilerAllocTemp(cUnit); 1530 int objHead; 1531 bool isVolatile; 1532 bool isSputObject; 1533 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1534 mir->meta.calleeMethod : cUnit->method; 1535 void *fieldPtr = (void*) 1536 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1537 1538 isVolatile = (mir->dalvikInsn.opCode == OP_SPUT_VOLATILE) || 1539 (mir->dalvikInsn.opCode == OP_SPUT_OBJECT_VOLATILE) || 1540 dvmIsVolatileField(fieldPtr); 1541 1542 isSputObject = (mir->dalvikInsn.opCode == OP_SPUT_OBJECT) || 1543 (mir->dalvikInsn.opCode == OP_SPUT_OBJECT_VOLATILE); 1544 1545 if (fieldPtr == NULL) { 1546 LOGE("Unexpected null static field"); 1547 dvmAbort(); 1548 } 1549 1550 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1551 rlSrc = loadValue(cUnit, rlSrc, kAnyReg); 1552 loadConstant(cUnit, tReg, (int) fieldPtr); 1553 if (isSputObject) { 1554 objHead = dvmCompilerAllocTemp(cUnit); 1555 loadWordDisp(cUnit, tReg, offsetof(Field, clazz), objHead); 1556 } 1557 HEAP_ACCESS_SHADOW(true); 1558 storeWordDisp(cUnit, tReg, valOffset ,rlSrc.lowReg); 1559 dvmCompilerFreeTemp(cUnit, tReg); 1560 HEAP_ACCESS_SHADOW(false); 1561 if (isVolatile) { 1562 dvmCompilerGenMemBarrier(cUnit); 1563 } 1564 if (isSputObject) { 1565 /* NOTE: marking card based sfield->clazz */ 1566 markCard(cUnit, rlSrc.lowReg, objHead); 1567 dvmCompilerFreeTemp(cUnit, objHead); 1568 } 1569 1570 break; 1571 } 1572 case OP_SPUT_WIDE: { 1573 int tReg = dvmCompilerAllocTemp(cUnit); 1574 int valOffset = offsetof(StaticField, value); 1575 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 1576 mir->meta.calleeMethod : cUnit->method; 1577 void *fieldPtr = (void*) 1578 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]); 1579 1580 if (fieldPtr == NULL) { 1581 LOGE("Unexpected null static field"); 1582 dvmAbort(); 1583 } 1584 1585 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 1586 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg); 1587 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset); 1588 1589 HEAP_ACCESS_SHADOW(true); 1590 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg); 1591 HEAP_ACCESS_SHADOW(false); 1592 break; 1593 } 1594 case OP_NEW_INSTANCE: { 1595 /* 1596 * Obey the calling convention and don't mess with the register 1597 * usage. 1598 */ 1599 ClassObject *classPtr = (void*) 1600 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]); 1601 1602 if (classPtr == NULL) { 1603 LOGE("Unexpected null class"); 1604 dvmAbort(); 1605 } 1606 1607 /* 1608 * If it is going to throw, it should not make to the trace to begin 1609 * with. However, Alloc might throw, so we need to genExportPC() 1610 */ 1611 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0); 1612 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 1613 genExportPC(cUnit, mir); 1614 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmAllocObject); 1615 loadConstant(cUnit, r0, (int) classPtr); 1616 loadConstant(cUnit, r1, ALLOC_DONT_TRACK); 1617 opReg(cUnit, kOpBlx, r2); 1618 dvmCompilerClobberCallRegs(cUnit); 1619 /* generate a branch over if allocation is successful */ 1620 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */ 1621 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe); 1622 /* 1623 * OOM exception needs to be thrown here and cannot re-execute 1624 */ 1625 loadConstant(cUnit, r0, 1626 (int) (cUnit->method->insns + mir->offset)); 1627 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 1628 /* noreturn */ 1629 1630 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 1631 target->defMask = ENCODE_ALL; 1632 branchOver->generic.target = (LIR *) target; 1633 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1634 rlResult = dvmCompilerGetReturn(cUnit); 1635 storeValue(cUnit, rlDest, rlResult); 1636 break; 1637 } 1638 case OP_CHECK_CAST: { 1639 /* 1640 * Obey the calling convention and don't mess with the register 1641 * usage. 1642 */ 1643 ClassObject *classPtr = 1644 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]); 1645 /* 1646 * Note: It is possible that classPtr is NULL at this point, 1647 * even though this instruction has been successfully interpreted. 1648 * If the previous interpretation had a null source, the 1649 * interpreter would not have bothered to resolve the clazz. 1650 * Bail out to the interpreter in this case, and log it 1651 * so that we can tell if it happens frequently. 1652 */ 1653 if (classPtr == NULL) { 1654 LOGVV("null clazz in OP_CHECK_CAST, single-stepping"); 1655 genInterpSingleStep(cUnit, mir); 1656 return false; 1657 } 1658 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 1659 loadConstant(cUnit, r1, (int) classPtr ); 1660 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1661 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 1662 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); /* Null? */ 1663 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq); 1664 /* 1665 * rlSrc.lowReg now contains object->clazz. Note that 1666 * it could have been allocated r0, but we're okay so long 1667 * as we don't do anything desctructive until r0 is loaded 1668 * with clazz. 1669 */ 1670 /* r0 now contains object->clazz */ 1671 loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0); 1672 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInstanceofNonTrivial); 1673 opRegReg(cUnit, kOpCmp, r0, r1); 1674 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq); 1675 opReg(cUnit, kOpBlx, r2); 1676 dvmCompilerClobberCallRegs(cUnit); 1677 /* 1678 * If null, check cast failed - punt to the interpreter. Because 1679 * interpreter will be the one throwing, we don't need to 1680 * genExportPC() here. 1681 */ 1682 genZeroCheck(cUnit, r0, mir->offset, NULL); 1683 /* check cast passed - branch target here */ 1684 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 1685 target->defMask = ENCODE_ALL; 1686 branch1->generic.target = (LIR *)target; 1687 branch2->generic.target = (LIR *)target; 1688 break; 1689 } 1690 case OP_SGET_WIDE_VOLATILE: 1691 case OP_SPUT_WIDE_VOLATILE: 1692 genInterpSingleStep(cUnit, mir); 1693 break; 1694 default: 1695 return true; 1696 } 1697 return false; 1698 } 1699 1700 /* 1701 * A typical example of inlined getter/setter from a monomorphic callsite: 1702 * 1703 * D/dalvikvm( 289): -------- dalvik offset: 0x0000 @ invoke-static (I) 1704 * D/dalvikvm( 289): -------- dalvik offset: 0x0000 @ sget-object (C) v0, ... 1705 * D/dalvikvm( 289): 0x4427fc22 (0002): ldr r0, [pc, #56] 1706 * D/dalvikvm( 289): 0x4427fc24 (0004): ldr r1, [r0, #0] 1707 * D/dalvikvm( 289): 0x4427fc26 (0006): str r1, [r5, #0] 1708 * D/dalvikvm( 289): 0x4427fc28 (0008): .align4 1709 * D/dalvikvm( 289): L0x0003: 1710 * D/dalvikvm( 289): -------- dalvik offset: 0x0003 @ move-result-object (I) v0 1711 * 1712 * Note the invoke-static and move-result-object with the (I) notation are 1713 * turned into no-op. 1714 */ 1715 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir) 1716 { 1717 OpCode dalvikOpCode = mir->dalvikInsn.opCode; 1718 RegLocation rlResult; 1719 switch (dalvikOpCode) { 1720 case OP_MOVE_EXCEPTION: { 1721 int offset = offsetof(InterpState, self); 1722 int exOffset = offsetof(Thread, exception); 1723 int selfReg = dvmCompilerAllocTemp(cUnit); 1724 int resetReg = dvmCompilerAllocTemp(cUnit); 1725 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1726 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1727 loadWordDisp(cUnit, rGLUE, offset, selfReg); 1728 loadConstant(cUnit, resetReg, 0); 1729 loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg); 1730 storeWordDisp(cUnit, selfReg, exOffset, resetReg); 1731 storeValue(cUnit, rlDest, rlResult); 1732 break; 1733 } 1734 case OP_MOVE_RESULT: 1735 case OP_MOVE_RESULT_OBJECT: { 1736 /* An inlined move result is effectively no-op */ 1737 if (mir->OptimizationFlags & MIR_INLINED) 1738 break; 1739 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1740 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL; 1741 rlSrc.fp = rlDest.fp; 1742 storeValue(cUnit, rlDest, rlSrc); 1743 break; 1744 } 1745 case OP_MOVE_RESULT_WIDE: { 1746 /* An inlined move result is effectively no-op */ 1747 if (mir->OptimizationFlags & MIR_INLINED) 1748 break; 1749 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1750 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE; 1751 rlSrc.fp = rlDest.fp; 1752 storeValueWide(cUnit, rlDest, rlSrc); 1753 break; 1754 } 1755 case OP_RETURN_WIDE: { 1756 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 1757 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE; 1758 rlDest.fp = rlSrc.fp; 1759 storeValueWide(cUnit, rlDest, rlSrc); 1760 genReturnCommon(cUnit,mir); 1761 break; 1762 } 1763 case OP_RETURN: 1764 case OP_RETURN_OBJECT: { 1765 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1766 RegLocation rlDest = LOC_DALVIK_RETURN_VAL; 1767 rlDest.fp = rlSrc.fp; 1768 storeValue(cUnit, rlDest, rlSrc); 1769 genReturnCommon(cUnit,mir); 1770 break; 1771 } 1772 case OP_MONITOR_EXIT: 1773 case OP_MONITOR_ENTER: 1774 #if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING) 1775 genMonitorPortable(cUnit, mir); 1776 #else 1777 genMonitor(cUnit, mir); 1778 #endif 1779 break; 1780 case OP_THROW: { 1781 genInterpSingleStep(cUnit, mir); 1782 break; 1783 } 1784 default: 1785 return true; 1786 } 1787 return false; 1788 } 1789 1790 static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir) 1791 { 1792 OpCode opCode = mir->dalvikInsn.opCode; 1793 RegLocation rlDest; 1794 RegLocation rlSrc; 1795 RegLocation rlResult; 1796 1797 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) { 1798 return genArithOp( cUnit, mir ); 1799 } 1800 1801 if (mir->ssaRep->numUses == 2) 1802 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 1803 else 1804 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1805 if (mir->ssaRep->numDefs == 2) 1806 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1807 else 1808 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1809 1810 switch (opCode) { 1811 case OP_DOUBLE_TO_INT: 1812 case OP_INT_TO_FLOAT: 1813 case OP_FLOAT_TO_INT: 1814 case OP_DOUBLE_TO_FLOAT: 1815 case OP_FLOAT_TO_DOUBLE: 1816 case OP_INT_TO_DOUBLE: 1817 case OP_FLOAT_TO_LONG: 1818 case OP_LONG_TO_FLOAT: 1819 case OP_DOUBLE_TO_LONG: 1820 case OP_LONG_TO_DOUBLE: 1821 return genConversion(cUnit, mir); 1822 case OP_NEG_INT: 1823 case OP_NOT_INT: 1824 return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc); 1825 case OP_NEG_LONG: 1826 case OP_NOT_LONG: 1827 return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc); 1828 case OP_NEG_FLOAT: 1829 return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc); 1830 case OP_NEG_DOUBLE: 1831 return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc); 1832 case OP_MOVE_WIDE: 1833 storeValueWide(cUnit, rlDest, rlSrc); 1834 break; 1835 case OP_INT_TO_LONG: 1836 rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc); 1837 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1838 //TUNING: shouldn't loadValueDirect already check for phys reg? 1839 if (rlSrc.location == kLocPhysReg) { 1840 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); 1841 } else { 1842 loadValueDirect(cUnit, rlSrc, rlResult.lowReg); 1843 } 1844 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, 1845 rlResult.lowReg, 31); 1846 storeValueWide(cUnit, rlDest, rlResult); 1847 break; 1848 case OP_LONG_TO_INT: 1849 rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc); 1850 rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc); 1851 // Intentional fallthrough 1852 case OP_MOVE: 1853 case OP_MOVE_OBJECT: 1854 storeValue(cUnit, rlDest, rlSrc); 1855 break; 1856 case OP_INT_TO_BYTE: 1857 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 1858 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1859 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg); 1860 storeValue(cUnit, rlDest, rlResult); 1861 break; 1862 case OP_INT_TO_SHORT: 1863 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 1864 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1865 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg); 1866 storeValue(cUnit, rlDest, rlResult); 1867 break; 1868 case OP_INT_TO_CHAR: 1869 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 1870 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1871 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg); 1872 storeValue(cUnit, rlDest, rlResult); 1873 break; 1874 case OP_ARRAY_LENGTH: { 1875 int lenOffset = offsetof(ArrayObject, length); 1876 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 1877 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg, 1878 mir->offset, NULL); 1879 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1880 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset, 1881 rlResult.lowReg); 1882 storeValue(cUnit, rlDest, rlResult); 1883 break; 1884 } 1885 default: 1886 return true; 1887 } 1888 return false; 1889 } 1890 1891 static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir) 1892 { 1893 OpCode dalvikOpCode = mir->dalvikInsn.opCode; 1894 RegLocation rlDest; 1895 RegLocation rlResult; 1896 int BBBB = mir->dalvikInsn.vB; 1897 if (dalvikOpCode == OP_CONST_WIDE_16) { 1898 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 1899 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1900 loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB); 1901 //TUNING: do high separately to avoid load dependency 1902 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31); 1903 storeValueWide(cUnit, rlDest, rlResult); 1904 } else if (dalvikOpCode == OP_CONST_16) { 1905 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 1906 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true); 1907 loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB); 1908 storeValue(cUnit, rlDest, rlResult); 1909 } else 1910 return true; 1911 return false; 1912 } 1913 1914 /* Compare agaist zero */ 1915 static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 1916 ArmLIR *labelList) 1917 { 1918 OpCode dalvikOpCode = mir->dalvikInsn.opCode; 1919 ArmConditionCode cond; 1920 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 1921 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 1922 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); 1923 1924 //TUNING: break this out to allow use of Thumb2 CB[N]Z 1925 switch (dalvikOpCode) { 1926 case OP_IF_EQZ: 1927 cond = kArmCondEq; 1928 break; 1929 case OP_IF_NEZ: 1930 cond = kArmCondNe; 1931 break; 1932 case OP_IF_LTZ: 1933 cond = kArmCondLt; 1934 break; 1935 case OP_IF_GEZ: 1936 cond = kArmCondGe; 1937 break; 1938 case OP_IF_GTZ: 1939 cond = kArmCondGt; 1940 break; 1941 case OP_IF_LEZ: 1942 cond = kArmCondLe; 1943 break; 1944 default: 1945 cond = 0; 1946 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode); 1947 dvmCompilerAbort(cUnit); 1948 } 1949 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]); 1950 /* This mostly likely will be optimized away in a later phase */ 1951 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); 1952 return false; 1953 } 1954 1955 static bool isPowerOfTwo(int x) 1956 { 1957 return (x & (x - 1)) == 0; 1958 } 1959 1960 // Returns true if no more than two bits are set in 'x'. 1961 static bool isPopCountLE2(unsigned int x) 1962 { 1963 x &= x - 1; 1964 return (x & (x - 1)) == 0; 1965 } 1966 1967 // Returns the index of the lowest set bit in 'x'. 1968 static int lowestSetBit(unsigned int x) { 1969 int bit_posn = 0; 1970 while ((x & 0xf) == 0) { 1971 bit_posn += 4; 1972 x >>= 4; 1973 } 1974 while ((x & 1) == 0) { 1975 bit_posn++; 1976 x >>= 1; 1977 } 1978 return bit_posn; 1979 } 1980 1981 // Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit' 1982 // and store the result in 'rlDest'. 1983 static bool handleEasyDivide(CompilationUnit *cUnit, OpCode dalvikOpCode, 1984 RegLocation rlSrc, RegLocation rlDest, int lit) 1985 { 1986 if (lit < 2 || !isPowerOfTwo(lit)) { 1987 return false; 1988 } 1989 int k = lowestSetBit(lit); 1990 if (k >= 30) { 1991 // Avoid special cases. 1992 return false; 1993 } 1994 bool div = (dalvikOpCode == OP_DIV_INT_LIT8 || dalvikOpCode == OP_DIV_INT_LIT16); 1995 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 1996 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 1997 if (div) { 1998 int tReg = dvmCompilerAllocTemp(cUnit); 1999 if (lit == 2) { 2000 // Division by 2 is by far the most common division by constant. 2001 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k); 2002 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg); 2003 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k); 2004 } else { 2005 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31); 2006 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k); 2007 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg); 2008 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k); 2009 } 2010 } else { 2011 int cReg = dvmCompilerAllocTemp(cUnit); 2012 loadConstant(cUnit, cReg, lit - 1); 2013 int tReg1 = dvmCompilerAllocTemp(cUnit); 2014 int tReg2 = dvmCompilerAllocTemp(cUnit); 2015 if (lit == 2) { 2016 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k); 2017 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg); 2018 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg); 2019 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1); 2020 } else { 2021 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31); 2022 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k); 2023 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg); 2024 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg); 2025 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1); 2026 } 2027 } 2028 storeValue(cUnit, rlDest, rlResult); 2029 return true; 2030 } 2031 2032 // Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit' 2033 // and store the result in 'rlDest'. 2034 static bool handleEasyMultiply(CompilationUnit *cUnit, 2035 RegLocation rlSrc, RegLocation rlDest, int lit) 2036 { 2037 // Can we simplify this multiplication? 2038 bool powerOfTwo = false; 2039 bool popCountLE2 = false; 2040 bool powerOfTwoMinusOne = false; 2041 if (lit < 2) { 2042 // Avoid special cases. 2043 return false; 2044 } else if (isPowerOfTwo(lit)) { 2045 powerOfTwo = true; 2046 } else if (isPopCountLE2(lit)) { 2047 popCountLE2 = true; 2048 } else if (isPowerOfTwo(lit + 1)) { 2049 powerOfTwoMinusOne = true; 2050 } else { 2051 return false; 2052 } 2053 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2054 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2055 if (powerOfTwo) { 2056 // Shift. 2057 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg, 2058 lowestSetBit(lit)); 2059 } else if (popCountLE2) { 2060 // Shift and add and shift. 2061 int firstBit = lowestSetBit(lit); 2062 int secondBit = lowestSetBit(lit ^ (1 << firstBit)); 2063 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit, 2064 firstBit, secondBit); 2065 } else { 2066 // Reverse subtract: (src << (shift + 1)) - src. 2067 assert(powerOfTwoMinusOne); 2068 // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1) 2069 int tReg = dvmCompilerAllocTemp(cUnit); 2070 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1)); 2071 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg); 2072 } 2073 storeValue(cUnit, rlDest, rlResult); 2074 return true; 2075 } 2076 2077 static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir) 2078 { 2079 OpCode dalvikOpCode = mir->dalvikInsn.opCode; 2080 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2081 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2082 RegLocation rlResult; 2083 int lit = mir->dalvikInsn.vC; 2084 OpKind op = 0; /* Make gcc happy */ 2085 int shiftOp = false; 2086 bool isDiv = false; 2087 2088 switch (dalvikOpCode) { 2089 case OP_RSUB_INT_LIT8: 2090 case OP_RSUB_INT: { 2091 int tReg; 2092 //TUNING: add support for use of Arm rsub op 2093 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2094 tReg = dvmCompilerAllocTemp(cUnit); 2095 loadConstant(cUnit, tReg, lit); 2096 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2097 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, 2098 tReg, rlSrc.lowReg); 2099 storeValue(cUnit, rlDest, rlResult); 2100 return false; 2101 break; 2102 } 2103 2104 case OP_ADD_INT_LIT8: 2105 case OP_ADD_INT_LIT16: 2106 op = kOpAdd; 2107 break; 2108 case OP_MUL_INT_LIT8: 2109 case OP_MUL_INT_LIT16: { 2110 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) { 2111 return false; 2112 } 2113 op = kOpMul; 2114 break; 2115 } 2116 case OP_AND_INT_LIT8: 2117 case OP_AND_INT_LIT16: 2118 op = kOpAnd; 2119 break; 2120 case OP_OR_INT_LIT8: 2121 case OP_OR_INT_LIT16: 2122 op = kOpOr; 2123 break; 2124 case OP_XOR_INT_LIT8: 2125 case OP_XOR_INT_LIT16: 2126 op = kOpXor; 2127 break; 2128 case OP_SHL_INT_LIT8: 2129 lit &= 31; 2130 shiftOp = true; 2131 op = kOpLsl; 2132 break; 2133 case OP_SHR_INT_LIT8: 2134 lit &= 31; 2135 shiftOp = true; 2136 op = kOpAsr; 2137 break; 2138 case OP_USHR_INT_LIT8: 2139 lit &= 31; 2140 shiftOp = true; 2141 op = kOpLsr; 2142 break; 2143 2144 case OP_DIV_INT_LIT8: 2145 case OP_DIV_INT_LIT16: 2146 case OP_REM_INT_LIT8: 2147 case OP_REM_INT_LIT16: 2148 if (lit == 0) { 2149 /* Let the interpreter deal with div by 0 */ 2150 genInterpSingleStep(cUnit, mir); 2151 return false; 2152 } 2153 if (handleEasyDivide(cUnit, dalvikOpCode, rlSrc, rlDest, lit)) { 2154 return false; 2155 } 2156 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2157 loadValueDirectFixed(cUnit, rlSrc, r0); 2158 dvmCompilerClobber(cUnit, r0); 2159 if ((dalvikOpCode == OP_DIV_INT_LIT8) || 2160 (dalvikOpCode == OP_DIV_INT_LIT16)) { 2161 LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idiv); 2162 isDiv = true; 2163 } else { 2164 LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idivmod); 2165 isDiv = false; 2166 } 2167 loadConstant(cUnit, r1, lit); 2168 opReg(cUnit, kOpBlx, r2); 2169 dvmCompilerClobberCallRegs(cUnit); 2170 if (isDiv) 2171 rlResult = dvmCompilerGetReturn(cUnit); 2172 else 2173 rlResult = dvmCompilerGetReturnAlt(cUnit); 2174 storeValue(cUnit, rlDest, rlResult); 2175 return false; 2176 break; 2177 default: 2178 return true; 2179 } 2180 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 2181 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 2182 // Avoid shifts by literal 0 - no support in Thumb. Change to copy 2183 if (shiftOp && (lit == 0)) { 2184 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg); 2185 } else { 2186 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit); 2187 } 2188 storeValue(cUnit, rlDest, rlResult); 2189 return false; 2190 } 2191 2192 static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir) 2193 { 2194 OpCode dalvikOpCode = mir->dalvikInsn.opCode; 2195 int fieldOffset = -1; 2196 bool isVolatile = false; 2197 switch (dalvikOpCode) { 2198 /* 2199 * Wide volatiles currently handled via single step. 2200 * Add them here if generating in-line code. 2201 * case OP_IGET_WIDE_VOLATILE: 2202 * case OP_IPUT_WIDE_VOLATILE: 2203 */ 2204 case OP_IGET: 2205 case OP_IGET_VOLATILE: 2206 case OP_IGET_WIDE: 2207 case OP_IGET_OBJECT: 2208 case OP_IGET_OBJECT_VOLATILE: 2209 case OP_IGET_BOOLEAN: 2210 case OP_IGET_BYTE: 2211 case OP_IGET_CHAR: 2212 case OP_IGET_SHORT: 2213 case OP_IPUT: 2214 case OP_IPUT_VOLATILE: 2215 case OP_IPUT_WIDE: 2216 case OP_IPUT_OBJECT: 2217 case OP_IPUT_OBJECT_VOLATILE: 2218 case OP_IPUT_BOOLEAN: 2219 case OP_IPUT_BYTE: 2220 case OP_IPUT_CHAR: 2221 case OP_IPUT_SHORT: { 2222 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ? 2223 mir->meta.calleeMethod : cUnit->method; 2224 Field *fieldPtr = 2225 method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC]; 2226 2227 if (fieldPtr == NULL) { 2228 LOGE("Unexpected null instance field"); 2229 dvmAbort(); 2230 } 2231 isVolatile = dvmIsVolatileField(fieldPtr); 2232 fieldOffset = ((InstField *)fieldPtr)->byteOffset; 2233 break; 2234 } 2235 default: 2236 break; 2237 } 2238 2239 switch (dalvikOpCode) { 2240 case OP_NEW_ARRAY: { 2241 // Generates a call - use explicit registers 2242 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2243 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2244 RegLocation rlResult; 2245 void *classPtr = (void*) 2246 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]); 2247 2248 if (classPtr == NULL) { 2249 LOGE("Unexpected null class"); 2250 dvmAbort(); 2251 } 2252 2253 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2254 genExportPC(cUnit, mir); 2255 loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */ 2256 loadConstant(cUnit, r0, (int) classPtr ); 2257 LOAD_FUNC_ADDR(cUnit, r3, (int)dvmAllocArrayByClass); 2258 /* 2259 * "len < 0": bail to the interpreter to re-execute the 2260 * instruction 2261 */ 2262 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL); 2263 loadConstant(cUnit, r2, ALLOC_DONT_TRACK); 2264 opReg(cUnit, kOpBlx, r3); 2265 dvmCompilerClobberCallRegs(cUnit); 2266 /* generate a branch over if allocation is successful */ 2267 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */ 2268 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe); 2269 /* 2270 * OOM exception needs to be thrown here and cannot re-execute 2271 */ 2272 loadConstant(cUnit, r0, 2273 (int) (cUnit->method->insns + mir->offset)); 2274 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 2275 /* noreturn */ 2276 2277 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2278 target->defMask = ENCODE_ALL; 2279 branchOver->generic.target = (LIR *) target; 2280 rlResult = dvmCompilerGetReturn(cUnit); 2281 storeValue(cUnit, rlDest, rlResult); 2282 break; 2283 } 2284 case OP_INSTANCE_OF: { 2285 // May generate a call - use explicit registers 2286 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2287 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2288 RegLocation rlResult; 2289 ClassObject *classPtr = 2290 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]); 2291 /* 2292 * Note: It is possible that classPtr is NULL at this point, 2293 * even though this instruction has been successfully interpreted. 2294 * If the previous interpretation had a null source, the 2295 * interpreter would not have bothered to resolve the clazz. 2296 * Bail out to the interpreter in this case, and log it 2297 * so that we can tell if it happens frequently. 2298 */ 2299 if (classPtr == NULL) { 2300 LOGD("null clazz in OP_INSTANCE_OF, single-stepping"); 2301 genInterpSingleStep(cUnit, mir); 2302 break; 2303 } 2304 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2305 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */ 2306 loadConstant(cUnit, r2, (int) classPtr ); 2307 //TUNING: compare to 0 primative to allow use of CB[N]Z 2308 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */ 2309 /* When taken r0 has NULL which can be used for store directly */ 2310 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq); 2311 /* r1 now contains object->clazz */ 2312 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1); 2313 /* r1 now contains object->clazz */ 2314 LOAD_FUNC_ADDR(cUnit, r3, (int)dvmInstanceofNonTrivial); 2315 loadConstant(cUnit, r0, 1); /* Assume true */ 2316 opRegReg(cUnit, kOpCmp, r1, r2); 2317 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq); 2318 genRegCopy(cUnit, r0, r1); 2319 genRegCopy(cUnit, r1, r2); 2320 opReg(cUnit, kOpBlx, r3); 2321 dvmCompilerClobberCallRegs(cUnit); 2322 /* branch target here */ 2323 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2324 target->defMask = ENCODE_ALL; 2325 rlResult = dvmCompilerGetReturn(cUnit); 2326 storeValue(cUnit, rlDest, rlResult); 2327 branch1->generic.target = (LIR *)target; 2328 branch2->generic.target = (LIR *)target; 2329 break; 2330 } 2331 case OP_IGET_WIDE: 2332 genIGetWide(cUnit, mir, fieldOffset); 2333 break; 2334 case OP_IGET_VOLATILE: 2335 case OP_IGET_OBJECT_VOLATILE: 2336 isVolatile = true; 2337 // NOTE: intentional fallthrough 2338 case OP_IGET: 2339 case OP_IGET_OBJECT: 2340 case OP_IGET_BOOLEAN: 2341 case OP_IGET_BYTE: 2342 case OP_IGET_CHAR: 2343 case OP_IGET_SHORT: 2344 genIGet(cUnit, mir, kWord, fieldOffset, isVolatile); 2345 break; 2346 case OP_IPUT_WIDE: 2347 genIPutWide(cUnit, mir, fieldOffset); 2348 break; 2349 case OP_IPUT: 2350 case OP_IPUT_SHORT: 2351 case OP_IPUT_CHAR: 2352 case OP_IPUT_BYTE: 2353 case OP_IPUT_BOOLEAN: 2354 genIPut(cUnit, mir, kWord, fieldOffset, false, isVolatile); 2355 break; 2356 case OP_IPUT_VOLATILE: 2357 case OP_IPUT_OBJECT_VOLATILE: 2358 isVolatile = true; 2359 // NOTE: intentional fallthrough 2360 case OP_IPUT_OBJECT: 2361 genIPut(cUnit, mir, kWord, fieldOffset, true, isVolatile); 2362 break; 2363 case OP_IGET_WIDE_VOLATILE: 2364 case OP_IPUT_WIDE_VOLATILE: 2365 genInterpSingleStep(cUnit, mir); 2366 break; 2367 default: 2368 return true; 2369 } 2370 return false; 2371 } 2372 2373 static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir) 2374 { 2375 OpCode dalvikOpCode = mir->dalvikInsn.opCode; 2376 int fieldOffset = mir->dalvikInsn.vC; 2377 switch (dalvikOpCode) { 2378 case OP_IGET_QUICK: 2379 case OP_IGET_OBJECT_QUICK: 2380 genIGet(cUnit, mir, kWord, fieldOffset, false); 2381 break; 2382 case OP_IPUT_QUICK: 2383 genIPut(cUnit, mir, kWord, fieldOffset, false, false); 2384 break; 2385 case OP_IPUT_OBJECT_QUICK: 2386 genIPut(cUnit, mir, kWord, fieldOffset, true, false); 2387 break; 2388 case OP_IGET_WIDE_QUICK: 2389 genIGetWide(cUnit, mir, fieldOffset); 2390 break; 2391 case OP_IPUT_WIDE_QUICK: 2392 genIPutWide(cUnit, mir, fieldOffset); 2393 break; 2394 default: 2395 return true; 2396 } 2397 return false; 2398 2399 } 2400 2401 /* Compare agaist zero */ 2402 static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 2403 ArmLIR *labelList) 2404 { 2405 OpCode dalvikOpCode = mir->dalvikInsn.opCode; 2406 ArmConditionCode cond; 2407 RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0); 2408 RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1); 2409 2410 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); 2411 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); 2412 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); 2413 2414 switch (dalvikOpCode) { 2415 case OP_IF_EQ: 2416 cond = kArmCondEq; 2417 break; 2418 case OP_IF_NE: 2419 cond = kArmCondNe; 2420 break; 2421 case OP_IF_LT: 2422 cond = kArmCondLt; 2423 break; 2424 case OP_IF_GE: 2425 cond = kArmCondGe; 2426 break; 2427 case OP_IF_GT: 2428 cond = kArmCondGt; 2429 break; 2430 case OP_IF_LE: 2431 cond = kArmCondLe; 2432 break; 2433 default: 2434 cond = 0; 2435 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode); 2436 dvmCompilerAbort(cUnit); 2437 } 2438 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]); 2439 /* This mostly likely will be optimized away in a later phase */ 2440 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]); 2441 return false; 2442 } 2443 2444 static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir) 2445 { 2446 OpCode opCode = mir->dalvikInsn.opCode; 2447 2448 switch (opCode) { 2449 case OP_MOVE_16: 2450 case OP_MOVE_OBJECT_16: 2451 case OP_MOVE_FROM16: 2452 case OP_MOVE_OBJECT_FROM16: { 2453 storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0), 2454 dvmCompilerGetSrc(cUnit, mir, 0)); 2455 break; 2456 } 2457 case OP_MOVE_WIDE_16: 2458 case OP_MOVE_WIDE_FROM16: { 2459 storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1), 2460 dvmCompilerGetSrcWide(cUnit, mir, 0, 1)); 2461 break; 2462 } 2463 default: 2464 return true; 2465 } 2466 return false; 2467 } 2468 2469 static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir) 2470 { 2471 OpCode opCode = mir->dalvikInsn.opCode; 2472 RegLocation rlSrc1; 2473 RegLocation rlSrc2; 2474 RegLocation rlDest; 2475 2476 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) { 2477 return genArithOp( cUnit, mir ); 2478 } 2479 2480 /* APUTs have 3 sources and no targets */ 2481 if (mir->ssaRep->numDefs == 0) { 2482 if (mir->ssaRep->numUses == 3) { 2483 rlDest = dvmCompilerGetSrc(cUnit, mir, 0); 2484 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1); 2485 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2); 2486 } else { 2487 assert(mir->ssaRep->numUses == 4); 2488 rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 2489 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2); 2490 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3); 2491 } 2492 } else { 2493 /* Two sources and 1 dest. Deduce the operand sizes */ 2494 if (mir->ssaRep->numUses == 4) { 2495 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 2496 rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3); 2497 } else { 2498 assert(mir->ssaRep->numUses == 2); 2499 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0); 2500 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1); 2501 } 2502 if (mir->ssaRep->numDefs == 2) { 2503 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 2504 } else { 2505 assert(mir->ssaRep->numDefs == 1); 2506 rlDest = dvmCompilerGetDest(cUnit, mir, 0); 2507 } 2508 } 2509 2510 2511 switch (opCode) { 2512 case OP_CMPL_FLOAT: 2513 case OP_CMPG_FLOAT: 2514 case OP_CMPL_DOUBLE: 2515 case OP_CMPG_DOUBLE: 2516 return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2); 2517 case OP_CMP_LONG: 2518 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2); 2519 break; 2520 case OP_AGET_WIDE: 2521 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3); 2522 break; 2523 case OP_AGET: 2524 case OP_AGET_OBJECT: 2525 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2); 2526 break; 2527 case OP_AGET_BOOLEAN: 2528 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0); 2529 break; 2530 case OP_AGET_BYTE: 2531 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0); 2532 break; 2533 case OP_AGET_CHAR: 2534 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1); 2535 break; 2536 case OP_AGET_SHORT: 2537 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1); 2538 break; 2539 case OP_APUT_WIDE: 2540 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3); 2541 break; 2542 case OP_APUT: 2543 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2); 2544 break; 2545 case OP_APUT_OBJECT: 2546 genArrayObjectPut(cUnit, mir, rlSrc1, rlSrc2, rlDest, 2); 2547 break; 2548 case OP_APUT_SHORT: 2549 case OP_APUT_CHAR: 2550 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1); 2551 break; 2552 case OP_APUT_BYTE: 2553 case OP_APUT_BOOLEAN: 2554 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0); 2555 break; 2556 default: 2557 return true; 2558 } 2559 return false; 2560 } 2561 2562 /* 2563 * Find the matching case. 2564 * 2565 * return values: 2566 * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case, 2567 * including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES). 2568 * r1 (high 32-bit): the branch offset of the matching case (only for indexes 2569 * above MAX_CHAINED_SWITCH_CASES). 2570 * 2571 * Instructions around the call are: 2572 * 2573 * mov r2, pc 2574 * blx &findPackedSwitchIndex 2575 * mov pc, r0 2576 * .align4 2577 * chaining cell for case 0 [12 bytes] 2578 * chaining cell for case 1 [12 bytes] 2579 * : 2580 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [12 bytes] 2581 * chaining cell for case default [8 bytes] 2582 * noChain exit 2583 */ 2584 static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc) 2585 { 2586 int size; 2587 int firstKey; 2588 const int *entries; 2589 int index; 2590 int jumpIndex; 2591 int caseDPCOffset = 0; 2592 /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */ 2593 int chainingPC = (pc + 4) & ~3; 2594 2595 /* 2596 * Packed switch data format: 2597 * ushort ident = 0x0100 magic value 2598 * ushort size number of entries in the table 2599 * int first_key first (and lowest) switch case value 2600 * int targets[size] branch targets, relative to switch opcode 2601 * 2602 * Total size is (4+size*2) 16-bit code units. 2603 */ 2604 size = switchData[1]; 2605 assert(size > 0); 2606 2607 firstKey = switchData[2]; 2608 firstKey |= switchData[3] << 16; 2609 2610 2611 /* The entries are guaranteed to be aligned on a 32-bit boundary; 2612 * we can treat them as a native int array. 2613 */ 2614 entries = (const int*) &switchData[4]; 2615 assert(((u4)entries & 0x3) == 0); 2616 2617 index = testVal - firstKey; 2618 2619 /* Jump to the default cell */ 2620 if (index < 0 || index >= size) { 2621 jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES); 2622 /* Jump to the non-chaining exit point */ 2623 } else if (index >= MAX_CHAINED_SWITCH_CASES) { 2624 jumpIndex = MAX_CHAINED_SWITCH_CASES + 1; 2625 caseDPCOffset = entries[index]; 2626 /* Jump to the inline chaining cell */ 2627 } else { 2628 jumpIndex = index; 2629 } 2630 2631 chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE; 2632 return (((s8) caseDPCOffset) << 32) | (u8) chainingPC; 2633 } 2634 2635 /* See comments for findPackedSwitchIndex */ 2636 static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc) 2637 { 2638 int size; 2639 const int *keys; 2640 const int *entries; 2641 int chainingPC = (pc + 4) & ~3; 2642 int i; 2643 2644 /* 2645 * Sparse switch data format: 2646 * ushort ident = 0x0200 magic value 2647 * ushort size number of entries in the table; > 0 2648 * int keys[size] keys, sorted low-to-high; 32-bit aligned 2649 * int targets[size] branch targets, relative to switch opcode 2650 * 2651 * Total size is (2+size*4) 16-bit code units. 2652 */ 2653 2654 size = switchData[1]; 2655 assert(size > 0); 2656 2657 /* The keys are guaranteed to be aligned on a 32-bit boundary; 2658 * we can treat them as a native int array. 2659 */ 2660 keys = (const int*) &switchData[2]; 2661 assert(((u4)keys & 0x3) == 0); 2662 2663 /* The entries are guaranteed to be aligned on a 32-bit boundary; 2664 * we can treat them as a native int array. 2665 */ 2666 entries = keys + size; 2667 assert(((u4)entries & 0x3) == 0); 2668 2669 /* 2670 * Run through the list of keys, which are guaranteed to 2671 * be sorted low-to-high. 2672 * 2673 * Most tables have 3-4 entries. Few have more than 10. A binary 2674 * search here is probably not useful. 2675 */ 2676 for (i = 0; i < size; i++) { 2677 int k = keys[i]; 2678 if (k == testVal) { 2679 /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */ 2680 int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ? 2681 i : MAX_CHAINED_SWITCH_CASES + 1; 2682 chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE; 2683 return (((s8) entries[i]) << 32) | (u8) chainingPC; 2684 } else if (k > testVal) { 2685 break; 2686 } 2687 } 2688 return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 2689 CHAIN_CELL_NORMAL_SIZE; 2690 } 2691 2692 static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir) 2693 { 2694 OpCode dalvikOpCode = mir->dalvikInsn.opCode; 2695 switch (dalvikOpCode) { 2696 case OP_FILL_ARRAY_DATA: { 2697 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2698 // Making a call - use explicit registers 2699 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2700 genExportPC(cUnit, mir); 2701 loadValueDirectFixed(cUnit, rlSrc, r0); 2702 LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInterpHandleFillArrayData); 2703 loadConstant(cUnit, r1, 2704 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB)); 2705 opReg(cUnit, kOpBlx, r2); 2706 dvmCompilerClobberCallRegs(cUnit); 2707 /* generate a branch over if successful */ 2708 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */ 2709 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe); 2710 loadConstant(cUnit, r0, 2711 (int) (cUnit->method->insns + mir->offset)); 2712 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 2713 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2714 target->defMask = ENCODE_ALL; 2715 branchOver->generic.target = (LIR *) target; 2716 break; 2717 } 2718 /* 2719 * Compute the goto target of up to 2720 * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells. 2721 * See the comment before findPackedSwitchIndex for the code layout. 2722 */ 2723 case OP_PACKED_SWITCH: 2724 case OP_SPARSE_SWITCH: { 2725 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 2726 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 2727 loadValueDirectFixed(cUnit, rlSrc, r1); 2728 dvmCompilerLockAllTemps(cUnit); 2729 if (dalvikOpCode == OP_PACKED_SWITCH) { 2730 LOAD_FUNC_ADDR(cUnit, r4PC, (int)findPackedSwitchIndex); 2731 } else { 2732 LOAD_FUNC_ADDR(cUnit, r4PC, (int)findSparseSwitchIndex); 2733 } 2734 /* r0 <- Addr of the switch data */ 2735 loadConstant(cUnit, r0, 2736 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB)); 2737 /* r2 <- pc of the instruction following the blx */ 2738 opRegReg(cUnit, kOpMov, r2, rpc); 2739 opReg(cUnit, kOpBlx, r4PC); 2740 dvmCompilerClobberCallRegs(cUnit); 2741 /* pc <- computed goto target */ 2742 opRegReg(cUnit, kOpMov, rpc, r0); 2743 break; 2744 } 2745 default: 2746 return true; 2747 } 2748 return false; 2749 } 2750 2751 /* 2752 * See the example of predicted inlining listed before the 2753 * genValidationForPredictedInline function. The function here takes care the 2754 * branch over at 0x4858de78 and the misprediction target at 0x4858de7a. 2755 */ 2756 static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir, 2757 BasicBlock *bb, 2758 ArmLIR *labelList) 2759 { 2760 BasicBlock *fallThrough = bb->fallThrough; 2761 2762 /* Bypass the move-result block if there is one */ 2763 if (fallThrough->firstMIRInsn) { 2764 assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED); 2765 fallThrough = fallThrough->fallThrough; 2766 } 2767 /* Generate a branch over if the predicted inlining is correct */ 2768 genUnconditionalBranch(cUnit, &labelList[fallThrough->id]); 2769 2770 /* Reset the register state */ 2771 dvmCompilerResetRegPool(cUnit); 2772 dvmCompilerClobberAllRegs(cUnit); 2773 dvmCompilerResetNullCheck(cUnit); 2774 2775 /* Target for the slow invoke path */ 2776 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 2777 target->defMask = ENCODE_ALL; 2778 /* Hook up the target to the verification branch */ 2779 mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target; 2780 } 2781 2782 static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 2783 ArmLIR *labelList) 2784 { 2785 ArmLIR *retChainingCell = NULL; 2786 ArmLIR *pcrLabel = NULL; 2787 2788 /* An invoke with the MIR_INLINED is effectively a no-op */ 2789 if (mir->OptimizationFlags & MIR_INLINED) 2790 return false; 2791 2792 if (bb->fallThrough != NULL) 2793 retChainingCell = &labelList[bb->fallThrough->id]; 2794 2795 DecodedInstruction *dInsn = &mir->dalvikInsn; 2796 switch (mir->dalvikInsn.opCode) { 2797 /* 2798 * calleeMethod = this->clazz->vtable[ 2799 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex 2800 * ] 2801 */ 2802 case OP_INVOKE_VIRTUAL: 2803 case OP_INVOKE_VIRTUAL_RANGE: { 2804 ArmLIR *predChainingCell = &labelList[bb->taken->id]; 2805 int methodIndex = 2806 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]-> 2807 methodIndex; 2808 2809 /* 2810 * If the invoke has non-null misPredBranchOver, we need to generate 2811 * the non-inlined version of the invoke here to handle the 2812 * mispredicted case. 2813 */ 2814 if (mir->meta.callsiteInfo->misPredBranchOver) { 2815 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList); 2816 } 2817 2818 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL) 2819 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 2820 else 2821 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 2822 2823 genInvokeVirtualCommon(cUnit, mir, methodIndex, 2824 retChainingCell, 2825 predChainingCell, 2826 pcrLabel); 2827 break; 2828 } 2829 /* 2830 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex 2831 * ->pResMethods[BBBB]->methodIndex] 2832 */ 2833 case OP_INVOKE_SUPER: 2834 case OP_INVOKE_SUPER_RANGE: { 2835 /* Grab the method ptr directly from what the interpreter sees */ 2836 const Method *calleeMethod = mir->meta.callsiteInfo->method; 2837 assert(calleeMethod == cUnit->method->clazz->super->vtable[ 2838 cUnit->method->clazz->pDvmDex-> 2839 pResMethods[dInsn->vB]->methodIndex]); 2840 2841 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER) 2842 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 2843 else 2844 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 2845 2846 /* r0 = calleeMethod */ 2847 loadConstant(cUnit, r0, (int) calleeMethod); 2848 2849 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 2850 calleeMethod); 2851 break; 2852 } 2853 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */ 2854 case OP_INVOKE_DIRECT: 2855 case OP_INVOKE_DIRECT_RANGE: { 2856 /* Grab the method ptr directly from what the interpreter sees */ 2857 const Method *calleeMethod = mir->meta.callsiteInfo->method; 2858 assert(calleeMethod == 2859 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]); 2860 2861 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT) 2862 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 2863 else 2864 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 2865 2866 /* r0 = calleeMethod */ 2867 loadConstant(cUnit, r0, (int) calleeMethod); 2868 2869 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 2870 calleeMethod); 2871 break; 2872 } 2873 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */ 2874 case OP_INVOKE_STATIC: 2875 case OP_INVOKE_STATIC_RANGE: { 2876 /* Grab the method ptr directly from what the interpreter sees */ 2877 const Method *calleeMethod = mir->meta.callsiteInfo->method; 2878 assert(calleeMethod == 2879 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]); 2880 2881 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC) 2882 genProcessArgsNoRange(cUnit, mir, dInsn, 2883 NULL /* no null check */); 2884 else 2885 genProcessArgsRange(cUnit, mir, dInsn, 2886 NULL /* no null check */); 2887 2888 /* r0 = calleeMethod */ 2889 loadConstant(cUnit, r0, (int) calleeMethod); 2890 2891 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 2892 calleeMethod); 2893 break; 2894 } 2895 /* 2896 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz, 2897 * BBBB, method, method->clazz->pDvmDex) 2898 * 2899 * The following is an example of generated code for 2900 * "invoke-interface v0" 2901 * 2902 * -------- dalvik offset: 0x0008 @ invoke-interface v0 2903 * 0x47357e36 : ldr r0, [r5, #0] --+ 2904 * 0x47357e38 : sub r7,r5,#24 | 2905 * 0x47357e3c : cmp r0, #0 | genProcessArgsNoRange 2906 * 0x47357e3e : beq 0x47357e82 | 2907 * 0x47357e40 : stmia r7, <r0> --+ 2908 * 0x47357e42 : ldr r4, [pc, #120] --> r4 <- dalvikPC of this invoke 2909 * 0x47357e44 : add r1, pc, #64 --> r1 <- &retChainingCell 2910 * 0x47357e46 : add r2, pc, #72 --> r2 <- &predictedChainingCell 2911 * 0x47357e48 : blx_1 0x47348190 --+ TEMPLATE_INVOKE_METHOD_ 2912 * 0x47357e4a : blx_2 see above --+ PREDICTED_CHAIN 2913 * 0x47357e4c : b 0x47357e90 --> off to the predicted chain 2914 * 0x47357e4e : b 0x47357e82 --> punt to the interpreter 2915 * 0x47357e50 : mov r8, r1 --+ 2916 * 0x47357e52 : mov r9, r2 | 2917 * 0x47357e54 : ldr r2, [pc, #96] | 2918 * 0x47357e56 : mov r10, r3 | 2919 * 0x47357e58 : movs r0, r3 | dvmFindInterfaceMethodInCache 2920 * 0x47357e5a : ldr r3, [pc, #88] | 2921 * 0x47357e5c : ldr r7, [pc, #80] | 2922 * 0x47357e5e : mov r1, #1452 | 2923 * 0x47357e62 : blx r7 --+ 2924 * 0x47357e64 : cmp r0, #0 --> calleeMethod == NULL? 2925 * 0x47357e66 : bne 0x47357e6e --> branch over the throw if !r0 2926 * 0x47357e68 : ldr r0, [pc, #80] --> load Dalvik PC of the invoke 2927 * 0x47357e6a : blx_1 0x47348494 --+ TEMPLATE_THROW_EXCEPTION_ 2928 * 0x47357e6c : blx_2 see above --+ COMMON 2929 * 0x47357e6e : mov r1, r8 --> r1 <- &retChainingCell 2930 * 0x47357e70 : cmp r1, #0 --> compare against 0 2931 * 0x47357e72 : bgt 0x47357e7c --> >=0? don't rechain 2932 * 0x47357e74 : ldr r7, [r6, #108] --+ 2933 * 0x47357e76 : mov r2, r9 | dvmJitToPatchPredictedChain 2934 * 0x47357e78 : mov r3, r10 | 2935 * 0x47357e7a : blx r7 --+ 2936 * 0x47357e7c : add r1, pc, #8 --> r1 <- &retChainingCell 2937 * 0x47357e7e : blx_1 0x4734809c --+ TEMPLATE_INVOKE_METHOD_NO_OPT 2938 * 0x47357e80 : blx_2 see above --+ 2939 * -------- reconstruct dalvik PC : 0x425719dc @ +0x0008 2940 * 0x47357e82 : ldr r0, [pc, #56] 2941 * Exception_Handling: 2942 * 0x47357e84 : ldr r1, [r6, #92] 2943 * 0x47357e86 : blx r1 2944 * 0x47357e88 : .align4 2945 * -------- chaining cell (hot): 0x000b 2946 * 0x47357e88 : ldr r0, [r6, #104] 2947 * 0x47357e8a : blx r0 2948 * 0x47357e8c : data 0x19e2(6626) 2949 * 0x47357e8e : data 0x4257(16983) 2950 * 0x47357e90 : .align4 2951 * -------- chaining cell (predicted) 2952 * 0x47357e90 : data 0xe7fe(59390) --> will be patched into bx 2953 * 0x47357e92 : data 0x0000(0) 2954 * 0x47357e94 : data 0x0000(0) --> class 2955 * 0x47357e96 : data 0x0000(0) 2956 * 0x47357e98 : data 0x0000(0) --> method 2957 * 0x47357e9a : data 0x0000(0) 2958 * 0x47357e9c : data 0x0000(0) --> rechain count 2959 * 0x47357e9e : data 0x0000(0) 2960 * -------- end of chaining cells (0x006c) 2961 * 0x47357eb0 : .word (0xad03e369) 2962 * 0x47357eb4 : .word (0x28a90) 2963 * 0x47357eb8 : .word (0x41a63394) 2964 * 0x47357ebc : .word (0x425719dc) 2965 */ 2966 case OP_INVOKE_INTERFACE: 2967 case OP_INVOKE_INTERFACE_RANGE: { 2968 ArmLIR *predChainingCell = &labelList[bb->taken->id]; 2969 2970 /* 2971 * If the invoke has non-null misPredBranchOver, we need to generate 2972 * the non-inlined version of the invoke here to handle the 2973 * mispredicted case. 2974 */ 2975 if (mir->meta.callsiteInfo->misPredBranchOver) { 2976 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList); 2977 } 2978 2979 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE) 2980 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 2981 else 2982 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 2983 2984 /* "this" is already left in r0 by genProcessArgs* */ 2985 2986 /* r4PC = dalvikCallsite */ 2987 loadConstant(cUnit, r4PC, 2988 (int) (cUnit->method->insns + mir->offset)); 2989 2990 /* r1 = &retChainingCell */ 2991 ArmLIR *addrRetChain = 2992 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0); 2993 addrRetChain->generic.target = (LIR *) retChainingCell; 2994 2995 /* r2 = &predictedChainingCell */ 2996 ArmLIR *predictedChainingCell = 2997 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0); 2998 predictedChainingCell->generic.target = (LIR *) predChainingCell; 2999 3000 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN); 3001 3002 /* return through lr - jump to the chaining cell */ 3003 genUnconditionalBranch(cUnit, predChainingCell); 3004 3005 /* 3006 * null-check on "this" may have been eliminated, but we still need 3007 * a PC-reconstruction label for stack overflow bailout. 3008 */ 3009 if (pcrLabel == NULL) { 3010 int dPC = (int) (cUnit->method->insns + mir->offset); 3011 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true); 3012 pcrLabel->opCode = kArmPseudoPCReconstructionCell; 3013 pcrLabel->operands[0] = dPC; 3014 pcrLabel->operands[1] = mir->offset; 3015 /* Insert the place holder to the growable list */ 3016 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel); 3017 } 3018 3019 /* return through lr+2 - punt to the interpreter */ 3020 genUnconditionalBranch(cUnit, pcrLabel); 3021 3022 /* 3023 * return through lr+4 - fully resolve the callee method. 3024 * r1 <- count 3025 * r2 <- &predictedChainCell 3026 * r3 <- this->class 3027 * r4 <- dPC 3028 * r7 <- this->class->vtable 3029 */ 3030 3031 /* Save count, &predictedChainCell, and class to high regs first */ 3032 genRegCopy(cUnit, r8, r1); 3033 genRegCopy(cUnit, r9, r2); 3034 genRegCopy(cUnit, r10, r3); 3035 3036 /* r0 now contains this->clazz */ 3037 genRegCopy(cUnit, r0, r3); 3038 3039 /* r1 = BBBB */ 3040 loadConstant(cUnit, r1, dInsn->vB); 3041 3042 /* r2 = method (caller) */ 3043 loadConstant(cUnit, r2, (int) cUnit->method); 3044 3045 /* r3 = pDvmDex */ 3046 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex); 3047 3048 LOAD_FUNC_ADDR(cUnit, r7, 3049 (intptr_t) dvmFindInterfaceMethodInCache); 3050 opReg(cUnit, kOpBlx, r7); 3051 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */ 3052 3053 dvmCompilerClobberCallRegs(cUnit); 3054 /* generate a branch over if the interface method is resolved */ 3055 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */ 3056 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe); 3057 /* 3058 * calleeMethod == NULL -> throw 3059 */ 3060 loadConstant(cUnit, r0, 3061 (int) (cUnit->method->insns + mir->offset)); 3062 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 3063 /* noreturn */ 3064 3065 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 3066 target->defMask = ENCODE_ALL; 3067 branchOver->generic.target = (LIR *) target; 3068 3069 genRegCopy(cUnit, r1, r8); 3070 3071 /* Check if rechain limit is reached */ 3072 opRegImm(cUnit, kOpCmp, r1, 0); 3073 3074 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt); 3075 3076 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, 3077 jitToInterpEntries.dvmJitToPatchPredictedChain), r7); 3078 3079 genRegCopy(cUnit, r1, rGLUE); 3080 genRegCopy(cUnit, r2, r9); 3081 genRegCopy(cUnit, r3, r10); 3082 3083 /* 3084 * r0 = calleeMethod 3085 * r2 = &predictedChainingCell 3086 * r3 = class 3087 * 3088 * &returnChainingCell has been loaded into r1 but is not needed 3089 * when patching the chaining cell and will be clobbered upon 3090 * returning so it will be reconstructed again. 3091 */ 3092 opReg(cUnit, kOpBlx, r7); 3093 3094 /* r1 = &retChainingCell */ 3095 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0); 3096 addrRetChain->generic.target = (LIR *) retChainingCell; 3097 3098 bypassRechaining->generic.target = (LIR *) addrRetChain; 3099 3100 /* 3101 * r0 = this, r1 = calleeMethod, 3102 * r1 = &ChainingCell, 3103 * r4PC = callsiteDPC, 3104 */ 3105 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT); 3106 #if defined(WITH_JIT_TUNING) 3107 gDvmJit.invokePolymorphic++; 3108 #endif 3109 /* Handle exceptions using the interpreter */ 3110 genTrap(cUnit, mir->offset, pcrLabel); 3111 break; 3112 } 3113 /* NOP */ 3114 case OP_INVOKE_DIRECT_EMPTY: { 3115 return false; 3116 } 3117 case OP_FILLED_NEW_ARRAY: 3118 case OP_FILLED_NEW_ARRAY_RANGE: { 3119 /* Just let the interpreter deal with these */ 3120 genInterpSingleStep(cUnit, mir); 3121 break; 3122 } 3123 default: 3124 return true; 3125 } 3126 return false; 3127 } 3128 3129 static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir, 3130 BasicBlock *bb, ArmLIR *labelList) 3131 { 3132 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id]; 3133 ArmLIR *predChainingCell = &labelList[bb->taken->id]; 3134 ArmLIR *pcrLabel = NULL; 3135 3136 /* An invoke with the MIR_INLINED is effectively a no-op */ 3137 if (mir->OptimizationFlags & MIR_INLINED) 3138 return false; 3139 3140 DecodedInstruction *dInsn = &mir->dalvikInsn; 3141 switch (mir->dalvikInsn.opCode) { 3142 /* calleeMethod = this->clazz->vtable[BBBB] */ 3143 case OP_INVOKE_VIRTUAL_QUICK_RANGE: 3144 case OP_INVOKE_VIRTUAL_QUICK: { 3145 int methodIndex = dInsn->vB; 3146 3147 /* 3148 * If the invoke has non-null misPredBranchOver, we need to generate 3149 * the non-inlined version of the invoke here to handle the 3150 * mispredicted case. 3151 */ 3152 if (mir->meta.callsiteInfo->misPredBranchOver) { 3153 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList); 3154 } 3155 3156 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK) 3157 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3158 else 3159 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3160 3161 genInvokeVirtualCommon(cUnit, mir, methodIndex, 3162 retChainingCell, 3163 predChainingCell, 3164 pcrLabel); 3165 break; 3166 } 3167 /* calleeMethod = method->clazz->super->vtable[BBBB] */ 3168 case OP_INVOKE_SUPER_QUICK: 3169 case OP_INVOKE_SUPER_QUICK_RANGE: { 3170 /* Grab the method ptr directly from what the interpreter sees */ 3171 const Method *calleeMethod = mir->meta.callsiteInfo->method; 3172 assert(calleeMethod == 3173 cUnit->method->clazz->super->vtable[dInsn->vB]); 3174 3175 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK) 3176 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel); 3177 else 3178 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel); 3179 3180 /* r0 = calleeMethod */ 3181 loadConstant(cUnit, r0, (int) calleeMethod); 3182 3183 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel, 3184 calleeMethod); 3185 break; 3186 } 3187 default: 3188 return true; 3189 } 3190 return false; 3191 } 3192 3193 /* 3194 * This operation is complex enough that we'll do it partly inline 3195 * and partly with a handler. NOTE: the handler uses hardcoded 3196 * values for string object offsets and must be revisitied if the 3197 * layout changes. 3198 */ 3199 static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir) 3200 { 3201 #if defined(USE_GLOBAL_STRING_DEFS) 3202 return false; 3203 #else 3204 ArmLIR *rollback; 3205 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0); 3206 RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1); 3207 3208 loadValueDirectFixed(cUnit, rlThis, r0); 3209 loadValueDirectFixed(cUnit, rlComp, r1); 3210 /* Test objects for NULL */ 3211 rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL); 3212 genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback); 3213 /* 3214 * TUNING: we could check for object pointer equality before invoking 3215 * handler. Unclear whether the gain would be worth the added code size 3216 * expansion. 3217 */ 3218 genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO); 3219 storeValue(cUnit, inlinedTarget(cUnit, mir, false), 3220 dvmCompilerGetReturn(cUnit)); 3221 return true; 3222 #endif 3223 } 3224 3225 static bool genInlinedFastIndexOf(CompilationUnit *cUnit, MIR *mir) 3226 { 3227 #if defined(USE_GLOBAL_STRING_DEFS) 3228 return false; 3229 #else 3230 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0); 3231 RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1); 3232 3233 loadValueDirectFixed(cUnit, rlThis, r0); 3234 loadValueDirectFixed(cUnit, rlChar, r1); 3235 RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2); 3236 loadValueDirectFixed(cUnit, rlStart, r2); 3237 /* Test objects for NULL */ 3238 genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL); 3239 genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF); 3240 storeValue(cUnit, inlinedTarget(cUnit, mir, false), 3241 dvmCompilerGetReturn(cUnit)); 3242 return true; 3243 #endif 3244 } 3245 3246 // Generates an inlined String.isEmpty or String.length. 3247 static bool genInlinedStringIsEmptyOrLength(CompilationUnit *cUnit, MIR *mir, 3248 bool isEmpty) 3249 { 3250 // dst = src.length(); 3251 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0); 3252 RegLocation rlDest = inlinedTarget(cUnit, mir, false); 3253 rlObj = loadValue(cUnit, rlObj, kCoreReg); 3254 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 3255 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL); 3256 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, 3257 rlResult.lowReg); 3258 if (isEmpty) { 3259 // dst = (dst == 0); 3260 int tReg = dvmCompilerAllocTemp(cUnit); 3261 opRegReg(cUnit, kOpNeg, tReg, rlResult.lowReg); 3262 opRegRegReg(cUnit, kOpAdc, rlResult.lowReg, rlResult.lowReg, tReg); 3263 } 3264 storeValue(cUnit, rlDest, rlResult); 3265 return false; 3266 } 3267 3268 static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir) 3269 { 3270 return genInlinedStringIsEmptyOrLength(cUnit, mir, false); 3271 } 3272 3273 static bool genInlinedStringIsEmpty(CompilationUnit *cUnit, MIR *mir) 3274 { 3275 return genInlinedStringIsEmptyOrLength(cUnit, mir, true); 3276 } 3277 3278 static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir) 3279 { 3280 int contents = offsetof(ArrayObject, contents); 3281 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0); 3282 RegLocation rlIdx = dvmCompilerGetSrc(cUnit, mir, 1); 3283 RegLocation rlDest = inlinedTarget(cUnit, mir, false); 3284 RegLocation rlResult; 3285 rlObj = loadValue(cUnit, rlObj, kCoreReg); 3286 rlIdx = loadValue(cUnit, rlIdx, kCoreReg); 3287 int regMax = dvmCompilerAllocTemp(cUnit); 3288 int regOff = dvmCompilerAllocTemp(cUnit); 3289 int regPtr = dvmCompilerAllocTemp(cUnit); 3290 ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, 3291 mir->offset, NULL); 3292 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax); 3293 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff); 3294 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr); 3295 genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel); 3296 dvmCompilerFreeTemp(cUnit, regMax); 3297 opRegImm(cUnit, kOpAdd, regPtr, contents); 3298 opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg); 3299 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 3300 loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf); 3301 storeValue(cUnit, rlDest, rlResult); 3302 return false; 3303 } 3304 3305 static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir) 3306 { 3307 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 3308 rlSrc = loadValue(cUnit, rlSrc, kCoreReg); 3309 RegLocation rlDest = inlinedTarget(cUnit, mir, false); 3310 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 3311 int signReg = dvmCompilerAllocTemp(cUnit); 3312 /* 3313 * abs(x) = y<=x>>31, (x+y)^y. 3314 * Thumb2's IT block also yields 3 instructions, but imposes 3315 * scheduling constraints. 3316 */ 3317 opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31); 3318 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg); 3319 opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg); 3320 storeValue(cUnit, rlDest, rlResult); 3321 return false; 3322 } 3323 3324 static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir) 3325 { 3326 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 3327 RegLocation rlDest = inlinedTargetWide(cUnit, mir, false); 3328 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); 3329 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 3330 int signReg = dvmCompilerAllocTemp(cUnit); 3331 /* 3332 * abs(x) = y<=x>>31, (x+y)^y. 3333 * Thumb2 IT block allows slightly shorter sequence, 3334 * but introduces a scheduling barrier. Stick with this 3335 * mechanism for now. 3336 */ 3337 opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31); 3338 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg); 3339 opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg); 3340 opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg); 3341 opRegReg(cUnit, kOpXor, rlResult.highReg, signReg); 3342 storeValueWide(cUnit, rlDest, rlResult); 3343 return false; 3344 } 3345 3346 static bool genInlinedIntFloatConversion(CompilationUnit *cUnit, MIR *mir) 3347 { 3348 // Just move from source to destination... 3349 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0); 3350 RegLocation rlDest = inlinedTarget(cUnit, mir, false); 3351 storeValue(cUnit, rlDest, rlSrc); 3352 return false; 3353 } 3354 3355 static bool genInlinedLongDoubleConversion(CompilationUnit *cUnit, MIR *mir) 3356 { 3357 // Just move from source to destination... 3358 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1); 3359 RegLocation rlDest = inlinedTargetWide(cUnit, mir, false); 3360 storeValueWide(cUnit, rlDest, rlSrc); 3361 return false; 3362 } 3363 3364 /* 3365 * NOTE: Handles both range and non-range versions (arguments 3366 * have already been normalized by this point). 3367 */ 3368 static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir) 3369 { 3370 DecodedInstruction *dInsn = &mir->dalvikInsn; 3371 switch( mir->dalvikInsn.opCode) { 3372 case OP_EXECUTE_INLINE_RANGE: 3373 case OP_EXECUTE_INLINE: { 3374 unsigned int i; 3375 const InlineOperation* inLineTable = dvmGetInlineOpsTable(); 3376 int offset = offsetof(InterpState, retval); 3377 int operation = dInsn->vB; 3378 switch (operation) { 3379 case INLINE_EMPTYINLINEMETHOD: 3380 return false; /* Nop */ 3381 case INLINE_STRING_LENGTH: 3382 return genInlinedStringLength(cUnit, mir); 3383 case INLINE_STRING_IS_EMPTY: 3384 return genInlinedStringIsEmpty(cUnit, mir); 3385 case INLINE_MATH_ABS_INT: 3386 return genInlinedAbsInt(cUnit, mir); 3387 case INLINE_MATH_ABS_LONG: 3388 return genInlinedAbsLong(cUnit, mir); 3389 case INLINE_MATH_MIN_INT: 3390 return genInlinedMinMaxInt(cUnit, mir, true); 3391 case INLINE_MATH_MAX_INT: 3392 return genInlinedMinMaxInt(cUnit, mir, false); 3393 case INLINE_STRING_CHARAT: 3394 return genInlinedStringCharAt(cUnit, mir); 3395 case INLINE_MATH_SQRT: 3396 if (genInlineSqrt(cUnit, mir)) 3397 return false; 3398 else 3399 break; /* Handle with C routine */ 3400 case INLINE_MATH_ABS_FLOAT: 3401 if (genInlinedAbsFloat(cUnit, mir)) 3402 return false; 3403 else 3404 break; 3405 case INLINE_MATH_ABS_DOUBLE: 3406 if (genInlinedAbsDouble(cUnit, mir)) 3407 return false; 3408 else 3409 break; 3410 case INLINE_STRING_COMPARETO: 3411 if (genInlinedCompareTo(cUnit, mir)) 3412 return false; 3413 else 3414 break; 3415 case INLINE_STRING_FASTINDEXOF_II: 3416 if (genInlinedFastIndexOf(cUnit, mir)) 3417 return false; 3418 else 3419 break; 3420 case INLINE_FLOAT_TO_RAW_INT_BITS: 3421 case INLINE_INT_BITS_TO_FLOAT: 3422 return genInlinedIntFloatConversion(cUnit, mir); 3423 case INLINE_DOUBLE_TO_RAW_LONG_BITS: 3424 case INLINE_LONG_BITS_TO_DOUBLE: 3425 return genInlinedLongDoubleConversion(cUnit, mir); 3426 case INLINE_STRING_EQUALS: 3427 case INLINE_MATH_COS: 3428 case INLINE_MATH_SIN: 3429 case INLINE_FLOAT_TO_INT_BITS: 3430 case INLINE_DOUBLE_TO_LONG_BITS: 3431 break; /* Handle with C routine */ 3432 default: 3433 dvmCompilerAbort(cUnit); 3434 } 3435 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */ 3436 dvmCompilerClobberCallRegs(cUnit); 3437 dvmCompilerClobber(cUnit, r4PC); 3438 dvmCompilerClobber(cUnit, r7); 3439 opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset); 3440 opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7)); 3441 LOAD_FUNC_ADDR(cUnit, r4PC, (int)inLineTable[operation].func); 3442 genExportPC(cUnit, mir); 3443 for (i=0; i < dInsn->vA; i++) { 3444 loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i); 3445 } 3446 opReg(cUnit, kOpBlx, r4PC); 3447 opRegImm(cUnit, kOpAdd, r13, 8); 3448 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */ 3449 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe); 3450 loadConstant(cUnit, r0, 3451 (int) (cUnit->method->insns + mir->offset)); 3452 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); 3453 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 3454 target->defMask = ENCODE_ALL; 3455 branchOver->generic.target = (LIR *) target; 3456 break; 3457 } 3458 default: 3459 return true; 3460 } 3461 return false; 3462 } 3463 3464 static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir) 3465 { 3466 //TUNING: We're using core regs here - not optimal when target is a double 3467 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1); 3468 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true); 3469 loadConstantNoClobber(cUnit, rlResult.lowReg, 3470 mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL); 3471 loadConstantNoClobber(cUnit, rlResult.highReg, 3472 (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL); 3473 storeValueWide(cUnit, rlDest, rlResult); 3474 return false; 3475 } 3476 3477 /* 3478 * The following are special processing routines that handle transfer of 3479 * controls between compiled code and the interpreter. Certain VM states like 3480 * Dalvik PC and special-purpose registers are reconstructed here. 3481 */ 3482 3483 /* 3484 * Insert a 3485 * b .+4 3486 * nop 3487 * pair at the beginning of a chaining cell. This serves as the 3488 * switch branch that selects between reverting to the interpreter or 3489 * not. Once the cell is chained to a translation, the cell will 3490 * contain a 32-bit branch. Subsequent chain/unchain operations will 3491 * then only alter that first 16-bits - the "b .+4" for unchaining, 3492 * and the restoration of the first half of the 32-bit branch for 3493 * rechaining. 3494 */ 3495 static void insertChainingSwitch(CompilationUnit *cUnit) 3496 { 3497 ArmLIR *branch = newLIR0(cUnit, kThumbBUncond); 3498 newLIR2(cUnit, kThumbOrr, r0, r0); 3499 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); 3500 target->defMask = ENCODE_ALL; 3501 branch->generic.target = (LIR *) target; 3502 } 3503 3504 /* Chaining cell for code that may need warmup. */ 3505 static void handleNormalChainingCell(CompilationUnit *cUnit, 3506 unsigned int offset) 3507 { 3508 /* 3509 * Use raw instruction constructors to guarantee that the generated 3510 * instructions fit the predefined cell size. 3511 */ 3512 insertChainingSwitch(cUnit); 3513 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE, 3514 offsetof(InterpState, 3515 jitToInterpEntries.dvmJitToInterpNormal) >> 2); 3516 newLIR1(cUnit, kThumbBlxR, r0); 3517 addWordData(cUnit, (int) (cUnit->method->insns + offset), true); 3518 } 3519 3520 /* 3521 * Chaining cell for instructions that immediately following already translated 3522 * code. 3523 */ 3524 static void handleHotChainingCell(CompilationUnit *cUnit, 3525 unsigned int offset) 3526 { 3527 /* 3528 * Use raw instruction constructors to guarantee that the generated 3529 * instructions fit the predefined cell size. 3530 */ 3531 insertChainingSwitch(cUnit); 3532 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE, 3533 offsetof(InterpState, 3534 jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2); 3535 newLIR1(cUnit, kThumbBlxR, r0); 3536 addWordData(cUnit, (int) (cUnit->method->insns + offset), true); 3537 } 3538 3539 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING) 3540 /* Chaining cell for branches that branch back into the same basic block */ 3541 static void handleBackwardBranchChainingCell(CompilationUnit *cUnit, 3542 unsigned int offset) 3543 { 3544 /* 3545 * Use raw instruction constructors to guarantee that the generated 3546 * instructions fit the predefined cell size. 3547 */ 3548 insertChainingSwitch(cUnit); 3549 #if defined(WITH_SELF_VERIFICATION) 3550 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE, 3551 offsetof(InterpState, 3552 jitToInterpEntries.dvmJitToInterpBackwardBranch) >> 2); 3553 #else 3554 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE, 3555 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2); 3556 #endif 3557 newLIR1(cUnit, kThumbBlxR, r0); 3558 addWordData(cUnit, (int) (cUnit->method->insns + offset), true); 3559 } 3560 3561 #endif 3562 /* Chaining cell for monomorphic method invocations. */ 3563 static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit, 3564 const Method *callee) 3565 { 3566 /* 3567 * Use raw instruction constructors to guarantee that the generated 3568 * instructions fit the predefined cell size. 3569 */ 3570 insertChainingSwitch(cUnit); 3571 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE, 3572 offsetof(InterpState, 3573 jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2); 3574 newLIR1(cUnit, kThumbBlxR, r0); 3575 addWordData(cUnit, (int) (callee->insns), true); 3576 } 3577 3578 /* Chaining cell for monomorphic method invocations. */ 3579 static void handleInvokePredictedChainingCell(CompilationUnit *cUnit) 3580 { 3581 3582 /* Should not be executed in the initial state */ 3583 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true); 3584 /* To be filled: class */ 3585 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true); 3586 /* To be filled: method */ 3587 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true); 3588 /* 3589 * Rechain count. The initial value of 0 here will trigger chaining upon 3590 * the first invocation of this callsite. 3591 */ 3592 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true); 3593 } 3594 3595 /* Load the Dalvik PC into r0 and jump to the specified target */ 3596 static void handlePCReconstruction(CompilationUnit *cUnit, 3597 ArmLIR *targetLabel) 3598 { 3599 ArmLIR **pcrLabel = 3600 (ArmLIR **) cUnit->pcReconstructionList.elemList; 3601 int numElems = cUnit->pcReconstructionList.numUsed; 3602 int i; 3603 for (i = 0; i < numElems; i++) { 3604 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]); 3605 /* r0 = dalvik PC */ 3606 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]); 3607 genUnconditionalBranch(cUnit, targetLabel); 3608 } 3609 } 3610 3611 static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = { 3612 "kMirOpPhi", 3613 "kMirOpNullNRangeUpCheck", 3614 "kMirOpNullNRangeDownCheck", 3615 "kMirOpLowerBound", 3616 "kMirOpPunt", 3617 "kMirOpCheckInlinePrediction", 3618 }; 3619 3620 /* 3621 * vA = arrayReg; 3622 * vB = idxReg; 3623 * vC = endConditionReg; 3624 * arg[0] = maxC 3625 * arg[1] = minC 3626 * arg[2] = loopBranchConditionCode 3627 */ 3628 static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir) 3629 { 3630 /* 3631 * NOTE: these synthesized blocks don't have ssa names assigned 3632 * for Dalvik registers. However, because they dominate the following 3633 * blocks we can simply use the Dalvik name w/ subscript 0 as the 3634 * ssa name. 3635 */ 3636 DecodedInstruction *dInsn = &mir->dalvikInsn; 3637 const int lenOffset = offsetof(ArrayObject, length); 3638 const int maxC = dInsn->arg[0]; 3639 int regLength; 3640 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA]; 3641 RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC]; 3642 3643 /* regArray <- arrayRef */ 3644 rlArray = loadValue(cUnit, rlArray, kCoreReg); 3645 rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg); 3646 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0, 3647 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3648 3649 /* regLength <- len(arrayRef) */ 3650 regLength = dvmCompilerAllocTemp(cUnit); 3651 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength); 3652 3653 int delta = maxC; 3654 /* 3655 * If the loop end condition is ">=" instead of ">", then the largest value 3656 * of the index is "endCondition - 1". 3657 */ 3658 if (dInsn->arg[2] == OP_IF_GE) { 3659 delta--; 3660 } 3661 3662 if (delta) { 3663 int tReg = dvmCompilerAllocTemp(cUnit); 3664 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta); 3665 rlIdxEnd.lowReg = tReg; 3666 dvmCompilerFreeTemp(cUnit, tReg); 3667 } 3668 /* Punt if "regIdxEnd < len(Array)" is false */ 3669 genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0, 3670 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3671 } 3672 3673 /* 3674 * vA = arrayReg; 3675 * vB = idxReg; 3676 * vC = endConditionReg; 3677 * arg[0] = maxC 3678 * arg[1] = minC 3679 * arg[2] = loopBranchConditionCode 3680 */ 3681 static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir) 3682 { 3683 DecodedInstruction *dInsn = &mir->dalvikInsn; 3684 const int lenOffset = offsetof(ArrayObject, length); 3685 const int regLength = dvmCompilerAllocTemp(cUnit); 3686 const int maxC = dInsn->arg[0]; 3687 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA]; 3688 RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB]; 3689 3690 /* regArray <- arrayRef */ 3691 rlArray = loadValue(cUnit, rlArray, kCoreReg); 3692 rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg); 3693 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0, 3694 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3695 3696 /* regLength <- len(arrayRef) */ 3697 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength); 3698 3699 if (maxC) { 3700 int tReg = dvmCompilerAllocTemp(cUnit); 3701 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC); 3702 rlIdxInit.lowReg = tReg; 3703 dvmCompilerFreeTemp(cUnit, tReg); 3704 } 3705 3706 /* Punt if "regIdxInit < len(Array)" is false */ 3707 genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0, 3708 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3709 } 3710 3711 /* 3712 * vA = idxReg; 3713 * vB = minC; 3714 */ 3715 static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir) 3716 { 3717 DecodedInstruction *dInsn = &mir->dalvikInsn; 3718 const int minC = dInsn->vB; 3719 RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA]; 3720 3721 /* regIdx <- initial index value */ 3722 rlIdx = loadValue(cUnit, rlIdx, kCoreReg); 3723 3724 /* Punt if "regIdxInit + minC >= 0" is false */ 3725 genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0, 3726 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3727 } 3728 3729 /* 3730 * vC = this 3731 * 3732 * A predicted inlining target looks like the following, where instructions 3733 * between 0x4858de66 and 0x4858de72 are checking if the predicted class 3734 * matches "this", and the verificaion code is generated by this routine. 3735 * 3736 * (C) means the instruction is inlined from the callee, and (PI) means the 3737 * instruction is the predicted inlined invoke, whose corresponding 3738 * instructions are still generated to handle the mispredicted case. 3739 * 3740 * D/dalvikvm( 86): -------- kMirOpCheckInlinePrediction 3741 * D/dalvikvm( 86): 0x4858de66 (0002): ldr r0, [r5, #68] 3742 * D/dalvikvm( 86): 0x4858de68 (0004): ldr r1, [pc, #140] 3743 * D/dalvikvm( 86): 0x4858de6a (0006): cmp r0, #0 3744 * D/dalvikvm( 86): 0x4858de6c (0008): beq 0x4858deb2 3745 * D/dalvikvm( 86): 0x4858de6e (000a): ldr r2, [r0, #0] 3746 * D/dalvikvm( 86): 0x4858de70 (000c): cmp r1, r2 3747 * D/dalvikvm( 86): 0x4858de72 (000e): bne 0x4858de7a 3748 * D/dalvikvm( 86): -------- dalvik offset: 0x004c @ +iget-object-quick (C) 3749 * v4, v17, (#8) 3750 * D/dalvikvm( 86): 0x4858de74 (0010): ldr r3, [r0, #8] 3751 * D/dalvikvm( 86): 0x4858de76 (0012): str r3, [r5, #16] 3752 * D/dalvikvm( 86): -------- dalvik offset: 0x004c @ 3753 * +invoke-virtual-quick/range (PI) v17..v17 3754 * D/dalvikvm( 86): 0x4858de78 (0014): b 0x4858debc 3755 * D/dalvikvm( 86): 0x4858de7a (0016): add r4,r5,#68 3756 * D/dalvikvm( 86): -------- BARRIER 3757 * D/dalvikvm( 86): 0x4858de7e (001a): ldmia r4, <r0> 3758 * D/dalvikvm( 86): -------- BARRIER 3759 * D/dalvikvm( 86): 0x4858de80 (001c): sub r7,r5,#24 3760 * D/dalvikvm( 86): 0x4858de84 (0020): cmp r0, #0 3761 * D/dalvikvm( 86): 0x4858de86 (0022): beq 0x4858deb6 3762 * D/dalvikvm( 86): -------- BARRIER 3763 * D/dalvikvm( 86): 0x4858de88 (0024): stmia r7, <r0> 3764 * D/dalvikvm( 86): -------- BARRIER 3765 * D/dalvikvm( 86): 0x4858de8a (0026): ldr r4, [pc, #104] 3766 * D/dalvikvm( 86): 0x4858de8c (0028): add r1, pc, #28 3767 * D/dalvikvm( 86): 0x4858de8e (002a): add r2, pc, #56 3768 * D/dalvikvm( 86): 0x4858de90 (002c): blx_1 0x48589198 3769 * D/dalvikvm( 86): 0x4858de92 (002e): blx_2 see above 3770 * D/dalvikvm( 86): 0x4858de94 (0030): b 0x4858dec8 3771 * D/dalvikvm( 86): 0x4858de96 (0032): b 0x4858deb6 3772 * D/dalvikvm( 86): 0x4858de98 (0034): ldr r0, [r7, #72] 3773 * D/dalvikvm( 86): 0x4858de9a (0036): cmp r1, #0 3774 * D/dalvikvm( 86): 0x4858de9c (0038): bgt 0x4858dea4 3775 * D/dalvikvm( 86): 0x4858de9e (003a): ldr r7, [r6, #116] 3776 * D/dalvikvm( 86): 0x4858dea0 (003c): movs r1, r6 3777 * D/dalvikvm( 86): 0x4858dea2 (003e): blx r7 3778 * D/dalvikvm( 86): 0x4858dea4 (0040): add r1, pc, #4 3779 * D/dalvikvm( 86): 0x4858dea6 (0042): blx_1 0x485890a0 3780 * D/dalvikvm( 86): 0x4858dea8 (0044): blx_2 see above 3781 * D/dalvikvm( 86): 0x4858deaa (0046): b 0x4858deb6 3782 * D/dalvikvm( 86): 0x4858deac (0048): .align4 3783 * D/dalvikvm( 86): L0x004f: 3784 * D/dalvikvm( 86): -------- dalvik offset: 0x004f @ move-result-object (PI) 3785 * v4, (#0), (#0) 3786 * D/dalvikvm( 86): 0x4858deac (0048): ldr r4, [r6, #8] 3787 * D/dalvikvm( 86): 0x4858deae (004a): str r4, [r5, #16] 3788 * D/dalvikvm( 86): 0x4858deb0 (004c): b 0x4858debc 3789 * D/dalvikvm( 86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c 3790 * D/dalvikvm( 86): 0x4858deb2 (004e): ldr r0, [pc, #64] 3791 * D/dalvikvm( 86): 0x4858deb4 (0050): b 0x4858deb8 3792 * D/dalvikvm( 86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c 3793 * D/dalvikvm( 86): 0x4858deb6 (0052): ldr r0, [pc, #60] 3794 * D/dalvikvm( 86): Exception_Handling: 3795 * D/dalvikvm( 86): 0x4858deb8 (0054): ldr r1, [r6, #100] 3796 * D/dalvikvm( 86): 0x4858deba (0056): blx r1 3797 * D/dalvikvm( 86): 0x4858debc (0058): .align4 3798 * D/dalvikvm( 86): -------- chaining cell (hot): 0x0050 3799 * D/dalvikvm( 86): 0x4858debc (0058): b 0x4858dec0 3800 * D/dalvikvm( 86): 0x4858debe (005a): orrs r0, r0 3801 * D/dalvikvm( 86): 0x4858dec0 (005c): ldr r0, [r6, #112] 3802 * D/dalvikvm( 86): 0x4858dec2 (005e): blx r0 3803 * D/dalvikvm( 86): 0x4858dec4 (0060): data 0xefd4(61396) 3804 * D/dalvikvm( 86): 0x4858dec6 (0062): data 0x42be(17086) 3805 * D/dalvikvm( 86): 0x4858dec8 (0064): .align4 3806 * D/dalvikvm( 86): -------- chaining cell (predicted) 3807 * D/dalvikvm( 86): 0x4858dec8 (0064): data 0xe7fe(59390) 3808 * D/dalvikvm( 86): 0x4858deca (0066): data 0x0000(0) 3809 * D/dalvikvm( 86): 0x4858decc (0068): data 0x0000(0) 3810 * D/dalvikvm( 86): 0x4858dece (006a): data 0x0000(0) 3811 * : 3812 */ 3813 static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir) 3814 { 3815 CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo; 3816 RegLocation rlThis = cUnit->regLocation[mir->dalvikInsn.vC]; 3817 3818 rlThis = loadValue(cUnit, rlThis, kCoreReg); 3819 int regPredictedClass = dvmCompilerAllocTemp(cUnit); 3820 loadConstant(cUnit, regPredictedClass, (int) callsiteInfo->clazz); 3821 genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset, 3822 NULL);/* null object? */ 3823 int regActualClass = dvmCompilerAllocTemp(cUnit); 3824 loadWordDisp(cUnit, rlThis.lowReg, offsetof(Object, clazz), regActualClass); 3825 opRegReg(cUnit, kOpCmp, regPredictedClass, regActualClass); 3826 /* 3827 * Set the misPredBranchOver target so that it will be generated when the 3828 * code for the non-optimized invoke is generated. 3829 */ 3830 callsiteInfo->misPredBranchOver = (LIR *) opCondBranch(cUnit, kArmCondNe); 3831 } 3832 3833 /* Extended MIR instructions like PHI */ 3834 static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir) 3835 { 3836 int opOffset = mir->dalvikInsn.opCode - kMirOpFirst; 3837 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1, 3838 false); 3839 strcpy(msg, extendedMIROpNames[opOffset]); 3840 newLIR1(cUnit, kArmPseudoExtended, (int) msg); 3841 3842 switch (mir->dalvikInsn.opCode) { 3843 case kMirOpPhi: { 3844 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep); 3845 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString); 3846 break; 3847 } 3848 case kMirOpNullNRangeUpCheck: { 3849 genHoistedChecksForCountUpLoop(cUnit, mir); 3850 break; 3851 } 3852 case kMirOpNullNRangeDownCheck: { 3853 genHoistedChecksForCountDownLoop(cUnit, mir); 3854 break; 3855 } 3856 case kMirOpLowerBound: { 3857 genHoistedLowerBoundCheck(cUnit, mir); 3858 break; 3859 } 3860 case kMirOpPunt: { 3861 genUnconditionalBranch(cUnit, 3862 (ArmLIR *) cUnit->loopAnalysis->branchToPCR); 3863 break; 3864 } 3865 case kMirOpCheckInlinePrediction: { 3866 genValidationForPredictedInline(cUnit, mir); 3867 break; 3868 } 3869 default: 3870 break; 3871 } 3872 } 3873 3874 /* 3875 * Create a PC-reconstruction cell for the starting offset of this trace. 3876 * Since the PCR cell is placed near the end of the compiled code which is 3877 * usually out of range for a conditional branch, we put two branches (one 3878 * branch over to the loop body and one layover branch to the actual PCR) at the 3879 * end of the entry block. 3880 */ 3881 static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry, 3882 ArmLIR *bodyLabel) 3883 { 3884 /* Set up the place holder to reconstruct this Dalvik PC */ 3885 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true); 3886 pcrLabel->opCode = kArmPseudoPCReconstructionCell; 3887 pcrLabel->operands[0] = 3888 (int) (cUnit->method->insns + entry->startOffset); 3889 pcrLabel->operands[1] = entry->startOffset; 3890 /* Insert the place holder to the growable list */ 3891 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel); 3892 3893 /* 3894 * Next, create two branches - one branch over to the loop body and the 3895 * other branch to the PCR cell to punt. 3896 */ 3897 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true); 3898 branchToBody->opCode = kThumbBUncond; 3899 branchToBody->generic.target = (LIR *) bodyLabel; 3900 setupResourceMasks(branchToBody); 3901 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody; 3902 3903 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true); 3904 branchToPCR->opCode = kThumbBUncond; 3905 branchToPCR->generic.target = (LIR *) pcrLabel; 3906 setupResourceMasks(branchToPCR); 3907 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR; 3908 } 3909 3910 #if defined(WITH_SELF_VERIFICATION) 3911 static bool selfVerificationPuntOps(MIR *mir) 3912 { 3913 DecodedInstruction *decInsn = &mir->dalvikInsn; 3914 OpCode op = decInsn->opCode; 3915 3916 /* 3917 * All opcodes that can throw exceptions and use the 3918 * TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace 3919 * under self-verification mode. 3920 */ 3921 return (op == OP_MONITOR_ENTER || op == OP_MONITOR_EXIT || 3922 op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY || 3923 op == OP_CHECK_CAST || op == OP_MOVE_EXCEPTION || 3924 op == OP_FILL_ARRAY_DATA || op == OP_EXECUTE_INLINE || 3925 op == OP_EXECUTE_INLINE_RANGE); 3926 } 3927 #endif 3928 3929 void dvmCompilerMIR2LIR(CompilationUnit *cUnit) 3930 { 3931 /* Used to hold the labels of each block */ 3932 ArmLIR *labelList = 3933 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true); 3934 GrowableList chainingListByType[kChainingCellGap]; 3935 int i; 3936 3937 /* 3938 * Initialize various types chaining lists. 3939 */ 3940 for (i = 0; i < kChainingCellGap; i++) { 3941 dvmInitGrowableList(&chainingListByType[i], 2); 3942 } 3943 3944 BasicBlock **blockList = cUnit->blockList; 3945 3946 if (cUnit->executionCount) { 3947 /* 3948 * Reserve 6 bytes at the beginning of the trace 3949 * +----------------------------+ 3950 * | execution count (4 bytes) | 3951 * +----------------------------+ 3952 * | chain cell offset (2 bytes)| 3953 * +----------------------------+ 3954 * ...and then code to increment the execution 3955 * count: 3956 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0 3957 * sub r0, #10 @ back up to addr of executionCount 3958 * ldr r1, [r0] 3959 * add r1, #1 3960 * str r1, [r0] 3961 */ 3962 newLIR1(cUnit, kArm16BitData, 0); 3963 newLIR1(cUnit, kArm16BitData, 0); 3964 cUnit->chainCellOffsetLIR = 3965 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG); 3966 cUnit->headerSize = 6; 3967 /* Thumb instruction used directly here to ensure correct size */ 3968 newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc); 3969 newLIR2(cUnit, kThumbSubRI8, r0, 10); 3970 newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0); 3971 newLIR2(cUnit, kThumbAddRI8, r1, 1); 3972 newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0); 3973 } else { 3974 /* Just reserve 2 bytes for the chain cell offset */ 3975 cUnit->chainCellOffsetLIR = 3976 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG); 3977 cUnit->headerSize = 2; 3978 } 3979 3980 /* Handle the content in each basic block */ 3981 for (i = 0; i < cUnit->numBlocks; i++) { 3982 blockList[i]->visited = true; 3983 MIR *mir; 3984 3985 labelList[i].operands[0] = blockList[i]->startOffset; 3986 3987 if (blockList[i]->blockType >= kChainingCellGap) { 3988 if (blockList[i]->isFallThroughFromInvoke == true) { 3989 /* Align this block first since it is a return chaining cell */ 3990 newLIR0(cUnit, kArmPseudoPseudoAlign4); 3991 } 3992 /* 3993 * Append the label pseudo LIR first. Chaining cells will be handled 3994 * separately afterwards. 3995 */ 3996 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]); 3997 } 3998 3999 if (blockList[i]->blockType == kTraceEntryBlock) { 4000 labelList[i].opCode = kArmPseudoEntryBlock; 4001 if (blockList[i]->firstMIRInsn == NULL) { 4002 continue; 4003 } else { 4004 setupLoopEntryBlock(cUnit, blockList[i], 4005 &labelList[blockList[i]->fallThrough->id]); 4006 } 4007 } else if (blockList[i]->blockType == kTraceExitBlock) { 4008 labelList[i].opCode = kArmPseudoExitBlock; 4009 goto gen_fallthrough; 4010 } else if (blockList[i]->blockType == kDalvikByteCode) { 4011 labelList[i].opCode = kArmPseudoNormalBlockLabel; 4012 /* Reset the register state */ 4013 dvmCompilerResetRegPool(cUnit); 4014 dvmCompilerClobberAllRegs(cUnit); 4015 dvmCompilerResetNullCheck(cUnit); 4016 } else { 4017 switch (blockList[i]->blockType) { 4018 case kChainingCellNormal: 4019 labelList[i].opCode = kArmPseudoChainingCellNormal; 4020 /* handle the codegen later */ 4021 dvmInsertGrowableList( 4022 &chainingListByType[kChainingCellNormal], (void *) i); 4023 break; 4024 case kChainingCellInvokeSingleton: 4025 labelList[i].opCode = 4026 kArmPseudoChainingCellInvokeSingleton; 4027 labelList[i].operands[0] = 4028 (int) blockList[i]->containingMethod; 4029 /* handle the codegen later */ 4030 dvmInsertGrowableList( 4031 &chainingListByType[kChainingCellInvokeSingleton], 4032 (void *) i); 4033 break; 4034 case kChainingCellInvokePredicted: 4035 labelList[i].opCode = 4036 kArmPseudoChainingCellInvokePredicted; 4037 /* handle the codegen later */ 4038 dvmInsertGrowableList( 4039 &chainingListByType[kChainingCellInvokePredicted], 4040 (void *) i); 4041 break; 4042 case kChainingCellHot: 4043 labelList[i].opCode = 4044 kArmPseudoChainingCellHot; 4045 /* handle the codegen later */ 4046 dvmInsertGrowableList( 4047 &chainingListByType[kChainingCellHot], 4048 (void *) i); 4049 break; 4050 case kPCReconstruction: 4051 /* Make sure exception handling block is next */ 4052 labelList[i].opCode = 4053 kArmPseudoPCReconstructionBlockLabel; 4054 assert (i == cUnit->numBlocks - 2); 4055 handlePCReconstruction(cUnit, &labelList[i+1]); 4056 break; 4057 case kExceptionHandling: 4058 labelList[i].opCode = kArmPseudoEHBlockLabel; 4059 if (cUnit->pcReconstructionList.numUsed) { 4060 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, 4061 jitToInterpEntries.dvmJitToInterpPunt), 4062 r1); 4063 opReg(cUnit, kOpBlx, r1); 4064 } 4065 break; 4066 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING) 4067 case kChainingCellBackwardBranch: 4068 labelList[i].opCode = 4069 kArmPseudoChainingCellBackwardBranch; 4070 /* handle the codegen later */ 4071 dvmInsertGrowableList( 4072 &chainingListByType[kChainingCellBackwardBranch], 4073 (void *) i); 4074 break; 4075 #endif 4076 default: 4077 break; 4078 } 4079 continue; 4080 } 4081 4082 ArmLIR *headLIR = NULL; 4083 4084 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) { 4085 4086 dvmCompilerResetRegPool(cUnit); 4087 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) { 4088 dvmCompilerClobberAllRegs(cUnit); 4089 } 4090 4091 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) { 4092 dvmCompilerResetDefTracking(cUnit); 4093 } 4094 4095 if (mir->dalvikInsn.opCode >= kMirOpFirst) { 4096 handleExtendedMIR(cUnit, mir); 4097 continue; 4098 } 4099 4100 4101 OpCode dalvikOpCode = mir->dalvikInsn.opCode; 4102 InstructionFormat dalvikFormat = 4103 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode); 4104 char *note; 4105 if (mir->OptimizationFlags & MIR_INLINED) { 4106 note = " (I)"; 4107 } else if (mir->OptimizationFlags & MIR_INLINED_PRED) { 4108 note = " (PI)"; 4109 } else if (mir->OptimizationFlags & MIR_CALLEE) { 4110 note = " (C)"; 4111 } else { 4112 note = NULL; 4113 } 4114 4115 ArmLIR *boundaryLIR = 4116 newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary, 4117 mir->offset, 4118 (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn, 4119 note)); 4120 if (mir->ssaRep) { 4121 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep); 4122 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString); 4123 } 4124 4125 /* Remember the first LIR for this block */ 4126 if (headLIR == NULL) { 4127 headLIR = boundaryLIR; 4128 /* Set the first boundaryLIR as a scheduling barrier */ 4129 headLIR->defMask = ENCODE_ALL; 4130 } 4131 4132 bool notHandled; 4133 /* 4134 * Debugging: screen the opcode first to see if it is in the 4135 * do[-not]-compile list 4136 */ 4137 bool singleStepMe = SINGLE_STEP_OP(dalvikOpCode); 4138 #if defined(WITH_SELF_VERIFICATION) 4139 if (singleStepMe == false) { 4140 singleStepMe = selfVerificationPuntOps(mir); 4141 } 4142 #endif 4143 if (singleStepMe || cUnit->allSingleStep) { 4144 notHandled = false; 4145 genInterpSingleStep(cUnit, mir); 4146 } else { 4147 opcodeCoverage[dalvikOpCode]++; 4148 switch (dalvikFormat) { 4149 case kFmt10t: 4150 case kFmt20t: 4151 case kFmt30t: 4152 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit, 4153 mir, blockList[i], labelList); 4154 break; 4155 case kFmt10x: 4156 notHandled = handleFmt10x(cUnit, mir); 4157 break; 4158 case kFmt11n: 4159 case kFmt31i: 4160 notHandled = handleFmt11n_Fmt31i(cUnit, mir); 4161 break; 4162 case kFmt11x: 4163 notHandled = handleFmt11x(cUnit, mir); 4164 break; 4165 case kFmt12x: 4166 notHandled = handleFmt12x(cUnit, mir); 4167 break; 4168 case kFmt20bc: 4169 notHandled = handleFmt20bc(cUnit, mir); 4170 break; 4171 case kFmt21c: 4172 case kFmt31c: 4173 notHandled = handleFmt21c_Fmt31c(cUnit, mir); 4174 break; 4175 case kFmt21h: 4176 notHandled = handleFmt21h(cUnit, mir); 4177 break; 4178 case kFmt21s: 4179 notHandled = handleFmt21s(cUnit, mir); 4180 break; 4181 case kFmt21t: 4182 notHandled = handleFmt21t(cUnit, mir, blockList[i], 4183 labelList); 4184 break; 4185 case kFmt22b: 4186 case kFmt22s: 4187 notHandled = handleFmt22b_Fmt22s(cUnit, mir); 4188 break; 4189 case kFmt22c: 4190 notHandled = handleFmt22c(cUnit, mir); 4191 break; 4192 case kFmt22cs: 4193 notHandled = handleFmt22cs(cUnit, mir); 4194 break; 4195 case kFmt22t: 4196 notHandled = handleFmt22t(cUnit, mir, blockList[i], 4197 labelList); 4198 break; 4199 case kFmt22x: 4200 case kFmt32x: 4201 notHandled = handleFmt22x_Fmt32x(cUnit, mir); 4202 break; 4203 case kFmt23x: 4204 notHandled = handleFmt23x(cUnit, mir); 4205 break; 4206 case kFmt31t: 4207 notHandled = handleFmt31t(cUnit, mir); 4208 break; 4209 case kFmt3rc: 4210 case kFmt35c: 4211 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i], 4212 labelList); 4213 break; 4214 case kFmt3rms: 4215 case kFmt35ms: 4216 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i], 4217 labelList); 4218 break; 4219 case kFmt3inline: 4220 case kFmt3rinline: 4221 notHandled = handleExecuteInline(cUnit, mir); 4222 break; 4223 case kFmt51l: 4224 notHandled = handleFmt51l(cUnit, mir); 4225 break; 4226 default: 4227 notHandled = true; 4228 break; 4229 } 4230 } 4231 if (notHandled) { 4232 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n", 4233 mir->offset, 4234 dalvikOpCode, dexGetOpcodeName(dalvikOpCode), 4235 dalvikFormat); 4236 dvmCompilerAbort(cUnit); 4237 break; 4238 } 4239 } 4240 4241 if (blockList[i]->blockType == kTraceEntryBlock) { 4242 dvmCompilerAppendLIR(cUnit, 4243 (LIR *) cUnit->loopAnalysis->branchToBody); 4244 dvmCompilerAppendLIR(cUnit, 4245 (LIR *) cUnit->loopAnalysis->branchToPCR); 4246 } 4247 4248 if (headLIR) { 4249 /* 4250 * Eliminate redundant loads/stores and delay stores into later 4251 * slots 4252 */ 4253 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR, 4254 cUnit->lastLIRInsn); 4255 } 4256 4257 gen_fallthrough: 4258 /* 4259 * Check if the block is terminated due to trace length constraint - 4260 * insert an unconditional branch to the chaining cell. 4261 */ 4262 if (blockList[i]->needFallThroughBranch) { 4263 genUnconditionalBranch(cUnit, 4264 &labelList[blockList[i]->fallThrough->id]); 4265 } 4266 4267 } 4268 4269 /* Handle the chaining cells in predefined order */ 4270 for (i = 0; i < kChainingCellGap; i++) { 4271 size_t j; 4272 int *blockIdList = (int *) chainingListByType[i].elemList; 4273 4274 cUnit->numChainingCells[i] = chainingListByType[i].numUsed; 4275 4276 /* No chaining cells of this type */ 4277 if (cUnit->numChainingCells[i] == 0) 4278 continue; 4279 4280 /* Record the first LIR for a new type of chaining cell */ 4281 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]]; 4282 4283 for (j = 0; j < chainingListByType[i].numUsed; j++) { 4284 int blockId = blockIdList[j]; 4285 4286 /* Align this chaining cell first */ 4287 newLIR0(cUnit, kArmPseudoPseudoAlign4); 4288 4289 /* Insert the pseudo chaining instruction */ 4290 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]); 4291 4292 4293 switch (blockList[blockId]->blockType) { 4294 case kChainingCellNormal: 4295 handleNormalChainingCell(cUnit, 4296 blockList[blockId]->startOffset); 4297 break; 4298 case kChainingCellInvokeSingleton: 4299 handleInvokeSingletonChainingCell(cUnit, 4300 blockList[blockId]->containingMethod); 4301 break; 4302 case kChainingCellInvokePredicted: 4303 handleInvokePredictedChainingCell(cUnit); 4304 break; 4305 case kChainingCellHot: 4306 handleHotChainingCell(cUnit, 4307 blockList[blockId]->startOffset); 4308 break; 4309 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING) 4310 case kChainingCellBackwardBranch: 4311 handleBackwardBranchChainingCell(cUnit, 4312 blockList[blockId]->startOffset); 4313 break; 4314 #endif 4315 default: 4316 LOGE("Bad blocktype %d", blockList[blockId]->blockType); 4317 dvmCompilerAbort(cUnit); 4318 } 4319 } 4320 } 4321 4322 /* Mark the bottom of chaining cells */ 4323 cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kArmChainingCellBottom); 4324 4325 /* 4326 * Generate the branch to the dvmJitToInterpNoChain entry point at the end 4327 * of all chaining cells for the overflow cases. 4328 */ 4329 if (cUnit->switchOverflowPad) { 4330 loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad); 4331 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, 4332 jitToInterpEntries.dvmJitToInterpNoChain), r2); 4333 opRegReg(cUnit, kOpAdd, r1, r1); 4334 opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1); 4335 #if defined(WITH_JIT_TUNING) 4336 loadConstant(cUnit, r0, kSwitchOverflow); 4337 #endif 4338 opReg(cUnit, kOpBlx, r2); 4339 } 4340 4341 dvmCompilerApplyGlobalOptimizations(cUnit); 4342 4343 #if defined(WITH_SELF_VERIFICATION) 4344 selfVerificationBranchInsertPass(cUnit); 4345 #endif 4346 } 4347 4348 /* Accept the work and start compiling */ 4349 bool dvmCompilerDoWork(CompilerWorkOrder *work) 4350 { 4351 bool res; 4352 4353 if (gDvmJit.codeCacheFull) { 4354 return false; 4355 } 4356 4357 switch (work->kind) { 4358 case kWorkOrderTrace: 4359 /* Start compilation with maximally allowed trace length */ 4360 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result, 4361 work->bailPtr, 0 /* no hints */); 4362 break; 4363 case kWorkOrderTraceDebug: { 4364 bool oldPrintMe = gDvmJit.printMe; 4365 gDvmJit.printMe = true; 4366 /* Start compilation with maximally allowed trace length */ 4367 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result, 4368 work->bailPtr, 0 /* no hints */); 4369 gDvmJit.printMe = oldPrintMe; 4370 break; 4371 } 4372 default: 4373 res = false; 4374 LOGE("Jit: unknown work order type"); 4375 assert(0); // Bail if debug build, discard otherwise 4376 } 4377 return res; 4378 } 4379 4380 /* Architectural-specific debugging helpers go here */ 4381 void dvmCompilerArchDump(void) 4382 { 4383 /* Print compiled opcode in this VM instance */ 4384 int i, start, streak; 4385 char buf[1024]; 4386 4387 streak = i = 0; 4388 buf[0] = 0; 4389 while (opcodeCoverage[i] == 0 && i < 256) { 4390 i++; 4391 } 4392 if (i == 256) { 4393 return; 4394 } 4395 for (start = i++, streak = 1; i < 256; i++) { 4396 if (opcodeCoverage[i]) { 4397 streak++; 4398 } else { 4399 if (streak == 1) { 4400 sprintf(buf+strlen(buf), "%x,", start); 4401 } else { 4402 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1); 4403 } 4404 streak = 0; 4405 while (opcodeCoverage[i] == 0 && i < 256) { 4406 i++; 4407 } 4408 if (i < 256) { 4409 streak = 1; 4410 start = i; 4411 } 4412 } 4413 } 4414 if (streak) { 4415 if (streak == 1) { 4416 sprintf(buf+strlen(buf), "%x", start); 4417 } else { 4418 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1); 4419 } 4420 } 4421 if (strlen(buf)) { 4422 LOGD("dalvik.vm.jit.op = %s", buf); 4423 } 4424 } 4425 4426 /* Common initialization routine for an architecture family */ 4427 bool dvmCompilerArchInit() 4428 { 4429 int i; 4430 4431 for (i = 0; i < kArmLast; i++) { 4432 if (EncodingMap[i].opCode != i) { 4433 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d", 4434 EncodingMap[i].name, i, EncodingMap[i].opCode); 4435 dvmAbort(); // OK to dvmAbort - build error 4436 } 4437 } 4438 4439 return dvmCompilerArchVariantInit(); 4440 } 4441 4442 void *dvmCompilerGetInterpretTemplate() 4443 { 4444 return (void*) ((int)gDvmJit.codeCache + 4445 templateEntryOffsets[TEMPLATE_INTERPRET]); 4446 } 4447 4448 /* Needed by the Assembler */ 4449 void dvmCompilerSetupResourceMasks(ArmLIR *lir) 4450 { 4451 setupResourceMasks(lir); 4452 } 4453 4454 /* Needed by the ld/st optmizatons */ 4455 ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc) 4456 { 4457 return genRegCopyNoInsert(cUnit, rDest, rSrc); 4458 } 4459 4460 /* Needed by the register allocator */ 4461 ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) 4462 { 4463 return genRegCopy(cUnit, rDest, rSrc); 4464 } 4465 4466 /* Needed by the register allocator */ 4467 void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, 4468 int srcLo, int srcHi) 4469 { 4470 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi); 4471 } 4472 4473 void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase, 4474 int displacement, int rSrc, OpSize size) 4475 { 4476 storeBaseDisp(cUnit, rBase, displacement, rSrc, size); 4477 } 4478 4479 void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase, 4480 int displacement, int rSrcLo, int rSrcHi) 4481 { 4482 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi); 4483 } 4484