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