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 */
40 static 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 */
108 static 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
123 static 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
134 static bool handleMethodFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
135 {
136 return handleFmt11n_Fmt31i(cUnit, mir);
137 }
138
139 static 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
152 static bool handleMethodFmt12x(CompilationUnit *cUnit, MIR *mir)
153 {
154 return handleFmt12x(cUnit, mir);
155 }
156
157 static bool handleMethodFmt20bc(CompilationUnit *cUnit, MIR *mir)
158 {
159 return handleFmt20bc(cUnit, mir);
160 }
161
162 static bool handleMethodFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
163 {
164 return handleFmt21c_Fmt31c(cUnit, mir);
165 }
166
167 static bool handleMethodFmt21h(CompilationUnit *cUnit, MIR *mir)
168 {
169 return handleFmt21h(cUnit, mir);
170 }
171
172 static bool handleMethodFmt21s(CompilationUnit *cUnit, MIR *mir)
173 {
174 return handleFmt21s(cUnit, mir);
175 }
176
177 static bool handleMethodFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
178 ArmLIR *labelList)
179 {
180 return handleFmt21t(cUnit, mir, bb, labelList);
181 }
182
183 static bool handleMethodFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
184 {
185 return handleFmt22b_Fmt22s(cUnit, mir);
186 }
187
188 static bool handleMethodFmt22c(CompilationUnit *cUnit, MIR *mir)
189 {
190 return handleFmt22c(cUnit, mir);
191 }
192
193 static bool handleMethodFmt22cs(CompilationUnit *cUnit, MIR *mir)
194 {
195 return handleFmt22cs(cUnit, mir);
196 }
197
198 static bool handleMethodFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
199 ArmLIR *labelList)
200 {
201 return handleFmt22t(cUnit, mir, bb, labelList);
202 }
203
204 static bool handleMethodFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
205 {
206 return handleFmt22x_Fmt32x(cUnit, mir);
207 }
208
209 static bool handleMethodFmt23x(CompilationUnit *cUnit, MIR *mir)
210 {
211 return handleFmt23x(cUnit, mir);
212 }
213
214 static bool handleMethodFmt31t(CompilationUnit *cUnit, MIR *mir)
215 {
216 return handleFmt31t(cUnit, mir);
217 }
218
219 static bool handleMethodFmt35c_3rc(CompilationUnit *cUnit, MIR *mir,
220 BasicBlock *bb, ArmLIR *labelList)
221 {
222 return handleFmt35c_3rc(cUnit, mir, bb, labelList);
223 }
224
225 static bool handleMethodFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
226 BasicBlock *bb, ArmLIR *labelList)
227 {
228 return handleFmt35ms_3rms(cUnit, mir, bb, labelList);
229 }
230
231 static bool handleMethodExecuteInline(CompilationUnit *cUnit, MIR *mir)
232 {
233 return handleExecuteInline(cUnit, mir);
234 }
235
236 static bool handleMethodFmt51l(CompilationUnit *cUnit, MIR *mir)
237 {
238 return handleFmt51l(cUnit, mir);
239 }
240
241 /* Handle the content in each basic block */
242 static 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
428 void 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
dvmCompilerMethodMIR2LIR(CompilationUnit * cUnit)453 void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit) {
454 // Method-based JIT not supported for ARM.
455 }
456
457 #endif
458