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