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 */ 38 static 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 */ 106 static 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 121 static 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 132 static bool handleMethodFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir) 133 { 134 return handleFmt11n_Fmt31i(cUnit, mir); 135 } 136 137 static 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 150 static bool handleMethodFmt12x(CompilationUnit *cUnit, MIR *mir) 151 { 152 return handleFmt12x(cUnit, mir); 153 } 154 155 static bool handleMethodFmt20bc(CompilationUnit *cUnit, MIR *mir) 156 { 157 return handleFmt20bc(cUnit, mir); 158 } 159 160 static bool handleMethodFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir) 161 { 162 return handleFmt21c_Fmt31c(cUnit, mir); 163 } 164 165 static bool handleMethodFmt21h(CompilationUnit *cUnit, MIR *mir) 166 { 167 return handleFmt21h(cUnit, mir); 168 } 169 170 static bool handleMethodFmt21s(CompilationUnit *cUnit, MIR *mir) 171 { 172 return handleFmt21s(cUnit, mir); 173 } 174 175 static bool handleMethodFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 176 ArmLIR *labelList) 177 { 178 return handleFmt21t(cUnit, mir, bb, labelList); 179 } 180 181 static bool handleMethodFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir) 182 { 183 return handleFmt22b_Fmt22s(cUnit, mir); 184 } 185 186 static bool handleMethodFmt22c(CompilationUnit *cUnit, MIR *mir) 187 { 188 return handleFmt22c(cUnit, mir); 189 } 190 191 static bool handleMethodFmt22cs(CompilationUnit *cUnit, MIR *mir) 192 { 193 return handleFmt22cs(cUnit, mir); 194 } 195 196 static bool handleMethodFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, 197 ArmLIR *labelList) 198 { 199 return handleFmt22t(cUnit, mir, bb, labelList); 200 } 201 202 static bool handleMethodFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir) 203 { 204 return handleFmt22x_Fmt32x(cUnit, mir); 205 } 206 207 static bool handleMethodFmt23x(CompilationUnit *cUnit, MIR *mir) 208 { 209 return handleFmt23x(cUnit, mir); 210 } 211 212 static bool handleMethodFmt31t(CompilationUnit *cUnit, MIR *mir) 213 { 214 return handleFmt31t(cUnit, mir); 215 } 216 217 static bool handleMethodFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, 218 BasicBlock *bb, ArmLIR *labelList) 219 { 220 return handleFmt35c_3rc(cUnit, mir, bb, labelList); 221 } 222 223 static bool handleMethodFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir, 224 BasicBlock *bb, ArmLIR *labelList) 225 { 226 return handleFmt35ms_3rms(cUnit, mir, bb, labelList); 227 } 228 229 static bool handleMethodExecuteInline(CompilationUnit *cUnit, MIR *mir) 230 { 231 return handleExecuteInline(cUnit, mir); 232 } 233 234 static bool handleMethodFmt51l(CompilationUnit *cUnit, MIR *mir) 235 { 236 return handleFmt51l(cUnit, mir); 237 } 238 239 /* Handle the content in each basic block */ 240 static 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 notHandled = handleMethodFmt20bc(cUnit, mir); 334 break; 335 case kFmt21c: 336 case kFmt31c: 337 notHandled = handleMethodFmt21c_Fmt31c(cUnit, mir); 338 break; 339 case kFmt21h: 340 notHandled = handleMethodFmt21h(cUnit, mir); 341 break; 342 case kFmt21s: 343 notHandled = handleMethodFmt21s(cUnit, mir); 344 break; 345 case kFmt21t: 346 notHandled = handleMethodFmt21t(cUnit, mir, bb, labelList); 347 break; 348 case kFmt22b: 349 case kFmt22s: 350 notHandled = handleMethodFmt22b_Fmt22s(cUnit, mir); 351 break; 352 case kFmt22c: 353 notHandled = handleMethodFmt22c(cUnit, mir); 354 break; 355 case kFmt22cs: 356 notHandled = handleMethodFmt22cs(cUnit, mir); 357 break; 358 case kFmt22t: 359 notHandled = handleMethodFmt22t(cUnit, mir, bb, labelList); 360 break; 361 case kFmt22x: 362 case kFmt32x: 363 notHandled = handleMethodFmt22x_Fmt32x(cUnit, mir); 364 break; 365 case kFmt23x: 366 notHandled = handleMethodFmt23x(cUnit, mir); 367 break; 368 case kFmt31t: 369 notHandled = handleMethodFmt31t(cUnit, mir); 370 break; 371 case kFmt3rc: 372 case kFmt35c: 373 notHandled = handleMethodFmt35c_3rc(cUnit, mir, bb, labelList); 374 break; 375 case kFmt3rms: 376 case kFmt35ms: 377 notHandled = handleMethodFmt35ms_3rms(cUnit, mir, bb, 378 labelList); 379 break; 380 case kFmt35mi: 381 case kFmt3rmi: 382 notHandled = handleMethodExecuteInline(cUnit, mir); 383 break; 384 case kFmt51l: 385 notHandled = handleMethodFmt51l(cUnit, mir); 386 break; 387 default: 388 notHandled = true; 389 break; 390 } 391 392 /* FIXME - to be implemented */ 393 if (notHandled == true && dalvikOpcode >= kNumPackedOpcodes) { 394 notHandled = false; 395 } 396 397 if (notHandled) { 398 ALOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled", 399 mir->offset, 400 dalvikOpcode, dexGetOpcodeName(dalvikOpcode), 401 dalvikFormat); 402 dvmCompilerAbort(cUnit); 403 break; 404 } 405 } 406 407 if (headLIR) { 408 /* 409 * Eliminate redundant loads/stores and delay stores into later 410 * slots 411 */ 412 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR, 413 cUnit->lastLIRInsn); 414 415 /* 416 * Generate an unconditional branch to the fallthrough block. 417 */ 418 if (bb->fallThrough) { 419 genUnconditionalBranch(cUnit, 420 &labelList[bb->fallThrough->id]); 421 } 422 } 423 return false; 424 } 425 426 void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit) 427 { 428 // FIXME - enable method compilation for selected routines here 429 if (strcmp(cUnit->method->name, "add")) return; 430 431 /* Used to hold the labels of each block */ 432 cUnit->blockLabelList = 433 (void *) dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true); 434 435 dvmCompilerDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen, 436 kPreOrderDFSTraversal, 437 false /* isIterative */); 438 439 dvmCompilerApplyGlobalOptimizations(cUnit); 440 441 // FIXME - temporarily enable verbose printing for all methods 442 cUnit->printMe = true; 443 444 #if defined(WITH_SELF_VERIFICATION) 445 selfVerificationBranchInsertPass(cUnit); 446 #endif 447 } 448