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