MethodCodegenDriver.cpp revision 291c84f60853d30e1c0d79dd08c5e5164f588e26
1/* 2 * Copyright (C) 2011 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 * Rebuild the interpreter frame then punt to the interpreter to execute 19 * instruction at specified PC. 20 * 21 * Currently parameters are passed to the current frame, so we just need to 22 * grow the stack save area above it, fill certain fields in StackSaveArea and 23 * Thread that are skipped during whole-method invocation (specified below), 24 * then return to the interpreter. 25 * 26 * StackSaveArea: 27 * - prevSave 28 * - prevFrame 29 * - savedPc 30 * - returnAddr 31 * - method 32 * 33 * Thread: 34 * - method 35 * - methodClassDex 36 * - curFrame 37 */ 38static void genMethodInflateAndPunt(CompilationUnit *cUnit, MIR *mir, 39 BasicBlock *bb) 40{ 41 int oldStackSave = r0; 42 int newStackSave = r1; 43 int oldFP = r2; 44 int savedPC = r3; 45 int currentPC = r4PC; 46 int returnAddr = r7; 47 int method = r8; 48 int pDvmDex = r9; 49 50 /* 51 * TODO: check whether to raise the stack overflow exception when growing 52 * the stack save area. 53 */ 54 55 /* Send everything to home location */ 56 dvmCompilerFlushAllRegs(cUnit); 57 58 /* oldStackSave = r5FP + sizeof(current frame) */ 59 opRegRegImm(cUnit, kOpAdd, oldStackSave, r5FP, 60 cUnit->method->registersSize * 4); 61 /* oldFP = oldStackSave + sizeof(stackSaveArea) */ 62 opRegRegImm(cUnit, kOpAdd, oldFP, oldStackSave, sizeof(StackSaveArea)); 63 /* newStackSave = r5FP - sizeof(StackSaveArea) */ 64 opRegRegImm(cUnit, kOpSub, newStackSave, r5FP, sizeof(StackSaveArea)); 65 66 loadWordDisp(cUnit, r13sp, 0, savedPC); 67 loadConstant(cUnit, currentPC, (int) (cUnit->method->insns + mir->offset)); 68 loadConstant(cUnit, method, (int) cUnit->method); 69 loadConstant(cUnit, pDvmDex, (int) cUnit->method->clazz->pDvmDex); 70#ifdef EASY_GDB 71 /* newStackSave->prevSave = oldStackSave */ 72 storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevSave), 73 oldStackSave); 74#endif 75 /* newStackSave->prevSave = oldStackSave */ 76 storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevFrame), 77 oldFP); 78 /* newStackSave->savedPc = savedPC */ 79 storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, savedPc), 80 savedPC); 81 /* return address */ 82 loadConstant(cUnit, returnAddr, 0); 83 storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, returnAddr), 84 returnAddr); 85 /* newStackSave->method = method */ 86 storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, method), method); 87 /* thread->method = method */ 88 storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, method), method); 89 /* thread->interpSave.curFrame = current FP */ 90 storeWordDisp(cUnit, r6SELF, offsetof(Thread, interpSave.curFrame), r5FP); 91 /* thread->methodClassDex = pDvmDex */ 92 storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, methodClassDex), 93 pDvmDex); 94 /* Restore the stack pointer */ 95 opRegImm(cUnit, kOpAdd, r13sp, 16); 96 genPuntToInterp(cUnit, mir->offset); 97} 98 99/* 100 * The following are the first-level codegen routines that analyze the format 101 * of each bytecode then either dispatch special purpose codegen routines 102 * or produce corresponding Thumb instructions directly. 103 * 104 * TODO - most them are just pass-through to the trace-based versions for now 105 */ 106static bool handleMethodFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir, 107 BasicBlock *bb, ArmLIR *labelList) 108{ 109 /* backward branch? */ 110 bool backwardBranch = (bb->taken->startOffset <= mir->offset); 111 112 if (backwardBranch && gDvmJit.genSuspendPoll) { 113 genSuspendPoll(cUnit, mir); 114 } 115 116 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */ 117 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]); 118 return false; 119} 120 121static bool handleMethodFmt10x(CompilationUnit *cUnit, MIR *mir) 122{ 123 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 124 switch (dalvikOpcode) { 125 case OP_RETURN_VOID: 126 return false; 127 default: 128 return handleFmt10x(cUnit, mir); 129 } 130} 131 132static bool handleMethodFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir) 133{ 134 return handleFmt11n_Fmt31i(cUnit, mir); 135} 136 137static bool handleMethodFmt11x(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 138 ArmLIR *labelList) 139{ 140 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 141 switch (dalvikOpcode) { 142 case OP_THROW: 143 genMethodInflateAndPunt(cUnit, mir, bb); 144 return false; 145 default: 146 return handleFmt11x(cUnit, mir); 147 } 148} 149 150static bool handleMethodFmt12x(CompilationUnit *cUnit, MIR *mir) 151{ 152 return handleFmt12x(cUnit, mir); 153} 154 155static bool handleMethodFmt20bc_Fmt40sc(CompilationUnit *cUnit, MIR *mir) 156{ 157 return handleFmt20bc_Fmt40sc(cUnit, mir); 158} 159 160static bool handleMethodFmt21c_Fmt31c_Fmt41c(CompilationUnit *cUnit, MIR *mir) 161{ 162 return handleFmt21c_Fmt31c_Fmt41c(cUnit, mir); 163} 164 165static bool handleMethodFmt21h(CompilationUnit *cUnit, MIR *mir) 166{ 167 return handleFmt21h(cUnit, mir); 168} 169 170static bool handleMethodFmt21s(CompilationUnit *cUnit, MIR *mir) 171{ 172 return handleFmt21s(cUnit, mir); 173} 174 175static bool handleMethodFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 176 ArmLIR *labelList) 177{ 178 return handleFmt21t(cUnit, mir, bb, labelList); 179} 180 181static bool handleMethodFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir) 182{ 183 return handleFmt22b_Fmt22s(cUnit, mir); 184} 185 186static bool handleMethodFmt22c_Fmt52c(CompilationUnit *cUnit, MIR *mir) 187{ 188 return handleFmt22c_Fmt52c(cUnit, mir); 189} 190 191static bool handleMethodFmt22cs(CompilationUnit *cUnit, MIR *mir) 192{ 193 return handleFmt22cs(cUnit, mir); 194} 195 196static bool handleMethodFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 197 ArmLIR *labelList) 198{ 199 return handleFmt22t(cUnit, mir, bb, labelList); 200} 201 202static bool handleMethodFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir) 203{ 204 return handleFmt22x_Fmt32x(cUnit, mir); 205} 206 207static bool handleMethodFmt23x(CompilationUnit *cUnit, MIR *mir) 208{ 209 return handleFmt23x(cUnit, mir); 210} 211 212static bool handleMethodFmt31t(CompilationUnit *cUnit, MIR *mir) 213{ 214 return handleFmt31t(cUnit, mir); 215} 216 217static bool handleMethodFmt35c_3rc_5rc(CompilationUnit *cUnit, MIR *mir, 218 BasicBlock *bb, ArmLIR *labelList) 219{ 220 return handleFmt35c_3rc_5rc(cUnit, mir, bb, labelList); 221} 222 223static bool handleMethodFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir, 224 BasicBlock *bb, ArmLIR *labelList) 225{ 226 return handleFmt35ms_3rms(cUnit, mir, bb, labelList); 227} 228 229static bool handleMethodExecuteInline(CompilationUnit *cUnit, MIR *mir) 230{ 231 return handleExecuteInline(cUnit, mir); 232} 233 234static bool handleMethodFmt51l(CompilationUnit *cUnit, MIR *mir) 235{ 236 return handleFmt51l(cUnit, mir); 237} 238 239/* Handle the content in each basic block */ 240static bool methodBlockCodeGen(CompilationUnit *cUnit, BasicBlock *bb) 241{ 242 MIR *mir; 243 ArmLIR *labelList = (ArmLIR *) cUnit->blockLabelList; 244 int blockId = bb->id; 245 246 cUnit->curBlock = bb; 247 labelList[blockId].operands[0] = bb->startOffset; 248 249 /* Insert the block label */ 250 labelList[blockId].opcode = kArmPseudoNormalBlockLabel; 251 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]); 252 253 dvmCompilerClobberAllRegs(cUnit); 254 dvmCompilerResetNullCheck(cUnit); 255 256 ArmLIR *headLIR = NULL; 257 258 if (bb->blockType == kEntryBlock) { 259 /* r0 = callsitePC */ 260 opImm(cUnit, kOpPush, (1 << r0 | 1 << r1 | 1 << r5FP | 1 << r14lr)); 261 opRegImm(cUnit, kOpSub, r5FP, 262 sizeof(StackSaveArea) + cUnit->method->registersSize * 4); 263 264 } else if (bb->blockType == kExitBlock) { 265 /* No need to pop r0 and r1 */ 266 opRegImm(cUnit, kOpAdd, r13sp, 8); 267 opImm(cUnit, kOpPop, (1 << r5FP | 1 << r15pc)); 268 } 269 270 for (mir = bb->firstMIRInsn; mir; mir = mir->next) { 271 272 dvmCompilerResetRegPool(cUnit); 273 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) { 274 dvmCompilerClobberAllRegs(cUnit); 275 } 276 277 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) { 278 dvmCompilerResetDefTracking(cUnit); 279 } 280 281 Opcode dalvikOpcode = mir->dalvikInsn.opcode; 282 InstructionFormat dalvikFormat = 283 dexGetFormatFromOpcode(dalvikOpcode); 284 285 ArmLIR *boundaryLIR; 286 287 /* 288 * Don't generate the boundary LIR unless we are debugging this 289 * trace or we need a scheduling barrier. 290 */ 291 if (headLIR == NULL || cUnit->printMe == true) { 292 boundaryLIR = 293 newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary, 294 mir->offset, 295 (int) dvmCompilerGetDalvikDisassembly( 296 &mir->dalvikInsn, "")); 297 /* Remember the first LIR for this block */ 298 if (headLIR == NULL) { 299 headLIR = boundaryLIR; 300 /* Set the first boundaryLIR as a scheduling barrier */ 301 headLIR->defMask = ENCODE_ALL; 302 } 303 } 304 305 /* Don't generate the SSA annotation unless verbose mode is on */ 306 if (cUnit->printMe && mir->ssaRep) { 307 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep); 308 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString); 309 } 310 311 bool notHandled; 312 switch (dalvikFormat) { 313 case kFmt10t: 314 case kFmt20t: 315 case kFmt30t: 316 notHandled = handleMethodFmt10t_Fmt20t_Fmt30t(cUnit, mir, bb, 317 labelList); 318 break; 319 case kFmt10x: 320 notHandled = handleMethodFmt10x(cUnit, mir); 321 break; 322 case kFmt11n: 323 case kFmt31i: 324 notHandled = handleMethodFmt11n_Fmt31i(cUnit, mir); 325 break; 326 case kFmt11x: 327 notHandled = handleMethodFmt11x(cUnit, mir, bb, labelList); 328 break; 329 case kFmt12x: 330 notHandled = handleMethodFmt12x(cUnit, mir); 331 break; 332 case kFmt20bc: 333 case kFmt40sc: 334 notHandled = handleMethodFmt20bc_Fmt40sc(cUnit, mir); 335 break; 336 case kFmt21c: 337 case kFmt31c: 338 case kFmt41c: 339 notHandled = handleMethodFmt21c_Fmt31c_Fmt41c(cUnit, mir); 340 break; 341 case kFmt21h: 342 notHandled = handleMethodFmt21h(cUnit, mir); 343 break; 344 case kFmt21s: 345 notHandled = handleMethodFmt21s(cUnit, mir); 346 break; 347 case kFmt21t: 348 notHandled = handleMethodFmt21t(cUnit, mir, bb, labelList); 349 break; 350 case kFmt22b: 351 case kFmt22s: 352 notHandled = handleMethodFmt22b_Fmt22s(cUnit, mir); 353 break; 354 case kFmt22c: 355 case kFmt52c: 356 notHandled = handleMethodFmt22c_Fmt52c(cUnit, mir); 357 break; 358 case kFmt22cs: 359 notHandled = handleMethodFmt22cs(cUnit, mir); 360 break; 361 case kFmt22t: 362 notHandled = handleMethodFmt22t(cUnit, mir, bb, labelList); 363 break; 364 case kFmt22x: 365 case kFmt32x: 366 notHandled = handleMethodFmt22x_Fmt32x(cUnit, mir); 367 break; 368 case kFmt23x: 369 notHandled = handleMethodFmt23x(cUnit, mir); 370 break; 371 case kFmt31t: 372 notHandled = handleMethodFmt31t(cUnit, mir); 373 break; 374 case kFmt3rc: 375 case kFmt35c: 376 case kFmt5rc: 377 notHandled = handleMethodFmt35c_3rc_5rc(cUnit, mir, bb, 378 labelList); 379 break; 380 case kFmt3rms: 381 case kFmt35ms: 382 notHandled = handleMethodFmt35ms_3rms(cUnit, mir, bb, 383 labelList); 384 break; 385 case kFmt35mi: 386 case kFmt3rmi: 387 notHandled = handleMethodExecuteInline(cUnit, mir); 388 break; 389 case kFmt51l: 390 notHandled = handleMethodFmt51l(cUnit, mir); 391 break; 392 default: 393 notHandled = true; 394 break; 395 } 396 397 /* FIXME - to be implemented */ 398 if (notHandled == true && dalvikOpcode >= kNumPackedOpcodes) { 399 notHandled = false; 400 } 401 402 if (notHandled) { 403 LOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled", 404 mir->offset, 405 dalvikOpcode, dexGetOpcodeName(dalvikOpcode), 406 dalvikFormat); 407 dvmCompilerAbort(cUnit); 408 break; 409 } 410 } 411 412 if (headLIR) { 413 /* 414 * Eliminate redundant loads/stores and delay stores into later 415 * slots 416 */ 417 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR, 418 cUnit->lastLIRInsn); 419 420 /* 421 * Generate an unconditional branch to the fallthrough block. 422 */ 423 if (bb->fallThrough) { 424 genUnconditionalBranch(cUnit, 425 &labelList[bb->fallThrough->id]); 426 } 427 } 428 return false; 429} 430 431void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit) 432{ 433 // FIXME - enable method compilation for selected routines here 434 if (strcmp(cUnit->method->name, "add")) return; 435 436 /* Used to hold the labels of each block */ 437 cUnit->blockLabelList = 438 (void *) dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true); 439 440 dvmCompilerDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen, 441 kPreOrderDFSTraversal, 442 false /* isIterative */); 443 444 dvmCompilerApplyGlobalOptimizations(cUnit); 445 446 // FIXME - temporarily enable verbose printing for all methods 447 cUnit->printMe = true; 448 449#if defined(WITH_SELF_VERIFICATION) 450 selfVerificationBranchInsertPass(cUnit); 451#endif 452} 453