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