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