CodegenDriver.cpp revision 291c84f60853d30e1c0d79dd08c5e5164f588e26
1/*
2 * Copyright (C) 2009 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 * This file contains codegen and support common to all supported
19 * ARM variants.  It is included by:
20 *
21 *        Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
25 */
26
27/*
28 * Mark garbage collection card. Skip if the value we're storing is null.
29 */
30static void markCard(CompilationUnit *cUnit, int valReg, int tgtAddrReg)
31{
32    int regCardBase = dvmCompilerAllocTemp(cUnit);
33    int regCardNo = dvmCompilerAllocTemp(cUnit);
34    ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
35    loadWordDisp(cUnit, r6SELF, offsetof(Thread, cardTable),
36                 regCardBase);
37    opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
38    storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
39                     kUnsignedByte);
40    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
41    target->defMask = ENCODE_ALL;
42    branchOver->generic.target = (LIR *)target;
43    dvmCompilerFreeTemp(cUnit, regCardBase);
44    dvmCompilerFreeTemp(cUnit, regCardNo);
45}
46
47static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
48                                     int srcSize, int tgtSize)
49{
50    /*
51     * Don't optimize the register usage since it calls out to template
52     * functions
53     */
54    RegLocation rlSrc;
55    RegLocation rlDest;
56    dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
57    if (srcSize == 1) {
58        rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
59        loadValueDirectFixed(cUnit, rlSrc, r0);
60    } else {
61        rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
62        loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
63    }
64    LOAD_FUNC_ADDR(cUnit, r2, (int)funct);
65    opReg(cUnit, kOpBlx, r2);
66    dvmCompilerClobberCallRegs(cUnit);
67    if (tgtSize == 1) {
68        RegLocation rlResult;
69        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
70        rlResult = dvmCompilerGetReturn(cUnit);
71        storeValue(cUnit, rlDest, rlResult);
72    } else {
73        RegLocation rlResult;
74        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
75        rlResult = dvmCompilerGetReturnWide(cUnit);
76        storeValueWide(cUnit, rlDest, rlResult);
77    }
78    return false;
79}
80
81static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
82                                    RegLocation rlDest, RegLocation rlSrc1,
83                                    RegLocation rlSrc2)
84{
85    RegLocation rlResult;
86    void* funct;
87
88    switch (mir->dalvikInsn.opcode) {
89        case OP_ADD_FLOAT_2ADDR:
90        case OP_ADD_FLOAT:
91            funct = (void*) __aeabi_fadd;
92            break;
93        case OP_SUB_FLOAT_2ADDR:
94        case OP_SUB_FLOAT:
95            funct = (void*) __aeabi_fsub;
96            break;
97        case OP_DIV_FLOAT_2ADDR:
98        case OP_DIV_FLOAT:
99            funct = (void*) __aeabi_fdiv;
100            break;
101        case OP_MUL_FLOAT_2ADDR:
102        case OP_MUL_FLOAT:
103            funct = (void*) __aeabi_fmul;
104            break;
105        case OP_REM_FLOAT_2ADDR:
106        case OP_REM_FLOAT:
107            funct = (void*) fmodf;
108            break;
109        case OP_NEG_FLOAT: {
110            genNegFloat(cUnit, rlDest, rlSrc1);
111            return false;
112        }
113        default:
114            return true;
115    }
116    dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
117    loadValueDirectFixed(cUnit, rlSrc1, r0);
118    loadValueDirectFixed(cUnit, rlSrc2, r1);
119    LOAD_FUNC_ADDR(cUnit, r2, (int)funct);
120    opReg(cUnit, kOpBlx, r2);
121    dvmCompilerClobberCallRegs(cUnit);
122    rlResult = dvmCompilerGetReturn(cUnit);
123    storeValue(cUnit, rlDest, rlResult);
124    return false;
125}
126
127static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
128                                     RegLocation rlDest, RegLocation rlSrc1,
129                                     RegLocation rlSrc2)
130{
131    RegLocation rlResult;
132    void* funct;
133
134    switch (mir->dalvikInsn.opcode) {
135        case OP_ADD_DOUBLE_2ADDR:
136        case OP_ADD_DOUBLE:
137            funct = (void*) __aeabi_dadd;
138            break;
139        case OP_SUB_DOUBLE_2ADDR:
140        case OP_SUB_DOUBLE:
141            funct = (void*) __aeabi_dsub;
142            break;
143        case OP_DIV_DOUBLE_2ADDR:
144        case OP_DIV_DOUBLE:
145            funct = (void*) __aeabi_ddiv;
146            break;
147        case OP_MUL_DOUBLE_2ADDR:
148        case OP_MUL_DOUBLE:
149            funct = (void*) __aeabi_dmul;
150            break;
151        case OP_REM_DOUBLE_2ADDR:
152        case OP_REM_DOUBLE:
153            funct = (void*) fmod;
154            break;
155        case OP_NEG_DOUBLE: {
156            genNegDouble(cUnit, rlDest, rlSrc1);
157            return false;
158        }
159        default:
160            return true;
161    }
162    dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
163    LOAD_FUNC_ADDR(cUnit, r14lr, (int)funct);
164    loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
165    loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
166    opReg(cUnit, kOpBlx, r14lr);
167    dvmCompilerClobberCallRegs(cUnit);
168    rlResult = dvmCompilerGetReturnWide(cUnit);
169    storeValueWide(cUnit, rlDest, rlResult);
170#if defined(WITH_SELF_VERIFICATION)
171    cUnit->usesLinkRegister = true;
172#endif
173    return false;
174}
175
176static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
177{
178    Opcode opcode = mir->dalvikInsn.opcode;
179
180    switch (opcode) {
181        case OP_INT_TO_FLOAT:
182            return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
183        case OP_FLOAT_TO_INT:
184            return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
185        case OP_DOUBLE_TO_FLOAT:
186            return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
187        case OP_FLOAT_TO_DOUBLE:
188            return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
189        case OP_INT_TO_DOUBLE:
190            return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
191        case OP_DOUBLE_TO_INT:
192            return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
193        case OP_FLOAT_TO_LONG:
194            return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
195        case OP_LONG_TO_FLOAT:
196            return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
197        case OP_DOUBLE_TO_LONG:
198            return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
199        case OP_LONG_TO_DOUBLE:
200            return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
201        default:
202            return true;
203    }
204    return false;
205}
206
207#if defined(WITH_SELF_VERIFICATION)
208static void selfVerificationBranchInsert(LIR *currentLIR, ArmOpcode opcode,
209                          int dest, int src1)
210{
211     ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
212     insn->opcode = opcode;
213     insn->operands[0] = dest;
214     insn->operands[1] = src1;
215     setupResourceMasks(insn);
216     dvmCompilerInsertLIRBefore(currentLIR, (LIR *) insn);
217}
218
219/*
220 * Example where r14 (LR) is preserved around a heap access under
221 * self-verification mode in Thumb2:
222 *
223 * D/dalvikvm( 1538): 0x59414c5e (0026): ldr     r14, [r15pc, #220] <-hoisted
224 * D/dalvikvm( 1538): 0x59414c62 (002a): mla     r4, r0, r8, r4
225 * D/dalvikvm( 1538): 0x59414c66 (002e): adds    r3, r4, r3
226 * D/dalvikvm( 1538): 0x59414c6a (0032): push    <r5, r14>    ---+
227 * D/dalvikvm( 1538): 0x59414c6c (0034): blx_1   0x5940f494      |
228 * D/dalvikvm( 1538): 0x59414c6e (0036): blx_2   see above       <-MEM_OP_DECODE
229 * D/dalvikvm( 1538): 0x59414c70 (0038): ldr     r10, [r9, #0]   |
230 * D/dalvikvm( 1538): 0x59414c74 (003c): pop     <r5, r14>    ---+
231 * D/dalvikvm( 1538): 0x59414c78 (0040): mov     r11, r10
232 * D/dalvikvm( 1538): 0x59414c7a (0042): asr     r12, r11, #31
233 * D/dalvikvm( 1538): 0x59414c7e (0046): movs    r0, r2
234 * D/dalvikvm( 1538): 0x59414c80 (0048): movs    r1, r3
235 * D/dalvikvm( 1538): 0x59414c82 (004a): str     r2, [r5, #16]
236 * D/dalvikvm( 1538): 0x59414c84 (004c): mov     r2, r11
237 * D/dalvikvm( 1538): 0x59414c86 (004e): str     r3, [r5, #20]
238 * D/dalvikvm( 1538): 0x59414c88 (0050): mov     r3, r12
239 * D/dalvikvm( 1538): 0x59414c8a (0052): str     r11, [r5, #24]
240 * D/dalvikvm( 1538): 0x59414c8e (0056): str     r12, [r5, #28]
241 * D/dalvikvm( 1538): 0x59414c92 (005a): blx     r14             <-use of LR
242 *
243 */
244static void selfVerificationBranchInsertPass(CompilationUnit *cUnit)
245{
246    ArmLIR *thisLIR;
247    TemplateOpcode opcode = TEMPLATE_MEM_OP_DECODE;
248
249    for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn;
250         thisLIR != (ArmLIR *) cUnit->lastLIRInsn;
251         thisLIR = NEXT_LIR(thisLIR)) {
252        if (!thisLIR->flags.isNop && thisLIR->flags.insertWrapper) {
253            /*
254             * Push r5(FP) and r14(LR) onto stack. We need to make sure that
255             * SP is 8-byte aligned, and we use r5 as a temp to restore LR
256             * for Thumb-only target since LR cannot be directly accessed in
257             * Thumb mode. Another reason to choose r5 here is it is the Dalvik
258             * frame pointer and cannot be the target of the emulated heap
259             * load.
260             */
261            if (cUnit->usesLinkRegister) {
262                genSelfVerificationPreBranch(cUnit, thisLIR);
263            }
264
265            /* Branch to mem op decode template */
266            selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx1,
267                       (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
268                       (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
269            selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx2,
270                       (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
271                       (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
272
273            /* Restore LR */
274            if (cUnit->usesLinkRegister) {
275                genSelfVerificationPostBranch(cUnit, thisLIR);
276            }
277        }
278    }
279}
280#endif
281
282/* Generate conditional branch instructions */
283static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
284                                    ArmConditionCode cond,
285                                    ArmLIR *target)
286{
287    ArmLIR *branch = opCondBranch(cUnit, cond);
288    branch->generic.target = (LIR *) target;
289    return branch;
290}
291
292/* Generate a unconditional branch to go to the interpreter */
293static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
294                                  ArmLIR *pcrLabel)
295{
296    ArmLIR *branch = opNone(cUnit, kOpUncondBr);
297    return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
298}
299
300/* Load a wide field from an object instance */
301static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
302{
303    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
304    RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
305    RegLocation rlResult;
306    rlObj = loadValue(cUnit, rlObj, kCoreReg);
307    int regPtr = dvmCompilerAllocTemp(cUnit);
308
309    assert(rlDest.wide);
310
311    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
312                 NULL);/* null object? */
313    opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
314    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
315
316    HEAP_ACCESS_SHADOW(true);
317    loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
318    HEAP_ACCESS_SHADOW(false);
319
320    dvmCompilerFreeTemp(cUnit, regPtr);
321    storeValueWide(cUnit, rlDest, rlResult);
322}
323
324/* Store a wide field to an object instance */
325static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
326{
327    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
328    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 2);
329    rlObj = loadValue(cUnit, rlObj, kCoreReg);
330    int regPtr;
331    rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
332    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
333                 NULL);/* null object? */
334    regPtr = dvmCompilerAllocTemp(cUnit);
335    opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
336
337    HEAP_ACCESS_SHADOW(true);
338    storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
339    HEAP_ACCESS_SHADOW(false);
340
341    dvmCompilerFreeTemp(cUnit, regPtr);
342}
343
344/*
345 * Load a field from an object instance
346 *
347 */
348static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
349                    int fieldOffset, bool isVolatile)
350{
351    RegLocation rlResult;
352    RegisterClass regClass = dvmCompilerRegClassBySize(size);
353    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
354    RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
355    rlObj = loadValue(cUnit, rlObj, kCoreReg);
356    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
357    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
358                 NULL);/* null object? */
359
360    HEAP_ACCESS_SHADOW(true);
361    loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
362                 size, rlObj.sRegLow);
363    HEAP_ACCESS_SHADOW(false);
364    if (isVolatile) {
365        dvmCompilerGenMemBarrier(cUnit, kSY);
366    }
367
368    storeValue(cUnit, rlDest, rlResult);
369}
370
371/*
372 * Store a field to an object instance
373 *
374 */
375static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
376                    int fieldOffset, bool isObject, bool isVolatile)
377{
378    RegisterClass regClass = dvmCompilerRegClassBySize(size);
379    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
380    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 1);
381    rlObj = loadValue(cUnit, rlObj, kCoreReg);
382    rlSrc = loadValue(cUnit, rlSrc, regClass);
383    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
384                 NULL);/* null object? */
385
386    if (isVolatile) {
387        dvmCompilerGenMemBarrier(cUnit, kSY);
388    }
389    HEAP_ACCESS_SHADOW(true);
390    storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
391    HEAP_ACCESS_SHADOW(false);
392    if (isObject) {
393        /* NOTE: marking card based on object head */
394        markCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
395    }
396}
397
398
399/*
400 * Generate array load
401 */
402static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
403                        RegLocation rlArray, RegLocation rlIndex,
404                        RegLocation rlDest, int scale)
405{
406    RegisterClass regClass = dvmCompilerRegClassBySize(size);
407    int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
408    int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
409    RegLocation rlResult;
410    rlArray = loadValue(cUnit, rlArray, kCoreReg);
411    rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
412    int regPtr;
413
414    /* null object? */
415    ArmLIR * pcrLabel = NULL;
416
417    if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
418        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
419                                rlArray.lowReg, mir->offset, NULL);
420    }
421
422    regPtr = dvmCompilerAllocTemp(cUnit);
423
424    if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
425        int regLen = dvmCompilerAllocTemp(cUnit);
426        /* Get len */
427        loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
428        /* regPtr -> array data */
429        opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
430        genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
431                       pcrLabel);
432        dvmCompilerFreeTemp(cUnit, regLen);
433    } else {
434        /* regPtr -> array data */
435        opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
436    }
437    if ((size == kLong) || (size == kDouble)) {
438        if (scale) {
439            int rNewIndex = dvmCompilerAllocTemp(cUnit);
440            opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
441            opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
442            dvmCompilerFreeTemp(cUnit, rNewIndex);
443        } else {
444            opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
445        }
446        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
447
448        HEAP_ACCESS_SHADOW(true);
449        loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
450        HEAP_ACCESS_SHADOW(false);
451
452        dvmCompilerFreeTemp(cUnit, regPtr);
453        storeValueWide(cUnit, rlDest, rlResult);
454    } else {
455        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
456
457        HEAP_ACCESS_SHADOW(true);
458        loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
459                        scale, size);
460        HEAP_ACCESS_SHADOW(false);
461
462        dvmCompilerFreeTemp(cUnit, regPtr);
463        storeValue(cUnit, rlDest, rlResult);
464    }
465}
466
467/*
468 * Generate array store
469 *
470 */
471static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
472                        RegLocation rlArray, RegLocation rlIndex,
473                        RegLocation rlSrc, int scale)
474{
475    RegisterClass regClass = dvmCompilerRegClassBySize(size);
476    int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
477    int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
478
479    int regPtr;
480    rlArray = loadValue(cUnit, rlArray, kCoreReg);
481    rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
482
483    if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) {
484        dvmCompilerClobber(cUnit, rlArray.lowReg);
485        regPtr = rlArray.lowReg;
486    } else {
487        regPtr = dvmCompilerAllocTemp(cUnit);
488        genRegCopy(cUnit, regPtr, rlArray.lowReg);
489    }
490
491    /* null object? */
492    ArmLIR * pcrLabel = NULL;
493
494    if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
495        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
496                                mir->offset, NULL);
497    }
498
499    if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
500        int regLen = dvmCompilerAllocTemp(cUnit);
501        //NOTE: max live temps(4) here.
502        /* Get len */
503        loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
504        /* regPtr -> array data */
505        opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
506        genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
507                       pcrLabel);
508        dvmCompilerFreeTemp(cUnit, regLen);
509    } else {
510        /* regPtr -> array data */
511        opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
512    }
513    /* at this point, regPtr points to array, 2 live temps */
514    if ((size == kLong) || (size == kDouble)) {
515        //TODO: need specific wide routine that can handle fp regs
516        if (scale) {
517            int rNewIndex = dvmCompilerAllocTemp(cUnit);
518            opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
519            opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
520            dvmCompilerFreeTemp(cUnit, rNewIndex);
521        } else {
522            opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
523        }
524        rlSrc = loadValueWide(cUnit, rlSrc, regClass);
525
526        HEAP_ACCESS_SHADOW(true);
527        storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
528        HEAP_ACCESS_SHADOW(false);
529
530        dvmCompilerFreeTemp(cUnit, regPtr);
531    } else {
532        rlSrc = loadValue(cUnit, rlSrc, regClass);
533
534        HEAP_ACCESS_SHADOW(true);
535        storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
536                         scale, size);
537        HEAP_ACCESS_SHADOW(false);
538    }
539}
540
541/*
542 * Generate array object store
543 * Must use explicit register allocation here because of
544 * call-out to dvmCanPutArrayElement
545 */
546static void genArrayObjectPut(CompilationUnit *cUnit, MIR *mir,
547                              RegLocation rlArray, RegLocation rlIndex,
548                              RegLocation rlSrc, int scale)
549{
550    int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
551    int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
552
553    dvmCompilerFlushAllRegs(cUnit);
554
555    int regLen = r0;
556    int regPtr = r4PC;  /* Preserved across call */
557    int regArray = r1;
558    int regIndex = r7;  /* Preserved across call */
559
560    loadValueDirectFixed(cUnit, rlArray, regArray);
561    loadValueDirectFixed(cUnit, rlIndex, regIndex);
562
563    /* null object? */
564    ArmLIR * pcrLabel = NULL;
565
566    if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
567        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, regArray,
568                                mir->offset, NULL);
569    }
570
571    if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
572        /* Get len */
573        loadWordDisp(cUnit, regArray, lenOffset, regLen);
574        /* regPtr -> array data */
575        opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset);
576        genBoundsCheck(cUnit, regIndex, regLen, mir->offset,
577                       pcrLabel);
578    } else {
579        /* regPtr -> array data */
580        opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset);
581    }
582
583    /* Get object to store */
584    loadValueDirectFixed(cUnit, rlSrc, r0);
585    LOAD_FUNC_ADDR(cUnit, r2, (int)dvmCanPutArrayElement);
586
587    /* Are we storing null?  If so, avoid check */
588    ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
589
590    /* Make sure the types are compatible */
591    loadWordDisp(cUnit, regArray, offsetof(Object, clazz), r1);
592    loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
593    opReg(cUnit, kOpBlx, r2);
594    dvmCompilerClobberCallRegs(cUnit);
595
596    /*
597     * Using fixed registers here, and counting on r4 and r7 being
598     * preserved across the above call.  Tell the register allocation
599     * utilities about the regs we are using directly
600     */
601    dvmCompilerLockTemp(cUnit, regPtr);   // r4PC
602    dvmCompilerLockTemp(cUnit, regIndex); // r7
603    dvmCompilerLockTemp(cUnit, r0);
604    dvmCompilerLockTemp(cUnit, r1);
605
606    /* Bad? - roll back and re-execute if so */
607    genRegImmCheck(cUnit, kArmCondEq, r0, 0, mir->offset, pcrLabel);
608
609    /* Resume here - must reload element & array, regPtr & index preserved */
610    loadValueDirectFixed(cUnit, rlSrc, r0);
611    loadValueDirectFixed(cUnit, rlArray, r1);
612
613    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
614    target->defMask = ENCODE_ALL;
615    branchOver->generic.target = (LIR *) target;
616
617    HEAP_ACCESS_SHADOW(true);
618    storeBaseIndexed(cUnit, regPtr, regIndex, r0,
619                     scale, kWord);
620    HEAP_ACCESS_SHADOW(false);
621
622    dvmCompilerFreeTemp(cUnit, regPtr);
623    dvmCompilerFreeTemp(cUnit, regIndex);
624
625    /* NOTE: marking card here based on object head */
626    markCard(cUnit, r0, r1);
627}
628
629static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
630                           RegLocation rlDest, RegLocation rlSrc1,
631                           RegLocation rlShift)
632{
633    /*
634     * Don't mess with the regsiters here as there is a particular calling
635     * convention to the out-of-line handler.
636     */
637    RegLocation rlResult;
638
639    loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
640    loadValueDirect(cUnit, rlShift, r2);
641    switch( mir->dalvikInsn.opcode) {
642        case OP_SHL_LONG:
643        case OP_SHL_LONG_2ADDR:
644            genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
645            break;
646        case OP_SHR_LONG:
647        case OP_SHR_LONG_2ADDR:
648            genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
649            break;
650        case OP_USHR_LONG:
651        case OP_USHR_LONG_2ADDR:
652            genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
653            break;
654        default:
655            return true;
656    }
657    rlResult = dvmCompilerGetReturnWide(cUnit);
658    storeValueWide(cUnit, rlDest, rlResult);
659    return false;
660}
661
662static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir,
663                           RegLocation rlDest, RegLocation rlSrc1,
664                           RegLocation rlSrc2)
665{
666    RegLocation rlResult;
667    OpKind firstOp = kOpBkpt;
668    OpKind secondOp = kOpBkpt;
669    bool callOut = false;
670    void *callTgt;
671    int retReg = r0;
672
673    switch (mir->dalvikInsn.opcode) {
674        case OP_NOT_LONG:
675            rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
676            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
677            opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
678            opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
679            storeValueWide(cUnit, rlDest, rlResult);
680            return false;
681            break;
682        case OP_ADD_LONG:
683        case OP_ADD_LONG_2ADDR:
684            firstOp = kOpAdd;
685            secondOp = kOpAdc;
686            break;
687        case OP_SUB_LONG:
688        case OP_SUB_LONG_2ADDR:
689            firstOp = kOpSub;
690            secondOp = kOpSbc;
691            break;
692        case OP_MUL_LONG:
693        case OP_MUL_LONG_2ADDR:
694            genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
695            return false;
696        case OP_DIV_LONG:
697        case OP_DIV_LONG_2ADDR:
698            callOut = true;
699            retReg = r0;
700            callTgt = (void*)__aeabi_ldivmod;
701            break;
702        /* NOTE - result is in r2/r3 instead of r0/r1 */
703        case OP_REM_LONG:
704        case OP_REM_LONG_2ADDR:
705            callOut = true;
706            callTgt = (void*)__aeabi_ldivmod;
707            retReg = r2;
708            break;
709        case OP_AND_LONG_2ADDR:
710        case OP_AND_LONG:
711            firstOp = kOpAnd;
712            secondOp = kOpAnd;
713            break;
714        case OP_OR_LONG:
715        case OP_OR_LONG_2ADDR:
716            firstOp = kOpOr;
717            secondOp = kOpOr;
718            break;
719        case OP_XOR_LONG:
720        case OP_XOR_LONG_2ADDR:
721            firstOp = kOpXor;
722            secondOp = kOpXor;
723            break;
724        case OP_NEG_LONG: {
725            //TUNING: can improve this using Thumb2 code
726            int tReg = dvmCompilerAllocTemp(cUnit);
727            rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
728            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
729            loadConstantNoClobber(cUnit, tReg, 0);
730            opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
731                        tReg, rlSrc2.lowReg);
732            opRegReg(cUnit, kOpSbc, tReg, rlSrc2.highReg);
733            genRegCopy(cUnit, rlResult.highReg, tReg);
734            storeValueWide(cUnit, rlDest, rlResult);
735            return false;
736        }
737        default:
738            LOGE("Invalid long arith op");
739            dvmCompilerAbort(cUnit);
740    }
741    if (!callOut) {
742        genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
743    } else {
744        // Adjust return regs in to handle case of rem returning r2/r3
745        dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
746        loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
747        LOAD_FUNC_ADDR(cUnit, r14lr, (int) callTgt);
748        loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
749        opReg(cUnit, kOpBlx, r14lr);
750        dvmCompilerClobberCallRegs(cUnit);
751        if (retReg == r0)
752            rlResult = dvmCompilerGetReturnWide(cUnit);
753        else
754            rlResult = dvmCompilerGetReturnWideAlt(cUnit);
755        storeValueWide(cUnit, rlDest, rlResult);
756#if defined(WITH_SELF_VERIFICATION)
757        cUnit->usesLinkRegister = true;
758#endif
759    }
760    return false;
761}
762
763static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir,
764                          RegLocation rlDest, RegLocation rlSrc1,
765                          RegLocation rlSrc2)
766{
767    OpKind op = kOpBkpt;
768    bool callOut = false;
769    bool checkZero = false;
770    bool unary = false;
771    int retReg = r0;
772    int (*callTgt)(int, int);
773    RegLocation rlResult;
774    bool shiftOp = false;
775
776    switch (mir->dalvikInsn.opcode) {
777        case OP_NEG_INT:
778            op = kOpNeg;
779            unary = true;
780            break;
781        case OP_NOT_INT:
782            op = kOpMvn;
783            unary = true;
784            break;
785        case OP_ADD_INT:
786        case OP_ADD_INT_2ADDR:
787            op = kOpAdd;
788            break;
789        case OP_SUB_INT:
790        case OP_SUB_INT_2ADDR:
791            op = kOpSub;
792            break;
793        case OP_MUL_INT:
794        case OP_MUL_INT_2ADDR:
795            op = kOpMul;
796            break;
797        case OP_DIV_INT:
798        case OP_DIV_INT_2ADDR:
799            callOut = true;
800            checkZero = true;
801            callTgt = __aeabi_idiv;
802            retReg = r0;
803            break;
804        /* NOTE: returns in r1 */
805        case OP_REM_INT:
806        case OP_REM_INT_2ADDR:
807            callOut = true;
808            checkZero = true;
809            callTgt = __aeabi_idivmod;
810            retReg = r1;
811            break;
812        case OP_AND_INT:
813        case OP_AND_INT_2ADDR:
814            op = kOpAnd;
815            break;
816        case OP_OR_INT:
817        case OP_OR_INT_2ADDR:
818            op = kOpOr;
819            break;
820        case OP_XOR_INT:
821        case OP_XOR_INT_2ADDR:
822            op = kOpXor;
823            break;
824        case OP_SHL_INT:
825        case OP_SHL_INT_2ADDR:
826            shiftOp = true;
827            op = kOpLsl;
828            break;
829        case OP_SHR_INT:
830        case OP_SHR_INT_2ADDR:
831            shiftOp = true;
832            op = kOpAsr;
833            break;
834        case OP_USHR_INT:
835        case OP_USHR_INT_2ADDR:
836            shiftOp = true;
837            op = kOpLsr;
838            break;
839        default:
840            LOGE("Invalid word arith op: %#x(%d)",
841                 mir->dalvikInsn.opcode, mir->dalvikInsn.opcode);
842            dvmCompilerAbort(cUnit);
843    }
844    if (!callOut) {
845        rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
846        if (unary) {
847            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
848            opRegReg(cUnit, op, rlResult.lowReg,
849                     rlSrc1.lowReg);
850        } else {
851            rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
852            if (shiftOp) {
853                int tReg = dvmCompilerAllocTemp(cUnit);
854                opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
855                rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
856                opRegRegReg(cUnit, op, rlResult.lowReg,
857                            rlSrc1.lowReg, tReg);
858                dvmCompilerFreeTemp(cUnit, tReg);
859            } else {
860                rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
861                opRegRegReg(cUnit, op, rlResult.lowReg,
862                            rlSrc1.lowReg, rlSrc2.lowReg);
863            }
864        }
865        storeValue(cUnit, rlDest, rlResult);
866    } else {
867        RegLocation rlResult;
868        dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
869        loadValueDirectFixed(cUnit, rlSrc2, r1);
870        LOAD_FUNC_ADDR(cUnit, r2, (int) callTgt);
871        loadValueDirectFixed(cUnit, rlSrc1, r0);
872        if (checkZero) {
873            genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
874        }
875        opReg(cUnit, kOpBlx, r2);
876        dvmCompilerClobberCallRegs(cUnit);
877        if (retReg == r0)
878            rlResult = dvmCompilerGetReturn(cUnit);
879        else
880            rlResult = dvmCompilerGetReturnAlt(cUnit);
881        storeValue(cUnit, rlDest, rlResult);
882    }
883    return false;
884}
885
886static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
887{
888    Opcode opcode = mir->dalvikInsn.opcode;
889    RegLocation rlDest;
890    RegLocation rlSrc1;
891    RegLocation rlSrc2;
892    /* Deduce sizes of operands */
893    if (mir->ssaRep->numUses == 2) {
894        rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
895        rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
896    } else if (mir->ssaRep->numUses == 3) {
897        rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
898        rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
899    } else {
900        rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
901        rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
902        assert(mir->ssaRep->numUses == 4);
903    }
904    if (mir->ssaRep->numDefs == 1) {
905        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
906    } else {
907        assert(mir->ssaRep->numDefs == 2);
908        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
909    }
910
911    if ((opcode >= OP_ADD_LONG_2ADDR) && (opcode <= OP_XOR_LONG_2ADDR)) {
912        return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
913    }
914    if ((opcode >= OP_ADD_LONG) && (opcode <= OP_XOR_LONG)) {
915        return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
916    }
917    if ((opcode >= OP_SHL_LONG_2ADDR) && (opcode <= OP_USHR_LONG_2ADDR)) {
918        return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
919    }
920    if ((opcode >= OP_SHL_LONG) && (opcode <= OP_USHR_LONG)) {
921        return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
922    }
923    if ((opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_USHR_INT_2ADDR)) {
924        return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
925    }
926    if ((opcode >= OP_ADD_INT) && (opcode <= OP_USHR_INT)) {
927        return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
928    }
929    if ((opcode >= OP_ADD_FLOAT_2ADDR) && (opcode <= OP_REM_FLOAT_2ADDR)) {
930        return genArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
931    }
932    if ((opcode >= OP_ADD_FLOAT) && (opcode <= OP_REM_FLOAT)) {
933        return genArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
934    }
935    if ((opcode >= OP_ADD_DOUBLE_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) {
936        return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
937    }
938    if ((opcode >= OP_ADD_DOUBLE) && (opcode <= OP_REM_DOUBLE)) {
939        return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
940    }
941    return true;
942}
943
944/* Generate unconditional branch instructions */
945static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
946{
947    ArmLIR *branch = opNone(cUnit, kOpUncondBr);
948    branch->generic.target = (LIR *) target;
949    return branch;
950}
951
952/* Perform the actual operation for OP_RETURN_* */
953static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
954{
955    genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
956                         TEMPLATE_RETURN_PROF : TEMPLATE_RETURN);
957#if defined(WITH_JIT_TUNING)
958    gDvmJit.returnOp++;
959#endif
960    int dPC = (int) (cUnit->method->insns + mir->offset);
961    /* Insert branch, but defer setting of target */
962    ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
963    /* Set up the place holder to reconstruct this Dalvik PC */
964    ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
965    pcrLabel->opcode = kArmPseudoPCReconstructionCell;
966    pcrLabel->operands[0] = dPC;
967    pcrLabel->operands[1] = mir->offset;
968    /* Insert the place holder to the growable list */
969    dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel);
970    /* Branch to the PC reconstruction code */
971    branch->generic.target = (LIR *) pcrLabel;
972}
973
974static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
975                                  DecodedInstruction *dInsn,
976                                  ArmLIR **pcrLabel)
977{
978    unsigned int i;
979    unsigned int regMask = 0;
980    RegLocation rlArg;
981    int numDone = 0;
982
983    /*
984     * Load arguments to r0..r4.  Note that these registers may contain
985     * live values, so we clobber them immediately after loading to prevent
986     * them from being used as sources for subsequent loads.
987     */
988    dvmCompilerLockAllTemps(cUnit);
989    for (i = 0; i < dInsn->vA; i++) {
990        regMask |= 1 << i;
991        rlArg = dvmCompilerGetSrc(cUnit, mir, numDone++);
992        loadValueDirectFixed(cUnit, rlArg, i);
993    }
994    if (regMask) {
995        /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
996        opRegRegImm(cUnit, kOpSub, r7, r5FP,
997                    sizeof(StackSaveArea) + (dInsn->vA << 2));
998        /* generate null check */
999        if (pcrLabel) {
1000            *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0,
1001                                     mir->offset, NULL);
1002        }
1003        storeMultiple(cUnit, r7, regMask);
1004    }
1005}
1006
1007static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1008                                DecodedInstruction *dInsn,
1009                                ArmLIR **pcrLabel)
1010{
1011    int srcOffset = dInsn->vC << 2;
1012    int numArgs = dInsn->vA;
1013    int regMask;
1014
1015    /*
1016     * Note: here, all promoted registers will have been flushed
1017     * back to the Dalvik base locations, so register usage restrictins
1018     * are lifted.  All parms loaded from original Dalvik register
1019     * region - even though some might conceivably have valid copies
1020     * cached in a preserved register.
1021     */
1022    dvmCompilerLockAllTemps(cUnit);
1023
1024    /*
1025     * r4PC     : &r5FP[vC]
1026     * r7: &newFP[0]
1027     */
1028    opRegRegImm(cUnit, kOpAdd, r4PC, r5FP, srcOffset);
1029    /* load [r0 .. min(numArgs,4)] */
1030    regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
1031    /*
1032     * Protect the loadMultiple instruction from being reordered with other
1033     * Dalvik stack accesses.
1034     *
1035     * This code is also shared by the invoke jumbo instructions, and this
1036     * does not need to be done if the invoke jumbo has no arguments.
1037     */
1038    if (numArgs != 0) loadMultiple(cUnit, r4PC, regMask);
1039
1040    opRegRegImm(cUnit, kOpSub, r7, r5FP,
1041                sizeof(StackSaveArea) + (numArgs << 2));
1042    /* generate null check */
1043    if (pcrLabel) {
1044        *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0,
1045                                 mir->offset, NULL);
1046    }
1047
1048    /*
1049     * Handle remaining 4n arguments:
1050     * store previously loaded 4 values and load the next 4 values
1051     */
1052    if (numArgs >= 8) {
1053        ArmLIR *loopLabel = NULL;
1054        /*
1055         * r0 contains "this" and it will be used later, so push it to the stack
1056         * first. Pushing r5FP is just for stack alignment purposes.
1057         */
1058        opImm(cUnit, kOpPush, (1 << r0 | 1 << r5FP));
1059        /* No need to generate the loop structure if numArgs <= 11 */
1060        if (numArgs > 11) {
1061            loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
1062            loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
1063            loopLabel->defMask = ENCODE_ALL;
1064        }
1065        storeMultiple(cUnit, r7, regMask);
1066        /*
1067         * Protect the loadMultiple instruction from being reordered with other
1068         * Dalvik stack accesses.
1069         */
1070        loadMultiple(cUnit, r4PC, regMask);
1071        /* No need to generate the loop structure if numArgs <= 11 */
1072        if (numArgs > 11) {
1073            opRegImm(cUnit, kOpSub, r5FP, 4);
1074            genConditionalBranch(cUnit, kArmCondNe, loopLabel);
1075        }
1076    }
1077
1078    /* Save the last batch of loaded values */
1079    if (numArgs != 0) storeMultiple(cUnit, r7, regMask);
1080
1081    /* Generate the loop epilogue - don't use r0 */
1082    if ((numArgs > 4) && (numArgs % 4)) {
1083        regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
1084        /*
1085         * Protect the loadMultiple instruction from being reordered with other
1086         * Dalvik stack accesses.
1087         */
1088        loadMultiple(cUnit, r4PC, regMask);
1089    }
1090    if (numArgs >= 8)
1091        opImm(cUnit, kOpPop, (1 << r0 | 1 << r5FP));
1092
1093    /* Save the modulo 4 arguments */
1094    if ((numArgs > 4) && (numArgs % 4)) {
1095        storeMultiple(cUnit, r7, regMask);
1096    }
1097}
1098
1099/*
1100 * Generate code to setup the call stack then jump to the chaining cell if it
1101 * is not a native method.
1102 */
1103static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
1104                                     BasicBlock *bb, ArmLIR *labelList,
1105                                     ArmLIR *pcrLabel,
1106                                     const Method *calleeMethod)
1107{
1108    /*
1109     * Note: all Dalvik register state should be flushed to
1110     * memory by the point, so register usage restrictions no
1111     * longer apply.  All temp & preserved registers may be used.
1112     */
1113    dvmCompilerLockAllTemps(cUnit);
1114    ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
1115
1116    /* r1 = &retChainingCell */
1117    ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0);
1118
1119    /* r4PC = dalvikCallsite */
1120    loadConstant(cUnit, r4PC,
1121                 (int) (cUnit->method->insns + mir->offset));
1122    addrRetChain->generic.target = (LIR *) retChainingCell;
1123
1124    /* r7 = calleeMethod->registersSize */
1125    loadConstant(cUnit, r7, calleeMethod->registersSize);
1126    /*
1127     * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
1128     * r1 = &ChainingCell
1129     * r2 = calleeMethod->outsSize (to be loaded later for Java callees)
1130     * r4PC = callsiteDPC
1131     * r7 = calleeMethod->registersSize
1132     */
1133    if (dvmIsNativeMethod(calleeMethod)) {
1134        genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
1135            TEMPLATE_INVOKE_METHOD_NATIVE_PROF :
1136            TEMPLATE_INVOKE_METHOD_NATIVE);
1137#if defined(WITH_JIT_TUNING)
1138        gDvmJit.invokeNative++;
1139#endif
1140    } else {
1141        /* For Java callees, set up r2 to be calleeMethod->outsSize */
1142        loadConstant(cUnit, r2, calleeMethod->outsSize);
1143        genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
1144            TEMPLATE_INVOKE_METHOD_CHAIN_PROF :
1145            TEMPLATE_INVOKE_METHOD_CHAIN);
1146#if defined(WITH_JIT_TUNING)
1147        gDvmJit.invokeMonomorphic++;
1148#endif
1149        /* Branch to the chaining cell */
1150        genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1151    }
1152    /* Handle exceptions using the interpreter */
1153    genTrap(cUnit, mir->offset, pcrLabel);
1154}
1155
1156/*
1157 * Generate code to check the validity of a predicted chain and take actions
1158 * based on the result.
1159 *
1160 * 0x426a99aa : ldr     r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1161 * 0x426a99ac : add     r1, pc, #32   --> r1 <- &retChainingCell
1162 * 0x426a99ae : add     r2, pc, #40   --> r2 <- &predictedChainingCell
1163 * 0x426a99b0 : blx_1   0x426a918c    --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1164 * 0x426a99b2 : blx_2   see above     --+
1165 * 0x426a99b4 : b       0x426a99d8    --> off to the predicted chain
1166 * 0x426a99b6 : b       0x426a99c8    --> punt to the interpreter
1167 * 0x426a99b8 : ldr     r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1168 * 0x426a99ba : cmp     r1, #0        --> compare r1 (rechain count) against 0
1169 * 0x426a99bc : bgt     0x426a99c2    --> >=0? don't rechain
1170 * 0x426a99be : ldr     r7, [pc, #off]--+ dvmJitToPatchPredictedChain
1171 * 0x426a99c0 : blx     r7            --+
1172 * 0x426a99c2 : add     r1, pc, #12   --> r1 <- &retChainingCell
1173 * 0x426a99c4 : blx_1   0x426a9098    --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1174 * 0x426a99c6 : blx_2   see above     --+
1175 */
1176static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1177                                   int methodIndex,
1178                                   ArmLIR *retChainingCell,
1179                                   ArmLIR *predChainingCell,
1180                                   ArmLIR *pcrLabel)
1181{
1182    /*
1183     * Note: all Dalvik register state should be flushed to
1184     * memory by the point, so register usage restrictions no
1185     * longer apply.  Lock temps to prevent them from being
1186     * allocated by utility routines.
1187     */
1188    dvmCompilerLockAllTemps(cUnit);
1189
1190    /*
1191     * For verbose printing, store the method pointer in operands[1] first as
1192     * operands[0] will be clobbered in dvmCompilerMIR2LIR.
1193     */
1194    predChainingCell->operands[1] = (int) mir->meta.callsiteInfo->method;
1195
1196    /* "this" is already left in r0 by genProcessArgs* */
1197
1198    /* r4PC = dalvikCallsite */
1199    loadConstant(cUnit, r4PC,
1200                 (int) (cUnit->method->insns + mir->offset));
1201
1202    /* r1 = &retChainingCell */
1203    ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0);
1204    addrRetChain->generic.target = (LIR *) retChainingCell;
1205
1206    /* r2 = &predictedChainingCell */
1207    ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, r15pc, 0);
1208    predictedChainingCell->generic.target = (LIR *) predChainingCell;
1209
1210    genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
1211        TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF :
1212        TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1213
1214    /* return through lr - jump to the chaining cell */
1215    genUnconditionalBranch(cUnit, predChainingCell);
1216
1217    /*
1218     * null-check on "this" may have been eliminated, but we still need a PC-
1219     * reconstruction label for stack overflow bailout.
1220     */
1221    if (pcrLabel == NULL) {
1222        int dPC = (int) (cUnit->method->insns + mir->offset);
1223        pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
1224        pcrLabel->opcode = kArmPseudoPCReconstructionCell;
1225        pcrLabel->operands[0] = dPC;
1226        pcrLabel->operands[1] = mir->offset;
1227        /* Insert the place holder to the growable list */
1228        dvmInsertGrowableList(&cUnit->pcReconstructionList,
1229                              (intptr_t) pcrLabel);
1230    }
1231
1232    /* return through lr+2 - punt to the interpreter */
1233    genUnconditionalBranch(cUnit, pcrLabel);
1234
1235    /*
1236     * return through lr+4 - fully resolve the callee method.
1237     * r1 <- count
1238     * r2 <- &predictedChainCell
1239     * r3 <- this->class
1240     * r4 <- dPC
1241     * r7 <- this->class->vtable
1242     */
1243
1244    /* r0 <- calleeMethod */
1245    loadWordDisp(cUnit, r7, methodIndex * 4, r0);
1246
1247    /* Check if rechain limit is reached */
1248    ArmLIR *bypassRechaining = genCmpImmBranch(cUnit, kArmCondGt, r1, 0);
1249
1250    LOAD_FUNC_ADDR(cUnit, r7, (int) dvmJitToPatchPredictedChain);
1251
1252    genRegCopy(cUnit, r1, r6SELF);
1253
1254    /*
1255     * r0 = calleeMethod
1256     * r2 = &predictedChainingCell
1257     * r3 = class
1258     *
1259     * &returnChainingCell has been loaded into r1 but is not needed
1260     * when patching the chaining cell and will be clobbered upon
1261     * returning so it will be reconstructed again.
1262     */
1263    opReg(cUnit, kOpBlx, r7);
1264
1265    /* r1 = &retChainingCell */
1266    addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0);
1267    addrRetChain->generic.target = (LIR *) retChainingCell;
1268
1269    bypassRechaining->generic.target = (LIR *) addrRetChain;
1270    /*
1271     * r0 = calleeMethod,
1272     * r1 = &ChainingCell,
1273     * r4PC = callsiteDPC,
1274     */
1275    genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
1276        TEMPLATE_INVOKE_METHOD_NO_OPT_PROF :
1277        TEMPLATE_INVOKE_METHOD_NO_OPT);
1278#if defined(WITH_JIT_TUNING)
1279    gDvmJit.invokePolymorphic++;
1280#endif
1281    /* Handle exceptions using the interpreter */
1282    genTrap(cUnit, mir->offset, pcrLabel);
1283}
1284
1285/* "this" pointer is already in r0 */
1286static void genInvokeVirtualWholeMethod(CompilationUnit *cUnit,
1287                                        MIR *mir,
1288                                        void *calleeAddr,
1289                                        ArmLIR *retChainingCell)
1290{
1291    CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
1292    dvmCompilerLockAllTemps(cUnit);
1293
1294    loadClassPointer(cUnit, r1, (int) callsiteInfo);
1295
1296    loadWordDisp(cUnit, r0, offsetof(Object, clazz), r2);
1297    /* Branch to the slow path if classes are not equal */
1298    opRegReg(cUnit, kOpCmp, r1, r2);
1299    /*
1300     * Set the misPredBranchOver target so that it will be generated when the
1301     * code for the non-optimized invoke is generated.
1302     */
1303    ArmLIR *classCheck = opCondBranch(cUnit, kArmCondNe);
1304
1305    /* r0 = the Dalvik PC of the callsite */
1306    loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1307
1308    newLIR2(cUnit, kThumbBl1, (int) calleeAddr, (int) calleeAddr);
1309    newLIR2(cUnit, kThumbBl2, (int) calleeAddr, (int) calleeAddr);
1310    genUnconditionalBranch(cUnit, retChainingCell);
1311
1312    /* Target of slow path */
1313    ArmLIR *slowPathLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
1314
1315    slowPathLabel->defMask = ENCODE_ALL;
1316    classCheck->generic.target = (LIR *) slowPathLabel;
1317
1318    // FIXME
1319    cUnit->printMe = true;
1320}
1321
1322static void genInvokeSingletonWholeMethod(CompilationUnit *cUnit,
1323                                          MIR *mir,
1324                                          void *calleeAddr,
1325                                          ArmLIR *retChainingCell)
1326{
1327    /* r0 = the Dalvik PC of the callsite */
1328    loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1329
1330    newLIR2(cUnit, kThumbBl1, (int) calleeAddr, (int) calleeAddr);
1331    newLIR2(cUnit, kThumbBl2, (int) calleeAddr, (int) calleeAddr);
1332    genUnconditionalBranch(cUnit, retChainingCell);
1333
1334    // FIXME
1335    cUnit->printMe = true;
1336}
1337
1338/* Geneate a branch to go back to the interpreter */
1339static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1340{
1341    /* r0 = dalvik pc */
1342    dvmCompilerFlushAllRegs(cUnit);
1343    loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
1344    loadWordDisp(cUnit, r6SELF, offsetof(Thread,
1345                 jitToInterpEntries.dvmJitToInterpPunt), r1);
1346    opReg(cUnit, kOpBlx, r1);
1347}
1348
1349/*
1350 * Attempt to single step one instruction using the interpreter and return
1351 * to the compiled code for the next Dalvik instruction
1352 */
1353static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1354{
1355    int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode);
1356    int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn;
1357
1358    // Single stepping is considered loop mode breaker
1359    if (cUnit->jitMode == kJitLoop) {
1360        cUnit->quitLoopMode = true;
1361        return;
1362    }
1363
1364    //If already optimized out, just ignore
1365    if (mir->dalvikInsn.opcode == OP_NOP)
1366        return;
1367
1368    //Ugly, but necessary.  Flush all Dalvik regs so Interp can find them
1369    dvmCompilerFlushAllRegs(cUnit);
1370
1371    if ((mir->next == NULL) || (flags & flagsToCheck)) {
1372       genPuntToInterp(cUnit, mir->offset);
1373       return;
1374    }
1375    int entryAddr = offsetof(Thread,
1376                             jitToInterpEntries.dvmJitToInterpSingleStep);
1377    loadWordDisp(cUnit, r6SELF, entryAddr, r2);
1378    /* r0 = dalvik pc */
1379    loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1380    /* r1 = dalvik pc of following instruction */
1381    loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
1382    opReg(cUnit, kOpBlx, r2);
1383}
1384
1385#if defined(_ARMV5TE) || defined(_ARMV5TE_VFP)
1386/*
1387 * To prevent a thread in a monitor wait from blocking the Jit from
1388 * resetting the code cache, heavyweight monitor lock will not
1389 * be allowed to return to an existing translation.  Instead, we will
1390 * handle them by branching to a handler, which will in turn call the
1391 * runtime lock routine and then branch directly back to the
1392 * interpreter main loop.  Given the high cost of the heavyweight
1393 * lock operation, this additional cost should be slight (especially when
1394 * considering that we expect the vast majority of lock operations to
1395 * use the fast-path thin lock bypass).
1396 */
1397static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir)
1398{
1399    bool isEnter = (mir->dalvikInsn.opcode == OP_MONITOR_ENTER);
1400    genExportPC(cUnit, mir);
1401    dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
1402    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1403    loadValueDirectFixed(cUnit, rlSrc, r1);
1404    genRegCopy(cUnit, r0, r6SELF);
1405    genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
1406    if (isEnter) {
1407        /* Get dPC of next insn */
1408        loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset +
1409                 dexGetWidthFromOpcode(OP_MONITOR_ENTER)));
1410        genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER);
1411    } else {
1412        LOAD_FUNC_ADDR(cUnit, r2, (int)dvmUnlockObject);
1413        /* Do the call */
1414        opReg(cUnit, kOpBlx, r2);
1415        /* Did we throw? */
1416        ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
1417        loadConstant(cUnit, r0,
1418                     (int) (cUnit->method->insns + mir->offset +
1419                     dexGetWidthFromOpcode(OP_MONITOR_EXIT)));
1420        genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1421        ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1422        target->defMask = ENCODE_ALL;
1423        branchOver->generic.target = (LIR *) target;
1424        dvmCompilerClobberCallRegs(cUnit);
1425    }
1426}
1427#endif
1428
1429/*
1430 * Fetch *self->info.breakFlags. If the breakFlags are non-zero,
1431 * punt to the interpreter.
1432 */
1433static void genSuspendPoll(CompilationUnit *cUnit, MIR *mir)
1434{
1435    int rTemp = dvmCompilerAllocTemp(cUnit);
1436    ArmLIR *ld;
1437    ld = loadBaseDisp(cUnit, NULL, r6SELF,
1438                      offsetof(Thread, interpBreak.ctl.breakFlags),
1439                      rTemp, kUnsignedByte, INVALID_SREG);
1440    setMemRefType(ld, true /* isLoad */, kMustNotAlias);
1441    genRegImmCheck(cUnit, kArmCondNe, rTemp, 0, mir->offset, NULL);
1442}
1443
1444/*
1445 * The following are the first-level codegen routines that analyze the format
1446 * of each bytecode then either dispatch special purpose codegen routines
1447 * or produce corresponding Thumb instructions directly.
1448 */
1449
1450static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
1451                                       BasicBlock *bb, ArmLIR *labelList)
1452{
1453    /* backward branch? */
1454    bool backwardBranch = (bb->taken->startOffset <= mir->offset);
1455
1456    if (backwardBranch &&
1457        (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
1458        genSuspendPoll(cUnit, mir);
1459    }
1460
1461    int numPredecessors = dvmCountSetBits(bb->taken->predecessors);
1462    /*
1463     * Things could be hoisted out of the taken block into the predecessor, so
1464     * make sure it is dominated by the predecessor.
1465     */
1466    if (numPredecessors == 1 && bb->taken->visited == false &&
1467        bb->taken->blockType == kDalvikByteCode) {
1468        cUnit->nextCodegenBlock = bb->taken;
1469    } else {
1470        /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1471        genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1472    }
1473    return false;
1474}
1475
1476static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1477{
1478    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1479    if ((dalvikOpcode >= OP_UNUSED_3E) && (dalvikOpcode <= OP_UNUSED_43)) {
1480        LOGE("Codegen: got unused opcode %#x",dalvikOpcode);
1481        return true;
1482    }
1483    switch (dalvikOpcode) {
1484        case OP_RETURN_VOID_BARRIER:
1485            dvmCompilerGenMemBarrier(cUnit, kST);
1486            // Intentional fallthrough
1487        case OP_RETURN_VOID:
1488            genReturnCommon(cUnit,mir);
1489            break;
1490        case OP_UNUSED_73:
1491        case OP_UNUSED_79:
1492        case OP_UNUSED_7A:
1493        case OP_DISPATCH_FF:
1494            LOGE("Codegen: got unused opcode %#x",dalvikOpcode);
1495            return true;
1496        case OP_NOP:
1497            break;
1498        default:
1499            return true;
1500    }
1501    return false;
1502}
1503
1504static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1505{
1506    RegLocation rlDest;
1507    RegLocation rlResult;
1508    if (mir->ssaRep->numDefs == 2) {
1509        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1510    } else {
1511        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1512    }
1513
1514    switch (mir->dalvikInsn.opcode) {
1515        case OP_CONST:
1516        case OP_CONST_4: {
1517            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1518            loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1519            storeValue(cUnit, rlDest, rlResult);
1520            break;
1521        }
1522        case OP_CONST_WIDE_32: {
1523            //TUNING: single routine to load constant pair for support doubles
1524            //TUNING: load 0/-1 separately to avoid load dependency
1525            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1526            loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1527            opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1528                        rlResult.lowReg, 31);
1529            storeValueWide(cUnit, rlDest, rlResult);
1530            break;
1531        }
1532        default:
1533            return true;
1534    }
1535    return false;
1536}
1537
1538static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1539{
1540    RegLocation rlDest;
1541    RegLocation rlResult;
1542    if (mir->ssaRep->numDefs == 2) {
1543        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1544    } else {
1545        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1546    }
1547    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1548
1549    switch (mir->dalvikInsn.opcode) {
1550        case OP_CONST_HIGH16: {
1551            loadConstantNoClobber(cUnit, rlResult.lowReg,
1552                                  mir->dalvikInsn.vB << 16);
1553            storeValue(cUnit, rlDest, rlResult);
1554            break;
1555        }
1556        case OP_CONST_WIDE_HIGH16: {
1557            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1558                                  0, mir->dalvikInsn.vB << 16);
1559            storeValueWide(cUnit, rlDest, rlResult);
1560            break;
1561        }
1562        default:
1563            return true;
1564    }
1565    return false;
1566}
1567
1568static bool handleFmt20bc_Fmt40sc(CompilationUnit *cUnit, MIR *mir)
1569{
1570    /* For OP_THROW_VERIFICATION_ERROR & OP_THROW_VERIFICATION_ERROR_JUMBO */
1571    genInterpSingleStep(cUnit, mir);
1572    return false;
1573}
1574
1575static bool handleFmt21c_Fmt31c_Fmt41c(CompilationUnit *cUnit, MIR *mir)
1576{
1577    RegLocation rlResult;
1578    RegLocation rlDest;
1579    RegLocation rlSrc;
1580
1581    switch (mir->dalvikInsn.opcode) {
1582        case OP_CONST_STRING_JUMBO:
1583        case OP_CONST_STRING: {
1584            void *strPtr = (void*)
1585              (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1586
1587            if (strPtr == NULL) {
1588                BAIL_LOOP_COMPILATION();
1589                LOGE("Unexpected null string");
1590                dvmAbort();
1591            }
1592
1593            rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1594            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1595            loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr );
1596            storeValue(cUnit, rlDest, rlResult);
1597            break;
1598        }
1599        case OP_CONST_CLASS:
1600        case OP_CONST_CLASS_JUMBO: {
1601            void *classPtr = (void*)
1602              (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1603
1604            if (classPtr == NULL) {
1605                BAIL_LOOP_COMPILATION();
1606                LOGE("Unexpected null class");
1607                dvmAbort();
1608            }
1609
1610            rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1611            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1612            loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr );
1613            storeValue(cUnit, rlDest, rlResult);
1614            break;
1615        }
1616        case OP_SGET:
1617        case OP_SGET_VOLATILE:
1618        case OP_SGET_VOLATILE_JUMBO:
1619        case OP_SGET_JUMBO:
1620        case OP_SGET_OBJECT:
1621        case OP_SGET_OBJECT_VOLATILE:
1622        case OP_SGET_OBJECT_VOLATILE_JUMBO:
1623        case OP_SGET_OBJECT_JUMBO:
1624        case OP_SGET_BOOLEAN:
1625        case OP_SGET_BOOLEAN_JUMBO:
1626        case OP_SGET_CHAR:
1627        case OP_SGET_CHAR_JUMBO:
1628        case OP_SGET_BYTE:
1629        case OP_SGET_BYTE_JUMBO:
1630        case OP_SGET_SHORT:
1631        case OP_SGET_SHORT_JUMBO: {
1632            int valOffset = OFFSETOF_MEMBER(StaticField, value);
1633            int tReg = dvmCompilerAllocTemp(cUnit);
1634            bool isVolatile;
1635            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
1636                mir->meta.calleeMethod : cUnit->method;
1637            void *fieldPtr = (void*)
1638              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1639
1640            if (fieldPtr == NULL) {
1641                BAIL_LOOP_COMPILATION();
1642                LOGE("Unexpected null static field");
1643                dvmAbort();
1644            }
1645
1646            /*
1647             * On SMP systems, Dalvik opcodes found to be referencing
1648             * volatile fields are rewritten to their _VOLATILE variant.
1649             * However, this does not happen on non-SMP systems. The JIT
1650             * still needs to know about volatility to avoid unsafe
1651             * optimizations so we determine volatility based on either
1652             * the opcode or the field access flags.
1653             */
1654#if ANDROID_SMP != 0
1655            Opcode opcode = mir->dalvikInsn.opcode;
1656            isVolatile = (opcode == OP_SGET_VOLATILE) ||
1657                         (opcode == OP_SGET_VOLATILE_JUMBO) ||
1658                         (opcode == OP_SGET_OBJECT_VOLATILE) ||
1659                         (opcode == OP_SGET_OBJECT_VOLATILE_JUMBO);
1660            assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
1661#else
1662            isVolatile = dvmIsVolatileField((Field *) fieldPtr);
1663#endif
1664
1665            rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1666            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1667            loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
1668
1669            if (isVolatile) {
1670                dvmCompilerGenMemBarrier(cUnit, kSY);
1671            }
1672            HEAP_ACCESS_SHADOW(true);
1673            loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
1674            HEAP_ACCESS_SHADOW(false);
1675
1676            storeValue(cUnit, rlDest, rlResult);
1677            break;
1678        }
1679        case OP_SGET_WIDE:
1680        case OP_SGET_WIDE_JUMBO: {
1681            int valOffset = OFFSETOF_MEMBER(StaticField, value);
1682            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
1683                mir->meta.calleeMethod : cUnit->method;
1684            void *fieldPtr = (void*)
1685              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1686
1687            if (fieldPtr == NULL) {
1688                BAIL_LOOP_COMPILATION();
1689                LOGE("Unexpected null static field");
1690                dvmAbort();
1691            }
1692
1693            int tReg = dvmCompilerAllocTemp(cUnit);
1694            rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1695            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1696            loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
1697
1698            HEAP_ACCESS_SHADOW(true);
1699            loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
1700            HEAP_ACCESS_SHADOW(false);
1701
1702            storeValueWide(cUnit, rlDest, rlResult);
1703            break;
1704        }
1705        case OP_SPUT:
1706        case OP_SPUT_VOLATILE:
1707        case OP_SPUT_VOLATILE_JUMBO:
1708        case OP_SPUT_JUMBO:
1709        case OP_SPUT_OBJECT:
1710        case OP_SPUT_OBJECT_VOLATILE:
1711        case OP_SPUT_OBJECT_VOLATILE_JUMBO:
1712        case OP_SPUT_OBJECT_JUMBO:
1713        case OP_SPUT_BOOLEAN:
1714        case OP_SPUT_BOOLEAN_JUMBO:
1715        case OP_SPUT_CHAR:
1716        case OP_SPUT_CHAR_JUMBO:
1717        case OP_SPUT_BYTE:
1718        case OP_SPUT_BYTE_JUMBO:
1719        case OP_SPUT_SHORT:
1720        case OP_SPUT_SHORT_JUMBO: {
1721            int valOffset = OFFSETOF_MEMBER(StaticField, value);
1722            int tReg = dvmCompilerAllocTemp(cUnit);
1723            int objHead;
1724            bool isVolatile;
1725            bool isSputObject;
1726            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
1727                mir->meta.calleeMethod : cUnit->method;
1728            void *fieldPtr = (void*)
1729              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1730            Opcode opcode = mir->dalvikInsn.opcode;
1731
1732            if (fieldPtr == NULL) {
1733                BAIL_LOOP_COMPILATION();
1734                LOGE("Unexpected null static field");
1735                dvmAbort();
1736            }
1737
1738#if ANDROID_SMP != 0
1739            isVolatile = (opcode == OP_SPUT_VOLATILE) ||
1740                         (opcode == OP_SPUT_VOLATILE_JUMBO) ||
1741                         (opcode == OP_SPUT_OBJECT_VOLATILE) ||
1742                         (opcode == OP_SPUT_OBJECT_VOLATILE_JUMBO);
1743            assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
1744#else
1745            isVolatile = dvmIsVolatileField((Field *) fieldPtr);
1746#endif
1747
1748            isSputObject = (opcode == OP_SPUT_OBJECT) ||
1749                           (opcode == OP_SPUT_OBJECT_JUMBO) ||
1750                           (opcode == OP_SPUT_OBJECT_VOLATILE) ||
1751                           (opcode == OP_SPUT_OBJECT_VOLATILE_JUMBO);
1752
1753            rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1754            rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1755            loadConstant(cUnit, tReg,  (int) fieldPtr);
1756            if (isSputObject) {
1757                objHead = dvmCompilerAllocTemp(cUnit);
1758                loadWordDisp(cUnit, tReg, OFFSETOF_MEMBER(Field, clazz), objHead);
1759            }
1760            HEAP_ACCESS_SHADOW(true);
1761            storeWordDisp(cUnit, tReg, valOffset ,rlSrc.lowReg);
1762            dvmCompilerFreeTemp(cUnit, tReg);
1763            HEAP_ACCESS_SHADOW(false);
1764            if (isVolatile) {
1765                dvmCompilerGenMemBarrier(cUnit, kSY);
1766            }
1767            if (isSputObject) {
1768                /* NOTE: marking card based sfield->clazz */
1769                markCard(cUnit, rlSrc.lowReg, objHead);
1770                dvmCompilerFreeTemp(cUnit, objHead);
1771            }
1772
1773            break;
1774        }
1775        case OP_SPUT_WIDE:
1776        case OP_SPUT_WIDE_JUMBO: {
1777            int tReg = dvmCompilerAllocTemp(cUnit);
1778            int valOffset = OFFSETOF_MEMBER(StaticField, value);
1779            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
1780                mir->meta.calleeMethod : cUnit->method;
1781            void *fieldPtr = (void*)
1782              (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1783
1784            if (fieldPtr == NULL) {
1785                BAIL_LOOP_COMPILATION();
1786                LOGE("Unexpected null static field");
1787                dvmAbort();
1788            }
1789
1790            rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1791            rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1792            loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
1793
1794            HEAP_ACCESS_SHADOW(true);
1795            storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
1796            HEAP_ACCESS_SHADOW(false);
1797            break;
1798        }
1799        case OP_NEW_INSTANCE:
1800        case OP_NEW_INSTANCE_JUMBO: {
1801            /*
1802             * Obey the calling convention and don't mess with the register
1803             * usage.
1804             */
1805            ClassObject *classPtr = (ClassObject *)
1806              (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1807
1808            if (classPtr == NULL) {
1809                BAIL_LOOP_COMPILATION();
1810                LOGE("Unexpected null class");
1811                dvmAbort();
1812            }
1813
1814            /*
1815             * If it is going to throw, it should not make to the trace to begin
1816             * with.  However, Alloc might throw, so we need to genExportPC()
1817             */
1818            assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
1819            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
1820            genExportPC(cUnit, mir);
1821            LOAD_FUNC_ADDR(cUnit, r2, (int)dvmAllocObject);
1822            loadConstant(cUnit, r0, (int) classPtr);
1823            loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
1824            opReg(cUnit, kOpBlx, r2);
1825            dvmCompilerClobberCallRegs(cUnit);
1826            /* generate a branch over if allocation is successful */
1827            ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
1828            /*
1829             * OOM exception needs to be thrown here and cannot re-execute
1830             */
1831            loadConstant(cUnit, r0,
1832                         (int) (cUnit->method->insns + mir->offset));
1833            genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1834            /* noreturn */
1835
1836            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1837            target->defMask = ENCODE_ALL;
1838            branchOver->generic.target = (LIR *) target;
1839            rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1840            rlResult = dvmCompilerGetReturn(cUnit);
1841            storeValue(cUnit, rlDest, rlResult);
1842            break;
1843        }
1844        case OP_CHECK_CAST:
1845        case OP_CHECK_CAST_JUMBO: {
1846            /*
1847             * Obey the calling convention and don't mess with the register
1848             * usage.
1849             */
1850            ClassObject *classPtr =
1851              (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1852            /*
1853             * Note: It is possible that classPtr is NULL at this point,
1854             * even though this instruction has been successfully interpreted.
1855             * If the previous interpretation had a null source, the
1856             * interpreter would not have bothered to resolve the clazz.
1857             * Bail out to the interpreter in this case, and log it
1858             * so that we can tell if it happens frequently.
1859             */
1860            if (classPtr == NULL) {
1861                BAIL_LOOP_COMPILATION();
1862                LOGVV("null clazz in OP_CHECK_CAST, single-stepping");
1863                genInterpSingleStep(cUnit, mir);
1864                return false;
1865            }
1866            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
1867            loadConstant(cUnit, r1, (int) classPtr );
1868            rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1869            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1870            /* Null? */
1871            ArmLIR *branch1 = genCmpImmBranch(cUnit, kArmCondEq,
1872                                              rlSrc.lowReg, 0);
1873            /*
1874             *  rlSrc.lowReg now contains object->clazz.  Note that
1875             *  it could have been allocated r0, but we're okay so long
1876             *  as we don't do anything desctructive until r0 is loaded
1877             *  with clazz.
1878             */
1879            /* r0 now contains object->clazz */
1880            loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
1881            LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInstanceofNonTrivial);
1882            opRegReg(cUnit, kOpCmp, r0, r1);
1883            ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
1884            opReg(cUnit, kOpBlx, r2);
1885            dvmCompilerClobberCallRegs(cUnit);
1886            /*
1887             * If null, check cast failed - punt to the interpreter.  Because
1888             * interpreter will be the one throwing, we don't need to
1889             * genExportPC() here.
1890             */
1891            genZeroCheck(cUnit, r0, mir->offset, NULL);
1892            /* check cast passed - branch target here */
1893            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1894            target->defMask = ENCODE_ALL;
1895            branch1->generic.target = (LIR *)target;
1896            branch2->generic.target = (LIR *)target;
1897            break;
1898        }
1899        case OP_SGET_WIDE_VOLATILE:
1900        case OP_SGET_WIDE_VOLATILE_JUMBO:
1901        case OP_SPUT_WIDE_VOLATILE:
1902        case OP_SPUT_WIDE_VOLATILE_JUMBO:
1903            genInterpSingleStep(cUnit, mir);
1904            break;
1905        default:
1906            return true;
1907    }
1908    return false;
1909}
1910
1911/*
1912 * A typical example of inlined getter/setter from a monomorphic callsite:
1913 *
1914 * D/dalvikvm(  289): -------- dalvik offset: 0x0000 @ invoke-static (I)
1915 * D/dalvikvm(  289): -------- dalvik offset: 0x0000 @ sget-object (C) v0, ...
1916 * D/dalvikvm(  289): 0x4427fc22 (0002): ldr     r0, [pc, #56]
1917 * D/dalvikvm(  289): 0x4427fc24 (0004): ldr     r1, [r0, #0]
1918 * D/dalvikvm(  289): 0x4427fc26 (0006): str     r1, [r5, #0]
1919 * D/dalvikvm(  289): 0x4427fc28 (0008): .align4
1920 * D/dalvikvm(  289): L0x0003:
1921 * D/dalvikvm(  289): -------- dalvik offset: 0x0003 @ move-result-object (I) v0
1922 *
1923 * Note the invoke-static and move-result-object with the (I) notation are
1924 * turned into no-op.
1925 */
1926static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1927{
1928    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1929    RegLocation rlResult;
1930    switch (dalvikOpcode) {
1931        case OP_MOVE_EXCEPTION: {
1932            int exOffset = offsetof(Thread, exception);
1933            int resetReg = dvmCompilerAllocTemp(cUnit);
1934            RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1935            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1936            loadWordDisp(cUnit, r6SELF, exOffset, rlResult.lowReg);
1937            loadConstant(cUnit, resetReg, 0);
1938            storeWordDisp(cUnit, r6SELF, exOffset, resetReg);
1939            storeValue(cUnit, rlDest, rlResult);
1940           break;
1941        }
1942        case OP_MOVE_RESULT:
1943        case OP_MOVE_RESULT_OBJECT: {
1944            /* An inlined move result is effectively no-op */
1945            if (mir->OptimizationFlags & MIR_INLINED)
1946                break;
1947            RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1948            RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
1949            rlSrc.fp = rlDest.fp;
1950            storeValue(cUnit, rlDest, rlSrc);
1951            break;
1952        }
1953        case OP_MOVE_RESULT_WIDE: {
1954            /* An inlined move result is effectively no-op */
1955            if (mir->OptimizationFlags & MIR_INLINED)
1956                break;
1957            RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1958            RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
1959            rlSrc.fp = rlDest.fp;
1960            storeValueWide(cUnit, rlDest, rlSrc);
1961            break;
1962        }
1963        case OP_RETURN_WIDE: {
1964            RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1965            RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
1966            rlDest.fp = rlSrc.fp;
1967            storeValueWide(cUnit, rlDest, rlSrc);
1968            genReturnCommon(cUnit,mir);
1969            break;
1970        }
1971        case OP_RETURN:
1972        case OP_RETURN_OBJECT: {
1973            RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1974            RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
1975            rlDest.fp = rlSrc.fp;
1976            storeValue(cUnit, rlDest, rlSrc);
1977            genReturnCommon(cUnit, mir);
1978            break;
1979        }
1980        case OP_MONITOR_EXIT:
1981        case OP_MONITOR_ENTER:
1982            genMonitor(cUnit, mir);
1983            break;
1984        case OP_THROW:
1985            genInterpSingleStep(cUnit, mir);
1986            break;
1987        default:
1988            return true;
1989    }
1990    return false;
1991}
1992
1993static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1994{
1995    Opcode opcode = mir->dalvikInsn.opcode;
1996    RegLocation rlDest;
1997    RegLocation rlSrc;
1998    RegLocation rlResult;
1999
2000    if ( (opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) {
2001        return genArithOp( cUnit, mir );
2002    }
2003
2004    if (mir->ssaRep->numUses == 2)
2005        rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2006    else
2007        rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2008    if (mir->ssaRep->numDefs == 2)
2009        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
2010    else
2011        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2012
2013    switch (opcode) {
2014        case OP_DOUBLE_TO_INT:
2015        case OP_INT_TO_FLOAT:
2016        case OP_FLOAT_TO_INT:
2017        case OP_DOUBLE_TO_FLOAT:
2018        case OP_FLOAT_TO_DOUBLE:
2019        case OP_INT_TO_DOUBLE:
2020        case OP_FLOAT_TO_LONG:
2021        case OP_LONG_TO_FLOAT:
2022        case OP_DOUBLE_TO_LONG:
2023        case OP_LONG_TO_DOUBLE:
2024            return genConversion(cUnit, mir);
2025        case OP_NEG_INT:
2026        case OP_NOT_INT:
2027            return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
2028        case OP_NEG_LONG:
2029        case OP_NOT_LONG:
2030            return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
2031        case OP_NEG_FLOAT:
2032            return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
2033        case OP_NEG_DOUBLE:
2034            return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
2035        case OP_MOVE_WIDE:
2036            storeValueWide(cUnit, rlDest, rlSrc);
2037            break;
2038        case OP_INT_TO_LONG:
2039            rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
2040            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2041            //TUNING: shouldn't loadValueDirect already check for phys reg?
2042            if (rlSrc.location == kLocPhysReg) {
2043                genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2044            } else {
2045                loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
2046            }
2047            opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
2048                        rlResult.lowReg, 31);
2049            storeValueWide(cUnit, rlDest, rlResult);
2050            break;
2051        case OP_LONG_TO_INT:
2052            rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
2053            rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc);
2054            // Intentional fallthrough
2055        case OP_MOVE:
2056        case OP_MOVE_OBJECT:
2057            storeValue(cUnit, rlDest, rlSrc);
2058            break;
2059        case OP_INT_TO_BYTE:
2060            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2061            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2062            opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
2063            storeValue(cUnit, rlDest, rlResult);
2064            break;
2065        case OP_INT_TO_SHORT:
2066            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2067            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2068            opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
2069            storeValue(cUnit, rlDest, rlResult);
2070            break;
2071        case OP_INT_TO_CHAR:
2072            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2073            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2074            opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
2075            storeValue(cUnit, rlDest, rlResult);
2076            break;
2077        case OP_ARRAY_LENGTH: {
2078            int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
2079            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2080            genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
2081                         mir->offset, NULL);
2082            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2083            loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
2084                         rlResult.lowReg);
2085            storeValue(cUnit, rlDest, rlResult);
2086            break;
2087        }
2088        default:
2089            return true;
2090    }
2091    return false;
2092}
2093
2094static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2095{
2096    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2097    RegLocation rlDest;
2098    RegLocation rlResult;
2099    int BBBB = mir->dalvikInsn.vB;
2100    if (dalvikOpcode == OP_CONST_WIDE_16) {
2101        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
2102        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2103        loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
2104        //TUNING: do high separately to avoid load dependency
2105        opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
2106        storeValueWide(cUnit, rlDest, rlResult);
2107    } else if (dalvikOpcode == OP_CONST_16) {
2108        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2109        rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
2110        loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
2111        storeValue(cUnit, rlDest, rlResult);
2112    } else
2113        return true;
2114    return false;
2115}
2116
2117/* Compare agaist zero */
2118static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2119                         ArmLIR *labelList)
2120{
2121    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2122    ArmConditionCode cond;
2123    /* backward branch? */
2124    bool backwardBranch = (bb->taken->startOffset <= mir->offset);
2125
2126    if (backwardBranch &&
2127        (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
2128        genSuspendPoll(cUnit, mir);
2129    }
2130
2131    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2132    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2133
2134    opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
2135
2136//TUNING: break this out to allow use of Thumb2 CB[N]Z
2137    switch (dalvikOpcode) {
2138        case OP_IF_EQZ:
2139            cond = kArmCondEq;
2140            break;
2141        case OP_IF_NEZ:
2142            cond = kArmCondNe;
2143            break;
2144        case OP_IF_LTZ:
2145            cond = kArmCondLt;
2146            break;
2147        case OP_IF_GEZ:
2148            cond = kArmCondGe;
2149            break;
2150        case OP_IF_GTZ:
2151            cond = kArmCondGt;
2152            break;
2153        case OP_IF_LEZ:
2154            cond = kArmCondLe;
2155            break;
2156        default:
2157            cond = (ArmConditionCode)0;
2158            LOGE("Unexpected opcode (%d) for Fmt21t", dalvikOpcode);
2159            dvmCompilerAbort(cUnit);
2160    }
2161    genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2162    /* This mostly likely will be optimized away in a later phase */
2163    genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2164    return false;
2165}
2166
2167static bool isPowerOfTwo(int x)
2168{
2169    return (x & (x - 1)) == 0;
2170}
2171
2172// Returns true if no more than two bits are set in 'x'.
2173static bool isPopCountLE2(unsigned int x)
2174{
2175    x &= x - 1;
2176    return (x & (x - 1)) == 0;
2177}
2178
2179// Returns the index of the lowest set bit in 'x'.
2180static int lowestSetBit(unsigned int x) {
2181    int bit_posn = 0;
2182    while ((x & 0xf) == 0) {
2183        bit_posn += 4;
2184        x >>= 4;
2185    }
2186    while ((x & 1) == 0) {
2187        bit_posn++;
2188        x >>= 1;
2189    }
2190    return bit_posn;
2191}
2192
2193// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
2194// and store the result in 'rlDest'.
2195static bool handleEasyDivide(CompilationUnit *cUnit, Opcode dalvikOpcode,
2196                             RegLocation rlSrc, RegLocation rlDest, int lit)
2197{
2198    if (lit < 2 || !isPowerOfTwo(lit)) {
2199        return false;
2200    }
2201    int k = lowestSetBit(lit);
2202    if (k >= 30) {
2203        // Avoid special cases.
2204        return false;
2205    }
2206    bool div = (dalvikOpcode == OP_DIV_INT_LIT8 || dalvikOpcode == OP_DIV_INT_LIT16);
2207    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2208    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2209    if (div) {
2210        int tReg = dvmCompilerAllocTemp(cUnit);
2211        if (lit == 2) {
2212            // Division by 2 is by far the most common division by constant.
2213            opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
2214            opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
2215            opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
2216        } else {
2217            opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
2218            opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
2219            opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
2220            opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
2221        }
2222    } else {
2223        int cReg = dvmCompilerAllocTemp(cUnit);
2224        loadConstant(cUnit, cReg, lit - 1);
2225        int tReg1 = dvmCompilerAllocTemp(cUnit);
2226        int tReg2 = dvmCompilerAllocTemp(cUnit);
2227        if (lit == 2) {
2228            opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
2229            opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
2230            opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
2231            opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
2232        } else {
2233            opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
2234            opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
2235            opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
2236            opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
2237            opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
2238        }
2239    }
2240    storeValue(cUnit, rlDest, rlResult);
2241    return true;
2242}
2243
2244// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
2245// and store the result in 'rlDest'.
2246static bool handleEasyMultiply(CompilationUnit *cUnit,
2247                               RegLocation rlSrc, RegLocation rlDest, int lit)
2248{
2249    // Can we simplify this multiplication?
2250    bool powerOfTwo = false;
2251    bool popCountLE2 = false;
2252    bool powerOfTwoMinusOne = false;
2253    if (lit < 2) {
2254        // Avoid special cases.
2255        return false;
2256    } else if (isPowerOfTwo(lit)) {
2257        powerOfTwo = true;
2258    } else if (isPopCountLE2(lit)) {
2259        popCountLE2 = true;
2260    } else if (isPowerOfTwo(lit + 1)) {
2261        powerOfTwoMinusOne = true;
2262    } else {
2263        return false;
2264    }
2265    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2266    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2267    if (powerOfTwo) {
2268        // Shift.
2269        opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
2270                    lowestSetBit(lit));
2271    } else if (popCountLE2) {
2272        // Shift and add and shift.
2273        int firstBit = lowestSetBit(lit);
2274        int secondBit = lowestSetBit(lit ^ (1 << firstBit));
2275        genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
2276                                      firstBit, secondBit);
2277    } else {
2278        // Reverse subtract: (src << (shift + 1)) - src.
2279        assert(powerOfTwoMinusOne);
2280        // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1)
2281        int tReg = dvmCompilerAllocTemp(cUnit);
2282        opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
2283        opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
2284    }
2285    storeValue(cUnit, rlDest, rlResult);
2286    return true;
2287}
2288
2289static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2290{
2291    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2292    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2293    RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2294    RegLocation rlResult;
2295    int lit = mir->dalvikInsn.vC;
2296    OpKind op = (OpKind)0;      /* Make gcc happy */
2297    int shiftOp = false;
2298    bool isDiv = false;
2299
2300    switch (dalvikOpcode) {
2301        case OP_RSUB_INT_LIT8:
2302        case OP_RSUB_INT: {
2303            int tReg;
2304            //TUNING: add support for use of Arm rsub op
2305            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2306            tReg = dvmCompilerAllocTemp(cUnit);
2307            loadConstant(cUnit, tReg, lit);
2308            rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2309            opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
2310                        tReg, rlSrc.lowReg);
2311            storeValue(cUnit, rlDest, rlResult);
2312            return false;
2313            break;
2314        }
2315
2316        case OP_ADD_INT_LIT8:
2317        case OP_ADD_INT_LIT16:
2318            op = kOpAdd;
2319            break;
2320        case OP_MUL_INT_LIT8:
2321        case OP_MUL_INT_LIT16: {
2322            if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
2323                return false;
2324            }
2325            op = kOpMul;
2326            break;
2327        }
2328        case OP_AND_INT_LIT8:
2329        case OP_AND_INT_LIT16:
2330            op = kOpAnd;
2331            break;
2332        case OP_OR_INT_LIT8:
2333        case OP_OR_INT_LIT16:
2334            op = kOpOr;
2335            break;
2336        case OP_XOR_INT_LIT8:
2337        case OP_XOR_INT_LIT16:
2338            op = kOpXor;
2339            break;
2340        case OP_SHL_INT_LIT8:
2341            lit &= 31;
2342            shiftOp = true;
2343            op = kOpLsl;
2344            break;
2345        case OP_SHR_INT_LIT8:
2346            lit &= 31;
2347            shiftOp = true;
2348            op = kOpAsr;
2349            break;
2350        case OP_USHR_INT_LIT8:
2351            lit &= 31;
2352            shiftOp = true;
2353            op = kOpLsr;
2354            break;
2355
2356        case OP_DIV_INT_LIT8:
2357        case OP_DIV_INT_LIT16:
2358        case OP_REM_INT_LIT8:
2359        case OP_REM_INT_LIT16:
2360            if (lit == 0) {
2361                /* Let the interpreter deal with div by 0 */
2362                genInterpSingleStep(cUnit, mir);
2363                return false;
2364            }
2365            if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
2366                return false;
2367            }
2368            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2369            loadValueDirectFixed(cUnit, rlSrc, r0);
2370            dvmCompilerClobber(cUnit, r0);
2371            if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
2372                (dalvikOpcode == OP_DIV_INT_LIT16)) {
2373                LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idiv);
2374                isDiv = true;
2375            } else {
2376                LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idivmod);
2377                isDiv = false;
2378            }
2379            loadConstant(cUnit, r1, lit);
2380            opReg(cUnit, kOpBlx, r2);
2381            dvmCompilerClobberCallRegs(cUnit);
2382            if (isDiv)
2383                rlResult = dvmCompilerGetReturn(cUnit);
2384            else
2385                rlResult = dvmCompilerGetReturnAlt(cUnit);
2386            storeValue(cUnit, rlDest, rlResult);
2387            return false;
2388            break;
2389        default:
2390            return true;
2391    }
2392    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2393    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2394    // Avoid shifts by literal 0 - no support in Thumb.  Change to copy
2395    if (shiftOp && (lit == 0)) {
2396        genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2397    } else {
2398        opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2399    }
2400    storeValue(cUnit, rlDest, rlResult);
2401    return false;
2402}
2403
2404static bool handleFmt22c_Fmt52c(CompilationUnit *cUnit, MIR *mir)
2405{
2406    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2407    int fieldOffset = -1;
2408    bool isVolatile = false;
2409    switch (dalvikOpcode) {
2410        /*
2411         * Wide volatiles currently handled via single step.
2412         * Add them here if generating in-line code.
2413         *     case OP_IGET_WIDE_VOLATILE:
2414         *     case OP_IGET_WIDE_VOLATILE_JUMBO:
2415         *     case OP_IPUT_WIDE_VOLATILE:
2416         *     case OP_IPUT_WIDE_VOLATILE_JUMBO:
2417         */
2418        case OP_IGET_VOLATILE:
2419        case OP_IGET_VOLATILE_JUMBO:
2420        case OP_IGET_OBJECT_VOLATILE:
2421        case OP_IGET_OBJECT_VOLATILE_JUMBO:
2422        case OP_IPUT_VOLATILE:
2423        case OP_IPUT_VOLATILE_JUMBO:
2424        case OP_IPUT_OBJECT_VOLATILE:
2425        case OP_IPUT_OBJECT_VOLATILE_JUMBO:
2426#if ANDROID_SMP != 0
2427            isVolatile = true;
2428        // NOTE: intentional fallthrough
2429#endif
2430        case OP_IGET:
2431        case OP_IGET_JUMBO:
2432        case OP_IGET_WIDE:
2433        case OP_IGET_WIDE_JUMBO:
2434        case OP_IGET_OBJECT:
2435        case OP_IGET_OBJECT_JUMBO:
2436        case OP_IGET_BOOLEAN:
2437        case OP_IGET_BOOLEAN_JUMBO:
2438        case OP_IGET_BYTE:
2439        case OP_IGET_BYTE_JUMBO:
2440        case OP_IGET_CHAR:
2441        case OP_IGET_CHAR_JUMBO:
2442        case OP_IGET_SHORT:
2443        case OP_IGET_SHORT_JUMBO:
2444        case OP_IPUT:
2445        case OP_IPUT_JUMBO:
2446        case OP_IPUT_WIDE:
2447        case OP_IPUT_WIDE_JUMBO:
2448        case OP_IPUT_OBJECT:
2449        case OP_IPUT_OBJECT_JUMBO:
2450        case OP_IPUT_BOOLEAN:
2451        case OP_IPUT_BOOLEAN_JUMBO:
2452        case OP_IPUT_BYTE:
2453        case OP_IPUT_BYTE_JUMBO:
2454        case OP_IPUT_CHAR:
2455        case OP_IPUT_CHAR_JUMBO:
2456        case OP_IPUT_SHORT:
2457        case OP_IPUT_SHORT_JUMBO: {
2458            const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
2459                mir->meta.calleeMethod : cUnit->method;
2460            Field *fieldPtr =
2461                method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2462
2463            if (fieldPtr == NULL) {
2464                BAIL_LOOP_COMPILATION();
2465                LOGE("Unexpected null instance field");
2466                dvmAbort();
2467            }
2468
2469#if ANDROID_SMP != 0
2470            assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
2471#else
2472            isVolatile = dvmIsVolatileField((Field *) fieldPtr);
2473#endif
2474            fieldOffset = ((InstField *)fieldPtr)->byteOffset;
2475            break;
2476        }
2477        default:
2478            break;
2479    }
2480
2481    switch (dalvikOpcode) {
2482        case OP_NEW_ARRAY:
2483        case OP_NEW_ARRAY_JUMBO: {
2484            // Generates a call - use explicit registers
2485            RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2486            RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2487            RegLocation rlResult;
2488            void *classPtr = (void*)
2489              (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2490
2491            if (classPtr == NULL) {
2492                BAIL_LOOP_COMPILATION();
2493                LOGE("Unexpected null class");
2494                dvmAbort();
2495            }
2496
2497            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2498            genExportPC(cUnit, mir);
2499            loadValueDirectFixed(cUnit, rlSrc, r1);   /* Len */
2500            loadConstant(cUnit, r0, (int) classPtr );
2501            LOAD_FUNC_ADDR(cUnit, r3, (int)dvmAllocArrayByClass);
2502            /*
2503             * "len < 0": bail to the interpreter to re-execute the
2504             * instruction
2505             */
2506            genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
2507            loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2508            opReg(cUnit, kOpBlx, r3);
2509            dvmCompilerClobberCallRegs(cUnit);
2510            /* generate a branch over if allocation is successful */
2511            ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
2512            /*
2513             * OOM exception needs to be thrown here and cannot re-execute
2514             */
2515            loadConstant(cUnit, r0,
2516                         (int) (cUnit->method->insns + mir->offset));
2517            genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2518            /* noreturn */
2519
2520            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2521            target->defMask = ENCODE_ALL;
2522            branchOver->generic.target = (LIR *) target;
2523            rlResult = dvmCompilerGetReturn(cUnit);
2524            storeValue(cUnit, rlDest, rlResult);
2525            break;
2526        }
2527        case OP_INSTANCE_OF:
2528        case OP_INSTANCE_OF_JUMBO: {
2529            // May generate a call - use explicit registers
2530            RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2531            RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2532            RegLocation rlResult;
2533            ClassObject *classPtr =
2534              (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2535            /*
2536             * Note: It is possible that classPtr is NULL at this point,
2537             * even though this instruction has been successfully interpreted.
2538             * If the previous interpretation had a null source, the
2539             * interpreter would not have bothered to resolve the clazz.
2540             * Bail out to the interpreter in this case, and log it
2541             * so that we can tell if it happens frequently.
2542             */
2543            if (classPtr == NULL) {
2544                BAIL_LOOP_COMPILATION();
2545                LOGD("null clazz in OP_INSTANCE_OF, single-stepping");
2546                genInterpSingleStep(cUnit, mir);
2547                break;
2548            }
2549            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2550            loadValueDirectFixed(cUnit, rlSrc, r0);  /* Ref */
2551            loadConstant(cUnit, r2, (int) classPtr );
2552            /* When taken r0 has NULL which can be used for store directly */
2553            ArmLIR *branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
2554            /* r1 now contains object->clazz */
2555            loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
2556            /* r1 now contains object->clazz */
2557            LOAD_FUNC_ADDR(cUnit, r3, (int)dvmInstanceofNonTrivial);
2558            loadConstant(cUnit, r0, 1);                /* Assume true */
2559            opRegReg(cUnit, kOpCmp, r1, r2);
2560            ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
2561            genRegCopy(cUnit, r0, r1);
2562            genRegCopy(cUnit, r1, r2);
2563            opReg(cUnit, kOpBlx, r3);
2564            dvmCompilerClobberCallRegs(cUnit);
2565            /* branch target here */
2566            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2567            target->defMask = ENCODE_ALL;
2568            rlResult = dvmCompilerGetReturn(cUnit);
2569            storeValue(cUnit, rlDest, rlResult);
2570            branch1->generic.target = (LIR *)target;
2571            branch2->generic.target = (LIR *)target;
2572            break;
2573        }
2574        case OP_IGET_WIDE:
2575        case OP_IGET_WIDE_JUMBO:
2576            genIGetWide(cUnit, mir, fieldOffset);
2577            break;
2578        case OP_IGET_VOLATILE:
2579        case OP_IGET_VOLATILE_JUMBO:
2580        case OP_IGET_OBJECT_VOLATILE:
2581        case OP_IGET_OBJECT_VOLATILE_JUMBO:
2582        case OP_IGET:
2583        case OP_IGET_JUMBO:
2584        case OP_IGET_OBJECT:
2585        case OP_IGET_OBJECT_JUMBO:
2586        case OP_IGET_BOOLEAN:
2587        case OP_IGET_BOOLEAN_JUMBO:
2588        case OP_IGET_BYTE:
2589        case OP_IGET_BYTE_JUMBO:
2590        case OP_IGET_CHAR:
2591        case OP_IGET_CHAR_JUMBO:
2592        case OP_IGET_SHORT:
2593        case OP_IGET_SHORT_JUMBO:
2594            genIGet(cUnit, mir, kWord, fieldOffset, isVolatile);
2595            break;
2596        case OP_IPUT_WIDE:
2597        case OP_IPUT_WIDE_JUMBO:
2598            genIPutWide(cUnit, mir, fieldOffset);
2599            break;
2600        case OP_IPUT_VOLATILE:
2601        case OP_IPUT_VOLATILE_JUMBO:
2602        case OP_IPUT:
2603        case OP_IPUT_JUMBO:
2604        case OP_IPUT_BOOLEAN:
2605        case OP_IPUT_BOOLEAN_JUMBO:
2606        case OP_IPUT_BYTE:
2607        case OP_IPUT_BYTE_JUMBO:
2608        case OP_IPUT_CHAR:
2609        case OP_IPUT_CHAR_JUMBO:
2610        case OP_IPUT_SHORT:
2611        case OP_IPUT_SHORT_JUMBO:
2612            genIPut(cUnit, mir, kWord, fieldOffset, false, isVolatile);
2613            break;
2614        case OP_IPUT_OBJECT_VOLATILE:
2615        case OP_IPUT_OBJECT_VOLATILE_JUMBO:
2616        case OP_IPUT_OBJECT:
2617        case OP_IPUT_OBJECT_JUMBO:
2618            genIPut(cUnit, mir, kWord, fieldOffset, true, isVolatile);
2619            break;
2620        case OP_IGET_WIDE_VOLATILE:
2621        case OP_IGET_WIDE_VOLATILE_JUMBO:
2622        case OP_IPUT_WIDE_VOLATILE:
2623        case OP_IPUT_WIDE_VOLATILE_JUMBO:
2624            genInterpSingleStep(cUnit, mir);
2625            break;
2626        default:
2627            return true;
2628    }
2629    return false;
2630}
2631
2632static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2633{
2634    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2635    int fieldOffset =  mir->dalvikInsn.vC;
2636    switch (dalvikOpcode) {
2637        case OP_IGET_QUICK:
2638        case OP_IGET_OBJECT_QUICK:
2639            genIGet(cUnit, mir, kWord, fieldOffset, false);
2640            break;
2641        case OP_IPUT_QUICK:
2642            genIPut(cUnit, mir, kWord, fieldOffset, false, false);
2643            break;
2644        case OP_IPUT_OBJECT_QUICK:
2645            genIPut(cUnit, mir, kWord, fieldOffset, true, false);
2646            break;
2647        case OP_IGET_WIDE_QUICK:
2648            genIGetWide(cUnit, mir, fieldOffset);
2649            break;
2650        case OP_IPUT_WIDE_QUICK:
2651            genIPutWide(cUnit, mir, fieldOffset);
2652            break;
2653        default:
2654            return true;
2655    }
2656    return false;
2657
2658}
2659
2660/* Compare agaist zero */
2661static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2662                         ArmLIR *labelList)
2663{
2664    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2665    ArmConditionCode cond;
2666    /* backward branch? */
2667    bool backwardBranch = (bb->taken->startOffset <= mir->offset);
2668
2669    if (backwardBranch &&
2670        (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
2671        genSuspendPoll(cUnit, mir);
2672    }
2673
2674    RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2675    RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
2676
2677    rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
2678    rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
2679
2680    opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
2681
2682    switch (dalvikOpcode) {
2683        case OP_IF_EQ:
2684            cond = kArmCondEq;
2685            break;
2686        case OP_IF_NE:
2687            cond = kArmCondNe;
2688            break;
2689        case OP_IF_LT:
2690            cond = kArmCondLt;
2691            break;
2692        case OP_IF_GE:
2693            cond = kArmCondGe;
2694            break;
2695        case OP_IF_GT:
2696            cond = kArmCondGt;
2697            break;
2698        case OP_IF_LE:
2699            cond = kArmCondLe;
2700            break;
2701        default:
2702            cond = (ArmConditionCode)0;
2703            LOGE("Unexpected opcode (%d) for Fmt22t", dalvikOpcode);
2704            dvmCompilerAbort(cUnit);
2705    }
2706    genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2707    /* This mostly likely will be optimized away in a later phase */
2708    genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2709    return false;
2710}
2711
2712static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2713{
2714    Opcode opcode = mir->dalvikInsn.opcode;
2715
2716    switch (opcode) {
2717        case OP_MOVE_16:
2718        case OP_MOVE_OBJECT_16:
2719        case OP_MOVE_FROM16:
2720        case OP_MOVE_OBJECT_FROM16: {
2721            storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0),
2722                       dvmCompilerGetSrc(cUnit, mir, 0));
2723            break;
2724        }
2725        case OP_MOVE_WIDE_16:
2726        case OP_MOVE_WIDE_FROM16: {
2727            storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1),
2728                           dvmCompilerGetSrcWide(cUnit, mir, 0, 1));
2729            break;
2730        }
2731        default:
2732            return true;
2733    }
2734    return false;
2735}
2736
2737static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2738{
2739    Opcode opcode = mir->dalvikInsn.opcode;
2740    RegLocation rlSrc1;
2741    RegLocation rlSrc2;
2742    RegLocation rlDest;
2743
2744    if ( (opcode >= OP_ADD_INT) && (opcode <= OP_REM_DOUBLE)) {
2745        return genArithOp( cUnit, mir );
2746    }
2747
2748    /* APUTs have 3 sources and no targets */
2749    if (mir->ssaRep->numDefs == 0) {
2750        if (mir->ssaRep->numUses == 3) {
2751            rlDest = dvmCompilerGetSrc(cUnit, mir, 0);
2752            rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1);
2753            rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
2754        } else {
2755            assert(mir->ssaRep->numUses == 4);
2756            rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2757            rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2);
2758            rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3);
2759        }
2760    } else {
2761        /* Two sources and 1 dest.  Deduce the operand sizes */
2762        if (mir->ssaRep->numUses == 4) {
2763            rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2764            rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
2765        } else {
2766            assert(mir->ssaRep->numUses == 2);
2767            rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2768            rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
2769        }
2770        if (mir->ssaRep->numDefs == 2) {
2771            rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
2772        } else {
2773            assert(mir->ssaRep->numDefs == 1);
2774            rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2775        }
2776    }
2777
2778
2779    switch (opcode) {
2780        case OP_CMPL_FLOAT:
2781        case OP_CMPG_FLOAT:
2782        case OP_CMPL_DOUBLE:
2783        case OP_CMPG_DOUBLE:
2784            return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2785        case OP_CMP_LONG:
2786            genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2787            break;
2788        case OP_AGET_WIDE:
2789            genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
2790            break;
2791        case OP_AGET:
2792        case OP_AGET_OBJECT:
2793            genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
2794            break;
2795        case OP_AGET_BOOLEAN:
2796            genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
2797            break;
2798        case OP_AGET_BYTE:
2799            genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
2800            break;
2801        case OP_AGET_CHAR:
2802            genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2803            break;
2804        case OP_AGET_SHORT:
2805            genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2806            break;
2807        case OP_APUT_WIDE:
2808            genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
2809            break;
2810        case OP_APUT:
2811            genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
2812            break;
2813        case OP_APUT_OBJECT:
2814            genArrayObjectPut(cUnit, mir, rlSrc1, rlSrc2, rlDest, 2);
2815            break;
2816        case OP_APUT_SHORT:
2817        case OP_APUT_CHAR:
2818            genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2819            break;
2820        case OP_APUT_BYTE:
2821        case OP_APUT_BOOLEAN:
2822            genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
2823            break;
2824        default:
2825            return true;
2826    }
2827    return false;
2828}
2829
2830/*
2831 * Find the matching case.
2832 *
2833 * return values:
2834 * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
2835 *    including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
2836 * r1 (high 32-bit): the branch offset of the matching case (only for indexes
2837 *    above MAX_CHAINED_SWITCH_CASES).
2838 *
2839 * Instructions around the call are:
2840 *
2841 * mov r2, pc
2842 * blx &findPackedSwitchIndex
2843 * mov pc, r0
2844 * .align4
2845 * chaining cell for case 0 [12 bytes]
2846 * chaining cell for case 1 [12 bytes]
2847 *               :
2848 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [12 bytes]
2849 * chaining cell for case default [8 bytes]
2850 * noChain exit
2851 */
2852static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
2853{
2854    int size;
2855    int firstKey;
2856    const int *entries;
2857    int index;
2858    int jumpIndex;
2859    int caseDPCOffset = 0;
2860    /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
2861    int chainingPC = (pc + 4) & ~3;
2862
2863    /*
2864     * Packed switch data format:
2865     *  ushort ident = 0x0100   magic value
2866     *  ushort size             number of entries in the table
2867     *  int first_key           first (and lowest) switch case value
2868     *  int targets[size]       branch targets, relative to switch opcode
2869     *
2870     * Total size is (4+size*2) 16-bit code units.
2871     */
2872    size = switchData[1];
2873    assert(size > 0);
2874
2875    firstKey = switchData[2];
2876    firstKey |= switchData[3] << 16;
2877
2878
2879    /* The entries are guaranteed to be aligned on a 32-bit boundary;
2880     * we can treat them as a native int array.
2881     */
2882    entries = (const int*) &switchData[4];
2883    assert(((u4)entries & 0x3) == 0);
2884
2885    index = testVal - firstKey;
2886
2887    /* Jump to the default cell */
2888    if (index < 0 || index >= size) {
2889        jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
2890    /* Jump to the non-chaining exit point */
2891    } else if (index >= MAX_CHAINED_SWITCH_CASES) {
2892        jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
2893        caseDPCOffset = entries[index];
2894    /* Jump to the inline chaining cell */
2895    } else {
2896        jumpIndex = index;
2897    }
2898
2899    chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE;
2900    return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
2901}
2902
2903/* See comments for findPackedSwitchIndex */
2904static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
2905{
2906    int size;
2907    const int *keys;
2908    const int *entries;
2909    int chainingPC = (pc + 4) & ~3;
2910    int i;
2911
2912    /*
2913     * Sparse switch data format:
2914     *  ushort ident = 0x0200   magic value
2915     *  ushort size             number of entries in the table; > 0
2916     *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
2917     *  int targets[size]       branch targets, relative to switch opcode
2918     *
2919     * Total size is (2+size*4) 16-bit code units.
2920     */
2921
2922    size = switchData[1];
2923    assert(size > 0);
2924
2925    /* The keys are guaranteed to be aligned on a 32-bit boundary;
2926     * we can treat them as a native int array.
2927     */
2928    keys = (const int*) &switchData[2];
2929    assert(((u4)keys & 0x3) == 0);
2930
2931    /* The entries are guaranteed to be aligned on a 32-bit boundary;
2932     * we can treat them as a native int array.
2933     */
2934    entries = keys + size;
2935    assert(((u4)entries & 0x3) == 0);
2936
2937    /*
2938     * Run through the list of keys, which are guaranteed to
2939     * be sorted low-to-high.
2940     *
2941     * Most tables have 3-4 entries.  Few have more than 10.  A binary
2942     * search here is probably not useful.
2943     */
2944    for (i = 0; i < size; i++) {
2945        int k = keys[i];
2946        if (k == testVal) {
2947            /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
2948            int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
2949                           i : MAX_CHAINED_SWITCH_CASES + 1;
2950            chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE;
2951            return (((s8) entries[i]) << 32) | (u8) chainingPC;
2952        } else if (k > testVal) {
2953            break;
2954        }
2955    }
2956    return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) *
2957           CHAIN_CELL_NORMAL_SIZE;
2958}
2959
2960static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2961{
2962    Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2963    switch (dalvikOpcode) {
2964        case OP_FILL_ARRAY_DATA: {
2965            RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2966            // Making a call - use explicit registers
2967            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2968            genExportPC(cUnit, mir);
2969            loadValueDirectFixed(cUnit, rlSrc, r0);
2970            LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInterpHandleFillArrayData);
2971            loadConstant(cUnit, r1,
2972               (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
2973            opReg(cUnit, kOpBlx, r2);
2974            dvmCompilerClobberCallRegs(cUnit);
2975            /* generate a branch over if successful */
2976            ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
2977            loadConstant(cUnit, r0,
2978                         (int) (cUnit->method->insns + mir->offset));
2979            genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2980            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2981            target->defMask = ENCODE_ALL;
2982            branchOver->generic.target = (LIR *) target;
2983            break;
2984        }
2985        /*
2986         * Compute the goto target of up to
2987         * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
2988         * See the comment before findPackedSwitchIndex for the code layout.
2989         */
2990        case OP_PACKED_SWITCH:
2991        case OP_SPARSE_SWITCH: {
2992            RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2993            dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2994            loadValueDirectFixed(cUnit, rlSrc, r1);
2995            dvmCompilerLockAllTemps(cUnit);
2996            if (dalvikOpcode == OP_PACKED_SWITCH) {
2997                LOAD_FUNC_ADDR(cUnit, r4PC, (int)findPackedSwitchIndex);
2998            } else {
2999                LOAD_FUNC_ADDR(cUnit, r4PC, (int)findSparseSwitchIndex);
3000            }
3001            /* r0 <- Addr of the switch data */
3002            loadConstant(cUnit, r0,
3003               (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
3004            /* r2 <- pc of the instruction following the blx */
3005            opRegReg(cUnit, kOpMov, r2, r15pc);
3006            opReg(cUnit, kOpBlx, r4PC);
3007            dvmCompilerClobberCallRegs(cUnit);
3008            /* pc <- computed goto target */
3009            opRegReg(cUnit, kOpMov, r15pc, r0);
3010            break;
3011        }
3012        default:
3013            return true;
3014    }
3015    return false;
3016}
3017
3018/*
3019 * See the example of predicted inlining listed before the
3020 * genValidationForPredictedInline function. The function here takes care the
3021 * branch over at 0x4858de78 and the misprediction target at 0x4858de7a.
3022 */
3023static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir,
3024                                               BasicBlock *bb,
3025                                               ArmLIR *labelList)
3026{
3027    BasicBlock *fallThrough = bb->fallThrough;
3028
3029    /* Bypass the move-result block if there is one */
3030    if (fallThrough->firstMIRInsn) {
3031        assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED);
3032        fallThrough = fallThrough->fallThrough;
3033    }
3034    /* Generate a branch over if the predicted inlining is correct */
3035    genUnconditionalBranch(cUnit, &labelList[fallThrough->id]);
3036
3037    /* Reset the register state */
3038    dvmCompilerResetRegPool(cUnit);
3039    dvmCompilerClobberAllRegs(cUnit);
3040    dvmCompilerResetNullCheck(cUnit);
3041
3042    /* Target for the slow invoke path */
3043    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3044    target->defMask = ENCODE_ALL;
3045    /* Hook up the target to the verification branch */
3046    mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target;
3047}
3048
3049static bool handleFmt35c_3rc_5rc(CompilationUnit *cUnit, MIR *mir,
3050                             BasicBlock *bb, ArmLIR *labelList)
3051{
3052    ArmLIR *retChainingCell = NULL;
3053    ArmLIR *pcrLabel = NULL;
3054
3055    /* An invoke with the MIR_INLINED is effectively a no-op */
3056    if (mir->OptimizationFlags & MIR_INLINED)
3057        return false;
3058
3059    if (bb->fallThrough != NULL)
3060        retChainingCell = &labelList[bb->fallThrough->id];
3061
3062    DecodedInstruction *dInsn = &mir->dalvikInsn;
3063    switch (mir->dalvikInsn.opcode) {
3064        /*
3065         * calleeMethod = this->clazz->vtable[
3066         *     method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3067         * ]
3068         */
3069        case OP_INVOKE_VIRTUAL:
3070        case OP_INVOKE_VIRTUAL_RANGE:
3071        case OP_INVOKE_VIRTUAL_JUMBO: {
3072            ArmLIR *predChainingCell = &labelList[bb->taken->id];
3073            int methodIndex =
3074                cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3075                methodIndex;
3076
3077            /*
3078             * If the invoke has non-null misPredBranchOver, we need to generate
3079             * the non-inlined version of the invoke here to handle the
3080             * mispredicted case.
3081             */
3082            if (mir->meta.callsiteInfo->misPredBranchOver) {
3083                genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
3084            }
3085
3086            if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
3087                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3088            else
3089                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3090
3091            genInvokeVirtualCommon(cUnit, mir, methodIndex,
3092                                   retChainingCell,
3093                                   predChainingCell,
3094                                   pcrLabel);
3095            break;
3096        }
3097        /*
3098         * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3099         *                ->pResMethods[BBBB]->methodIndex]
3100         */
3101        case OP_INVOKE_SUPER:
3102        case OP_INVOKE_SUPER_RANGE:
3103        case OP_INVOKE_SUPER_JUMBO: {
3104            /* Grab the method ptr directly from what the interpreter sees */
3105            const Method *calleeMethod = mir->meta.callsiteInfo->method;
3106            assert(calleeMethod == cUnit->method->clazz->super->vtable[
3107                                     cUnit->method->clazz->pDvmDex->
3108                                       pResMethods[dInsn->vB]->methodIndex]);
3109
3110            if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
3111                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3112            else
3113                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3114
3115            if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
3116                const Method *calleeMethod = mir->meta.callsiteInfo->method;
3117                void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
3118                assert(calleeAddr);
3119                genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr,
3120                                              retChainingCell);
3121            } else {
3122                /* r0 = calleeMethod */
3123                loadConstant(cUnit, r0, (int) calleeMethod);
3124
3125                genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3126                                         calleeMethod);
3127            }
3128            break;
3129        }
3130        /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3131        case OP_INVOKE_DIRECT:
3132        case OP_INVOKE_DIRECT_RANGE:
3133        case OP_INVOKE_DIRECT_JUMBO: {
3134            /* Grab the method ptr directly from what the interpreter sees */
3135            const Method *calleeMethod = mir->meta.callsiteInfo->method;
3136            assert(calleeMethod ==
3137                   cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
3138
3139            if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT)
3140                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3141            else
3142                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3143
3144            /* r0 = calleeMethod */
3145            loadConstant(cUnit, r0, (int) calleeMethod);
3146
3147            genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3148                                     calleeMethod);
3149            break;
3150        }
3151        /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3152        case OP_INVOKE_STATIC:
3153        case OP_INVOKE_STATIC_RANGE:
3154        case OP_INVOKE_STATIC_JUMBO: {
3155            /* Grab the method ptr directly from what the interpreter sees */
3156            const Method *calleeMethod = mir->meta.callsiteInfo->method;
3157            assert(calleeMethod ==
3158                   cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
3159
3160            if (mir->dalvikInsn.opcode == OP_INVOKE_STATIC)
3161                genProcessArgsNoRange(cUnit, mir, dInsn,
3162                                      NULL /* no null check */);
3163            else
3164                genProcessArgsRange(cUnit, mir, dInsn,
3165                                    NULL /* no null check */);
3166
3167            if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
3168                const Method *calleeMethod = mir->meta.callsiteInfo->method;
3169                void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
3170                assert(calleeAddr);
3171                genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr,
3172                                              retChainingCell);
3173            } else {
3174                /* r0 = calleeMethod */
3175                loadConstant(cUnit, r0, (int) calleeMethod);
3176
3177                genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3178                                         calleeMethod);
3179            }
3180            break;
3181        }
3182        /*
3183         * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3184         *                    BBBB, method, method->clazz->pDvmDex)
3185         *
3186         * The following is an example of generated code for
3187         *      "invoke-interface v0"
3188         *
3189         * -------- dalvik offset: 0x0008 @ invoke-interface v0
3190         * 0x47357e36 : ldr     r0, [r5, #0]   --+
3191         * 0x47357e38 : sub     r7,r5,#24        |
3192         * 0x47357e3c : cmp     r0, #0           | genProcessArgsNoRange
3193         * 0x47357e3e : beq     0x47357e82       |
3194         * 0x47357e40 : stmia   r7, <r0>       --+
3195         * 0x47357e42 : ldr     r4, [pc, #120] --> r4 <- dalvikPC of this invoke
3196         * 0x47357e44 : add     r1, pc, #64    --> r1 <- &retChainingCell
3197         * 0x47357e46 : add     r2, pc, #72    --> r2 <- &predictedChainingCell
3198         * 0x47357e48 : blx_1   0x47348190     --+ TEMPLATE_INVOKE_METHOD_
3199         * 0x47357e4a : blx_2   see above      --+     PREDICTED_CHAIN
3200         * 0x47357e4c : b       0x47357e90     --> off to the predicted chain
3201         * 0x47357e4e : b       0x47357e82     --> punt to the interpreter
3202         * 0x47357e50 : mov     r8, r1         --+
3203         * 0x47357e52 : mov     r9, r2           |
3204         * 0x47357e54 : ldr     r2, [pc, #96]    |
3205         * 0x47357e56 : mov     r10, r3          |
3206         * 0x47357e58 : movs    r0, r3           | dvmFindInterfaceMethodInCache
3207         * 0x47357e5a : ldr     r3, [pc, #88]    |
3208         * 0x47357e5c : ldr     r7, [pc, #80]    |
3209         * 0x47357e5e : mov     r1, #1452        |
3210         * 0x47357e62 : blx     r7             --+
3211         * 0x47357e64 : cmp     r0, #0         --> calleeMethod == NULL?
3212         * 0x47357e66 : bne     0x47357e6e     --> branch over the throw if !r0
3213         * 0x47357e68 : ldr     r0, [pc, #80]  --> load Dalvik PC of the invoke
3214         * 0x47357e6a : blx_1   0x47348494     --+ TEMPLATE_THROW_EXCEPTION_
3215         * 0x47357e6c : blx_2   see above      --+     COMMON
3216         * 0x47357e6e : mov     r1, r8         --> r1 <- &retChainingCell
3217         * 0x47357e70 : cmp     r1, #0         --> compare against 0
3218         * 0x47357e72 : bgt     0x47357e7c     --> >=0? don't rechain
3219         * 0x47357e74 : ldr     r7, [pc, #off] --+
3220         * 0x47357e76 : mov     r2, r9           | dvmJitToPatchPredictedChain
3221         * 0x47357e78 : mov     r3, r10          |
3222         * 0x47357e7a : blx     r7             --+
3223         * 0x47357e7c : add     r1, pc, #8     --> r1 <- &retChainingCell
3224         * 0x47357e7e : blx_1   0x4734809c     --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3225         * 0x47357e80 : blx_2   see above      --+
3226         * -------- reconstruct dalvik PC : 0x425719dc @ +0x0008
3227         * 0x47357e82 : ldr     r0, [pc, #56]
3228         * Exception_Handling:
3229         * 0x47357e84 : ldr     r1, [r6, #92]
3230         * 0x47357e86 : blx     r1
3231         * 0x47357e88 : .align4
3232         * -------- chaining cell (hot): 0x000b
3233         * 0x47357e88 : ldr     r0, [r6, #104]
3234         * 0x47357e8a : blx     r0
3235         * 0x47357e8c : data    0x19e2(6626)
3236         * 0x47357e8e : data    0x4257(16983)
3237         * 0x47357e90 : .align4
3238         * -------- chaining cell (predicted)
3239         * 0x47357e90 : data    0xe7fe(59390)  --> will be patched into bx
3240         * 0x47357e92 : data    0x0000(0)
3241         * 0x47357e94 : data    0x0000(0)      --> class
3242         * 0x47357e96 : data    0x0000(0)
3243         * 0x47357e98 : data    0x0000(0)      --> method
3244         * 0x47357e9a : data    0x0000(0)
3245         * 0x47357e9c : data    0x0000(0)      --> rechain count
3246         * 0x47357e9e : data    0x0000(0)
3247         * -------- end of chaining cells (0x006c)
3248         * 0x47357eb0 : .word (0xad03e369)
3249         * 0x47357eb4 : .word (0x28a90)
3250         * 0x47357eb8 : .word (0x41a63394)
3251         * 0x47357ebc : .word (0x425719dc)
3252         */
3253        case OP_INVOKE_INTERFACE:
3254        case OP_INVOKE_INTERFACE_RANGE:
3255        case OP_INVOKE_INTERFACE_JUMBO: {
3256            ArmLIR *predChainingCell = &labelList[bb->taken->id];
3257
3258            /*
3259             * If the invoke has non-null misPredBranchOver, we need to generate
3260             * the non-inlined version of the invoke here to handle the
3261             * mispredicted case.
3262             */
3263            if (mir->meta.callsiteInfo->misPredBranchOver) {
3264                genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
3265            }
3266
3267            if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
3268                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3269            else
3270                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3271
3272            /* "this" is already left in r0 by genProcessArgs* */
3273
3274            /* r4PC = dalvikCallsite */
3275            loadConstant(cUnit, r4PC,
3276                         (int) (cUnit->method->insns + mir->offset));
3277
3278            /* r1 = &retChainingCell */
3279            ArmLIR *addrRetChain =
3280                opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0);
3281            addrRetChain->generic.target = (LIR *) retChainingCell;
3282
3283            /* r2 = &predictedChainingCell */
3284            ArmLIR *predictedChainingCell =
3285                opRegRegImm(cUnit, kOpAdd, r2, r15pc, 0);
3286            predictedChainingCell->generic.target = (LIR *) predChainingCell;
3287
3288            genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
3289                TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF :
3290                TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3291
3292            /* return through lr - jump to the chaining cell */
3293            genUnconditionalBranch(cUnit, predChainingCell);
3294
3295            /*
3296             * null-check on "this" may have been eliminated, but we still need
3297             * a PC-reconstruction label for stack overflow bailout.
3298             */
3299            if (pcrLabel == NULL) {
3300                int dPC = (int) (cUnit->method->insns + mir->offset);
3301                pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
3302                pcrLabel->opcode = kArmPseudoPCReconstructionCell;
3303                pcrLabel->operands[0] = dPC;
3304                pcrLabel->operands[1] = mir->offset;
3305                /* Insert the place holder to the growable list */
3306                dvmInsertGrowableList(&cUnit->pcReconstructionList,
3307                                      (intptr_t) pcrLabel);
3308            }
3309
3310            /* return through lr+2 - punt to the interpreter */
3311            genUnconditionalBranch(cUnit, pcrLabel);
3312
3313            /*
3314             * return through lr+4 - fully resolve the callee method.
3315             * r1 <- count
3316             * r2 <- &predictedChainCell
3317             * r3 <- this->class
3318             * r4 <- dPC
3319             * r7 <- this->class->vtable
3320             */
3321
3322            /* Save count, &predictedChainCell, and class to high regs first */
3323            genRegCopy(cUnit, r8, r1);
3324            genRegCopy(cUnit, r9, r2);
3325            genRegCopy(cUnit, r10, r3);
3326
3327            /* r0 now contains this->clazz */
3328            genRegCopy(cUnit, r0, r3);
3329
3330            /* r1 = BBBB */
3331            loadConstant(cUnit, r1, dInsn->vB);
3332
3333            /* r2 = method (caller) */
3334            loadConstant(cUnit, r2, (int) cUnit->method);
3335
3336            /* r3 = pDvmDex */
3337            loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3338
3339            LOAD_FUNC_ADDR(cUnit, r7,
3340                           (intptr_t) dvmFindInterfaceMethodInCache);
3341            opReg(cUnit, kOpBlx, r7);
3342            /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3343
3344            dvmCompilerClobberCallRegs(cUnit);
3345            /* generate a branch over if the interface method is resolved */
3346            ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
3347            /*
3348             * calleeMethod == NULL -> throw
3349             */
3350            loadConstant(cUnit, r0,
3351                         (int) (cUnit->method->insns + mir->offset));
3352            genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3353            /* noreturn */
3354
3355            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3356            target->defMask = ENCODE_ALL;
3357            branchOver->generic.target = (LIR *) target;
3358
3359            genRegCopy(cUnit, r1, r8);
3360
3361            /* Check if rechain limit is reached */
3362            ArmLIR *bypassRechaining = genCmpImmBranch(cUnit, kArmCondGt,
3363                                                       r1, 0);
3364
3365            LOAD_FUNC_ADDR(cUnit, r7, (int) dvmJitToPatchPredictedChain);
3366
3367            genRegCopy(cUnit, r1, r6SELF);
3368            genRegCopy(cUnit, r2, r9);
3369            genRegCopy(cUnit, r3, r10);
3370
3371            /*
3372             * r0 = calleeMethod
3373             * r2 = &predictedChainingCell
3374             * r3 = class
3375             *
3376             * &returnChainingCell has been loaded into r1 but is not needed
3377             * when patching the chaining cell and will be clobbered upon
3378             * returning so it will be reconstructed again.
3379             */
3380            opReg(cUnit, kOpBlx, r7);
3381
3382            /* r1 = &retChainingCell */
3383            addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, r15pc, 0);
3384            addrRetChain->generic.target = (LIR *) retChainingCell;
3385
3386            bypassRechaining->generic.target = (LIR *) addrRetChain;
3387
3388            /*
3389             * r0 = this, r1 = calleeMethod,
3390             * r1 = &ChainingCell,
3391             * r4PC = callsiteDPC,
3392             */
3393            genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
3394                TEMPLATE_INVOKE_METHOD_NO_OPT_PROF :
3395                TEMPLATE_INVOKE_METHOD_NO_OPT);
3396#if defined(WITH_JIT_TUNING)
3397            gDvmJit.invokePolymorphic++;
3398#endif
3399            /* Handle exceptions using the interpreter */
3400            genTrap(cUnit, mir->offset, pcrLabel);
3401            break;
3402        }
3403        case OP_INVOKE_OBJECT_INIT_JUMBO:
3404        case OP_INVOKE_OBJECT_INIT_RANGE:
3405        case OP_FILLED_NEW_ARRAY:
3406        case OP_FILLED_NEW_ARRAY_RANGE:
3407        case OP_FILLED_NEW_ARRAY_JUMBO: {
3408            /* Just let the interpreter deal with these */
3409            genInterpSingleStep(cUnit, mir);
3410            break;
3411        }
3412        default:
3413            return true;
3414    }
3415    return false;
3416}
3417
3418static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
3419                               BasicBlock *bb, ArmLIR *labelList)
3420{
3421    ArmLIR *pcrLabel = NULL;
3422
3423    /* An invoke with the MIR_INLINED is effectively a no-op */
3424    if (mir->OptimizationFlags & MIR_INLINED)
3425        return false;
3426
3427    DecodedInstruction *dInsn = &mir->dalvikInsn;
3428    switch (mir->dalvikInsn.opcode) {
3429        /* calleeMethod = this->clazz->vtable[BBBB] */
3430        case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3431        case OP_INVOKE_VIRTUAL_QUICK: {
3432            int methodIndex = dInsn->vB;
3433            ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3434            ArmLIR *predChainingCell = &labelList[bb->taken->id];
3435
3436            /*
3437             * If the invoke has non-null misPredBranchOver, we need to generate
3438             * the non-inlined version of the invoke here to handle the
3439             * mispredicted case.
3440             */
3441            if (mir->meta.callsiteInfo->misPredBranchOver) {
3442                genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
3443            }
3444
3445            if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL_QUICK)
3446                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3447            else
3448                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3449
3450
3451            if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
3452                const Method *calleeMethod = mir->meta.callsiteInfo->method;
3453                void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
3454                assert(calleeAddr);
3455                genInvokeVirtualWholeMethod(cUnit, mir, calleeAddr,
3456                                            retChainingCell);
3457            }
3458
3459            genInvokeVirtualCommon(cUnit, mir, methodIndex,
3460                                   retChainingCell,
3461                                   predChainingCell,
3462                                   pcrLabel);
3463            break;
3464        }
3465        /* calleeMethod = method->clazz->super->vtable[BBBB] */
3466        case OP_INVOKE_SUPER_QUICK:
3467        case OP_INVOKE_SUPER_QUICK_RANGE: {
3468            /* Grab the method ptr directly from what the interpreter sees */
3469            const Method *calleeMethod = mir->meta.callsiteInfo->method;
3470            assert(calleeMethod ==
3471                   cUnit->method->clazz->super->vtable[dInsn->vB]);
3472
3473            if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER_QUICK)
3474                genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3475            else
3476                genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3477
3478            /* r0 = calleeMethod */
3479            loadConstant(cUnit, r0, (int) calleeMethod);
3480
3481            genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3482                                     calleeMethod);
3483            break;
3484        }
3485        default:
3486            return true;
3487    }
3488    return false;
3489}
3490
3491/*
3492 * This operation is complex enough that we'll do it partly inline
3493 * and partly with a handler.  NOTE: the handler uses hardcoded
3494 * values for string object offsets and must be revisitied if the
3495 * layout changes.
3496 */
3497static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
3498{
3499#if defined(USE_GLOBAL_STRING_DEFS)
3500    return handleExecuteInlineC(cUnit, mir);
3501#else
3502    ArmLIR *rollback;
3503    RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
3504    RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1);
3505
3506    loadValueDirectFixed(cUnit, rlThis, r0);
3507    loadValueDirectFixed(cUnit, rlComp, r1);
3508    /* Test objects for NULL */
3509    rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
3510    genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback);
3511    /*
3512     * TUNING: we could check for object pointer equality before invoking
3513     * handler. Unclear whether the gain would be worth the added code size
3514     * expansion.
3515     */
3516    genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
3517    storeValue(cUnit, inlinedTarget(cUnit, mir, false),
3518               dvmCompilerGetReturn(cUnit));
3519    return false;
3520#endif
3521}
3522
3523static bool genInlinedFastIndexOf(CompilationUnit *cUnit, MIR *mir)
3524{
3525#if defined(USE_GLOBAL_STRING_DEFS)
3526    return handleExecuteInlineC(cUnit, mir);
3527#else
3528    RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
3529    RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1);
3530
3531    loadValueDirectFixed(cUnit, rlThis, r0);
3532    loadValueDirectFixed(cUnit, rlChar, r1);
3533    RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
3534    loadValueDirectFixed(cUnit, rlStart, r2);
3535    /* Test objects for NULL */
3536    genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
3537    genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
3538    storeValue(cUnit, inlinedTarget(cUnit, mir, false),
3539               dvmCompilerGetReturn(cUnit));
3540    return false;
3541#endif
3542}
3543
3544// Generates an inlined String.isEmpty or String.length.
3545static bool genInlinedStringIsEmptyOrLength(CompilationUnit *cUnit, MIR *mir,
3546                                            bool isEmpty)
3547{
3548    // dst = src.length();
3549    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
3550    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
3551    rlObj = loadValue(cUnit, rlObj, kCoreReg);
3552    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3553    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
3554    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
3555                 rlResult.lowReg);
3556    if (isEmpty) {
3557        // dst = (dst == 0);
3558        int tReg = dvmCompilerAllocTemp(cUnit);
3559        opRegReg(cUnit, kOpNeg, tReg, rlResult.lowReg);
3560        opRegRegReg(cUnit, kOpAdc, rlResult.lowReg, rlResult.lowReg, tReg);
3561    }
3562    storeValue(cUnit, rlDest, rlResult);
3563    return false;
3564}
3565
3566static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
3567{
3568    return genInlinedStringIsEmptyOrLength(cUnit, mir, false);
3569}
3570
3571static bool genInlinedStringIsEmpty(CompilationUnit *cUnit, MIR *mir)
3572{
3573    return genInlinedStringIsEmptyOrLength(cUnit, mir, true);
3574}
3575
3576static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
3577{
3578    int contents = OFFSETOF_MEMBER(ArrayObject, contents);
3579    RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
3580    RegLocation rlIdx = dvmCompilerGetSrc(cUnit, mir, 1);
3581    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
3582    RegLocation rlResult;
3583    rlObj = loadValue(cUnit, rlObj, kCoreReg);
3584    rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
3585    int regMax = dvmCompilerAllocTemp(cUnit);
3586    int regOff = dvmCompilerAllocTemp(cUnit);
3587    int regPtr = dvmCompilerAllocTemp(cUnit);
3588    ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
3589                                    mir->offset, NULL);
3590    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
3591    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
3592    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
3593    genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
3594    dvmCompilerFreeTemp(cUnit, regMax);
3595    opRegImm(cUnit, kOpAdd, regPtr, contents);
3596    opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
3597    rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3598    loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
3599    storeValue(cUnit, rlDest, rlResult);
3600    return false;
3601}
3602
3603static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
3604{
3605    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
3606    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
3607    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
3608    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3609    int signReg = dvmCompilerAllocTemp(cUnit);
3610    /*
3611     * abs(x) = y<=x>>31, (x+y)^y.
3612     * Thumb2's IT block also yields 3 instructions, but imposes
3613     * scheduling constraints.
3614     */
3615    opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
3616    opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
3617    opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
3618    storeValue(cUnit, rlDest, rlResult);
3619    return false;
3620}
3621
3622static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
3623{
3624    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
3625    RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
3626    rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
3627    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3628    int signReg = dvmCompilerAllocTemp(cUnit);
3629    /*
3630     * abs(x) = y<=x>>31, (x+y)^y.
3631     * Thumb2 IT block allows slightly shorter sequence,
3632     * but introduces a scheduling barrier.  Stick with this
3633     * mechanism for now.
3634     */
3635    opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
3636    opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
3637    opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg);
3638    opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
3639    opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
3640    storeValueWide(cUnit, rlDest, rlResult);
3641    return false;
3642}
3643
3644static bool genInlinedIntFloatConversion(CompilationUnit *cUnit, MIR *mir)
3645{
3646    // Just move from source to destination...
3647    RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
3648    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
3649    storeValue(cUnit, rlDest, rlSrc);
3650    return false;
3651}
3652
3653static bool genInlinedLongDoubleConversion(CompilationUnit *cUnit, MIR *mir)
3654{
3655    // Just move from source to destination...
3656    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
3657    RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
3658    storeValueWide(cUnit, rlDest, rlSrc);
3659    return false;
3660}
3661
3662/*
3663 * JITs a call to a C function.
3664 * TODO: use this for faster native method invocation for simple native
3665 * methods (http://b/3069458).
3666 */
3667static bool handleExecuteInlineC(CompilationUnit *cUnit, MIR *mir)
3668{
3669    DecodedInstruction *dInsn = &mir->dalvikInsn;
3670    int operation = dInsn->vB;
3671    unsigned int i;
3672    const InlineOperation* inLineTable = dvmGetInlineOpsTable();
3673    uintptr_t fn = (int) inLineTable[operation].func;
3674    if (fn == 0) {
3675        dvmCompilerAbort(cUnit);
3676    }
3677    dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
3678    dvmCompilerClobberCallRegs(cUnit);
3679    dvmCompilerClobber(cUnit, r4PC);
3680    dvmCompilerClobber(cUnit, r7);
3681    int offset = offsetof(Thread, interpSave.retval);
3682    opRegRegImm(cUnit, kOpAdd, r4PC, r6SELF, offset);
3683    opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
3684    LOAD_FUNC_ADDR(cUnit, r4PC, fn);
3685    genExportPC(cUnit, mir);
3686    for (i=0; i < dInsn->vA; i++) {
3687        loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i);
3688    }
3689    opReg(cUnit, kOpBlx, r4PC);
3690    opRegImm(cUnit, kOpAdd, r13sp, 8);
3691    /* NULL? */
3692    ArmLIR *branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
3693    loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
3694    genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3695    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3696    target->defMask = ENCODE_ALL;
3697    branchOver->generic.target = (LIR *) target;
3698    return false;
3699}
3700
3701/*
3702 * NOTE: Handles both range and non-range versions (arguments
3703 * have already been normalized by this point).
3704 */
3705static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
3706{
3707    DecodedInstruction *dInsn = &mir->dalvikInsn;
3708    assert(dInsn->opcode == OP_EXECUTE_INLINE_RANGE ||
3709           dInsn->opcode == OP_EXECUTE_INLINE);
3710    switch (dInsn->vB) {
3711        case INLINE_EMPTYINLINEMETHOD:
3712            return false;  /* Nop */
3713
3714        /* These ones we potentially JIT inline. */
3715        case INLINE_STRING_LENGTH:
3716            return genInlinedStringLength(cUnit, mir);
3717        case INLINE_STRING_IS_EMPTY:
3718            return genInlinedStringIsEmpty(cUnit, mir);
3719        case INLINE_MATH_ABS_INT:
3720            return genInlinedAbsInt(cUnit, mir);
3721        case INLINE_MATH_ABS_LONG:
3722            return genInlinedAbsLong(cUnit, mir);
3723        case INLINE_MATH_MIN_INT:
3724            return genInlinedMinMaxInt(cUnit, mir, true);
3725        case INLINE_MATH_MAX_INT:
3726            return genInlinedMinMaxInt(cUnit, mir, false);
3727        case INLINE_STRING_CHARAT:
3728            return genInlinedStringCharAt(cUnit, mir);
3729        case INLINE_MATH_SQRT:
3730            return genInlineSqrt(cUnit, mir);
3731        case INLINE_MATH_ABS_FLOAT:
3732            return genInlinedAbsFloat(cUnit, mir);
3733        case INLINE_MATH_ABS_DOUBLE:
3734            return genInlinedAbsDouble(cUnit, mir);
3735        case INLINE_STRING_COMPARETO:
3736            return genInlinedCompareTo(cUnit, mir);
3737        case INLINE_STRING_FASTINDEXOF_II:
3738            return genInlinedFastIndexOf(cUnit, mir);
3739        case INLINE_FLOAT_TO_RAW_INT_BITS:
3740        case INLINE_INT_BITS_TO_FLOAT:
3741            return genInlinedIntFloatConversion(cUnit, mir);
3742        case INLINE_DOUBLE_TO_RAW_LONG_BITS:
3743        case INLINE_LONG_BITS_TO_DOUBLE:
3744            return genInlinedLongDoubleConversion(cUnit, mir);
3745
3746        /*
3747         * These ones we just JIT a call to a C function for.
3748         * TODO: special-case these in the other "invoke" call paths.
3749         */
3750        case INLINE_STRING_EQUALS:
3751        case INLINE_MATH_COS:
3752        case INLINE_MATH_SIN:
3753        case INLINE_FLOAT_TO_INT_BITS:
3754        case INLINE_DOUBLE_TO_LONG_BITS:
3755            return handleExecuteInlineC(cUnit, mir);
3756    }
3757    dvmCompilerAbort(cUnit);
3758    return false; // Not reachable; keeps compiler happy.
3759}
3760
3761static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3762{
3763    //TUNING: We're using core regs here - not optimal when target is a double
3764    RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
3765    RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3766    loadConstantNoClobber(cUnit, rlResult.lowReg,
3767                          mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3768    loadConstantNoClobber(cUnit, rlResult.highReg,
3769                          (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3770    storeValueWide(cUnit, rlDest, rlResult);
3771    return false;
3772}
3773
3774/*
3775 * The following are special processing routines that handle transfer of
3776 * controls between compiled code and the interpreter. Certain VM states like
3777 * Dalvik PC and special-purpose registers are reconstructed here.
3778 */
3779
3780/*
3781 * Insert a
3782 *    b   .+4
3783 *    nop
3784 * pair at the beginning of a chaining cell.  This serves as the
3785 * switch branch that selects between reverting to the interpreter or
3786 * not.  Once the cell is chained to a translation, the cell will
3787 * contain a 32-bit branch.  Subsequent chain/unchain operations will
3788 * then only alter that first 16-bits - the "b .+4" for unchaining,
3789 * and the restoration of the first half of the 32-bit branch for
3790 * rechaining.
3791 */
3792static void insertChainingSwitch(CompilationUnit *cUnit)
3793{
3794    ArmLIR *branch = newLIR0(cUnit, kThumbBUncond);
3795    newLIR2(cUnit, kThumbOrr, r0, r0);
3796    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3797    target->defMask = ENCODE_ALL;
3798    branch->generic.target = (LIR *) target;
3799}
3800
3801/* Chaining cell for code that may need warmup. */
3802static void handleNormalChainingCell(CompilationUnit *cUnit,
3803                                     unsigned int offset)
3804{
3805    /*
3806     * Use raw instruction constructors to guarantee that the generated
3807     * instructions fit the predefined cell size.
3808     */
3809    insertChainingSwitch(cUnit);
3810    newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF,
3811            offsetof(Thread,
3812                     jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3813    newLIR1(cUnit, kThumbBlxR, r0);
3814    addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
3815}
3816
3817/*
3818 * Chaining cell for instructions that immediately following already translated
3819 * code.
3820 */
3821static void handleHotChainingCell(CompilationUnit *cUnit,
3822                                  unsigned int offset)
3823{
3824    /*
3825     * Use raw instruction constructors to guarantee that the generated
3826     * instructions fit the predefined cell size.
3827     */
3828    insertChainingSwitch(cUnit);
3829    newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF,
3830            offsetof(Thread,
3831                     jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2);
3832    newLIR1(cUnit, kThumbBlxR, r0);
3833    addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
3834}
3835
3836/* Chaining cell for branches that branch back into the same basic block */
3837static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3838                                             unsigned int offset)
3839{
3840    /*
3841     * Use raw instruction constructors to guarantee that the generated
3842     * instructions fit the predefined cell size.
3843     */
3844    insertChainingSwitch(cUnit);
3845#if defined(WITH_SELF_VERIFICATION)
3846    newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF,
3847        offsetof(Thread,
3848                 jitToInterpEntries.dvmJitToInterpBackwardBranch) >> 2);
3849#else
3850    newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF,
3851        offsetof(Thread, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3852#endif
3853    newLIR1(cUnit, kThumbBlxR, r0);
3854    addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
3855}
3856
3857/* Chaining cell for monomorphic method invocations. */
3858static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3859                                              const Method *callee)
3860{
3861    /*
3862     * Use raw instruction constructors to guarantee that the generated
3863     * instructions fit the predefined cell size.
3864     */
3865    insertChainingSwitch(cUnit);
3866    newLIR3(cUnit, kThumbLdrRRI5, r0, r6SELF,
3867            offsetof(Thread,
3868                     jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2);
3869    newLIR1(cUnit, kThumbBlxR, r0);
3870    addWordData(cUnit, NULL, (int) (callee->insns));
3871}
3872
3873/* Chaining cell for monomorphic method invocations. */
3874static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3875{
3876
3877    /* Should not be executed in the initial state */
3878    addWordData(cUnit, NULL, PREDICTED_CHAIN_BX_PAIR_INIT);
3879    /* To be filled: class */
3880    addWordData(cUnit, NULL, PREDICTED_CHAIN_CLAZZ_INIT);
3881    /* To be filled: method */
3882    addWordData(cUnit, NULL, PREDICTED_CHAIN_METHOD_INIT);
3883    /*
3884     * Rechain count. The initial value of 0 here will trigger chaining upon
3885     * the first invocation of this callsite.
3886     */
3887    addWordData(cUnit, NULL, PREDICTED_CHAIN_COUNTER_INIT);
3888}
3889
3890/* Load the Dalvik PC into r0 and jump to the specified target */
3891static void handlePCReconstruction(CompilationUnit *cUnit,
3892                                   ArmLIR *targetLabel)
3893{
3894    ArmLIR **pcrLabel =
3895        (ArmLIR **) cUnit->pcReconstructionList.elemList;
3896    int numElems = cUnit->pcReconstructionList.numUsed;
3897    int i;
3898
3899    /*
3900     * We should never reach here through fall-through code, so insert
3901     * a bomb to signal troubles immediately.
3902     */
3903    if (numElems) {
3904        newLIR0(cUnit, kThumbUndefined);
3905    }
3906
3907    for (i = 0; i < numElems; i++) {
3908        dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3909        /* r0 = dalvik PC */
3910        loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3911        genUnconditionalBranch(cUnit, targetLabel);
3912    }
3913}
3914
3915static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
3916    "kMirOpPhi",
3917    "kMirOpNullNRangeUpCheck",
3918    "kMirOpNullNRangeDownCheck",
3919    "kMirOpLowerBound",
3920    "kMirOpPunt",
3921    "kMirOpCheckInlinePrediction",
3922};
3923
3924/*
3925 * vA = arrayReg;
3926 * vB = idxReg;
3927 * vC = endConditionReg;
3928 * arg[0] = maxC
3929 * arg[1] = minC
3930 * arg[2] = loopBranchConditionCode
3931 */
3932static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3933{
3934    /*
3935     * NOTE: these synthesized blocks don't have ssa names assigned
3936     * for Dalvik registers.  However, because they dominate the following
3937     * blocks we can simply use the Dalvik name w/ subscript 0 as the
3938     * ssa name.
3939     */
3940    DecodedInstruction *dInsn = &mir->dalvikInsn;
3941    const int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
3942    const int maxC = dInsn->arg[0];
3943    int regLength;
3944    RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3945    RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
3946
3947    /* regArray <- arrayRef */
3948    rlArray = loadValue(cUnit, rlArray, kCoreReg);
3949    rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
3950    genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
3951                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3952
3953    /* regLength <- len(arrayRef) */
3954    regLength = dvmCompilerAllocTemp(cUnit);
3955    loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
3956
3957    int delta = maxC;
3958    /*
3959     * If the loop end condition is ">=" instead of ">", then the largest value
3960     * of the index is "endCondition - 1".
3961     */
3962    if (dInsn->arg[2] == OP_IF_GE) {
3963        delta--;
3964    }
3965
3966    if (delta) {
3967        int tReg = dvmCompilerAllocTemp(cUnit);
3968        opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
3969        rlIdxEnd.lowReg = tReg;
3970        dvmCompilerFreeTemp(cUnit, tReg);
3971    }
3972    /* Punt if "regIdxEnd < len(Array)" is false */
3973    genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
3974                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3975}
3976
3977/*
3978 * vA = arrayReg;
3979 * vB = idxReg;
3980 * vC = endConditionReg;
3981 * arg[0] = maxC
3982 * arg[1] = minC
3983 * arg[2] = loopBranchConditionCode
3984 */
3985static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3986{
3987    DecodedInstruction *dInsn = &mir->dalvikInsn;
3988    const int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
3989    const int regLength = dvmCompilerAllocTemp(cUnit);
3990    const int maxC = dInsn->arg[0];
3991    RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3992    RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
3993
3994    /* regArray <- arrayRef */
3995    rlArray = loadValue(cUnit, rlArray, kCoreReg);
3996    rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
3997    genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
3998                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3999
4000    /* regLength <- len(arrayRef) */
4001    loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
4002
4003    if (maxC) {
4004        int tReg = dvmCompilerAllocTemp(cUnit);
4005        opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
4006        rlIdxInit.lowReg = tReg;
4007        dvmCompilerFreeTemp(cUnit, tReg);
4008    }
4009
4010    /* Punt if "regIdxInit < len(Array)" is false */
4011    genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
4012                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4013}
4014
4015/*
4016 * vA = idxReg;
4017 * vB = minC;
4018 */
4019static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
4020{
4021    DecodedInstruction *dInsn = &mir->dalvikInsn;
4022    const int minC = dInsn->vB;
4023    RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
4024
4025    /* regIdx <- initial index value */
4026    rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
4027
4028    /* Punt if "regIdxInit + minC >= 0" is false */
4029    genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
4030                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4031}
4032
4033/*
4034 * vC = this
4035 *
4036 * A predicted inlining target looks like the following, where instructions
4037 * between 0x4858de66 and 0x4858de72 are checking if the predicted class
4038 * matches "this", and the verificaion code is generated by this routine.
4039 *
4040 * (C) means the instruction is inlined from the callee, and (PI) means the
4041 * instruction is the predicted inlined invoke, whose corresponding
4042 * instructions are still generated to handle the mispredicted case.
4043 *
4044 * D/dalvikvm(   86): -------- kMirOpCheckInlinePrediction
4045 * D/dalvikvm(   86): 0x4858de66 (0002): ldr     r0, [r5, #68]
4046 * D/dalvikvm(   86): 0x4858de68 (0004): ldr     r1, [pc, #140]
4047 * D/dalvikvm(   86): 0x4858de6a (0006): cmp     r0, #0
4048 * D/dalvikvm(   86): 0x4858de6c (0008): beq     0x4858deb2
4049 * D/dalvikvm(   86): 0x4858de6e (000a): ldr     r2, [r0, #0]
4050 * D/dalvikvm(   86): 0x4858de70 (000c): cmp     r1, r2
4051 * D/dalvikvm(   86): 0x4858de72 (000e): bne     0x4858de7a
4052 * D/dalvikvm(   86): -------- dalvik offset: 0x004c @ +iget-object-quick (C)
4053 * v4, v17, (#8)
4054 * D/dalvikvm(   86): 0x4858de74 (0010): ldr     r3, [r0, #8]
4055 * D/dalvikvm(   86): 0x4858de76 (0012): str     r3, [r5, #16]
4056 * D/dalvikvm(   86): -------- dalvik offset: 0x004c @
4057 * +invoke-virtual-quick/range (PI) v17..v17
4058 * D/dalvikvm(   86): 0x4858de78 (0014): b       0x4858debc
4059 * D/dalvikvm(   86): 0x4858de7a (0016): add     r4,r5,#68
4060 * D/dalvikvm(   86): -------- BARRIER
4061 * D/dalvikvm(   86): 0x4858de7e (001a): ldmia   r4, <r0>
4062 * D/dalvikvm(   86): -------- BARRIER
4063 * D/dalvikvm(   86): 0x4858de80 (001c): sub     r7,r5,#24
4064 * D/dalvikvm(   86): 0x4858de84 (0020): cmp     r0, #0
4065 * D/dalvikvm(   86): 0x4858de86 (0022): beq     0x4858deb6
4066 * D/dalvikvm(   86): -------- BARRIER
4067 * D/dalvikvm(   86): 0x4858de88 (0024): stmia   r7, <r0>
4068 * D/dalvikvm(   86): -------- BARRIER
4069 * D/dalvikvm(   86): 0x4858de8a (0026): ldr     r4, [pc, #104]
4070 * D/dalvikvm(   86): 0x4858de8c (0028): add     r1, pc, #28
4071 * D/dalvikvm(   86): 0x4858de8e (002a): add     r2, pc, #56
4072 * D/dalvikvm(   86): 0x4858de90 (002c): blx_1   0x48589198
4073 * D/dalvikvm(   86): 0x4858de92 (002e): blx_2   see above
4074 * D/dalvikvm(   86): 0x4858de94 (0030): b       0x4858dec8
4075 * D/dalvikvm(   86): 0x4858de96 (0032): b       0x4858deb6
4076 * D/dalvikvm(   86): 0x4858de98 (0034): ldr     r0, [r7, #72]
4077 * D/dalvikvm(   86): 0x4858de9a (0036): cmp     r1, #0
4078 * D/dalvikvm(   86): 0x4858de9c (0038): bgt     0x4858dea4
4079 * D/dalvikvm(   86): 0x4858de9e (003a): ldr     r7, [r6, #116]
4080 * D/dalvikvm(   86): 0x4858dea0 (003c): movs    r1, r6
4081 * D/dalvikvm(   86): 0x4858dea2 (003e): blx     r7
4082 * D/dalvikvm(   86): 0x4858dea4 (0040): add     r1, pc, #4
4083 * D/dalvikvm(   86): 0x4858dea6 (0042): blx_1   0x485890a0
4084 * D/dalvikvm(   86): 0x4858dea8 (0044): blx_2   see above
4085 * D/dalvikvm(   86): 0x4858deaa (0046): b       0x4858deb6
4086 * D/dalvikvm(   86): 0x4858deac (0048): .align4
4087 * D/dalvikvm(   86): L0x004f:
4088 * D/dalvikvm(   86): -------- dalvik offset: 0x004f @ move-result-object (PI)
4089 * v4, (#0), (#0)
4090 * D/dalvikvm(   86): 0x4858deac (0048): ldr     r4, [r6, #8]
4091 * D/dalvikvm(   86): 0x4858deae (004a): str     r4, [r5, #16]
4092 * D/dalvikvm(   86): 0x4858deb0 (004c): b       0x4858debc
4093 * D/dalvikvm(   86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
4094 * D/dalvikvm(   86): 0x4858deb2 (004e): ldr     r0, [pc, #64]
4095 * D/dalvikvm(   86): 0x4858deb4 (0050): b       0x4858deb8
4096 * D/dalvikvm(   86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
4097 * D/dalvikvm(   86): 0x4858deb6 (0052): ldr     r0, [pc, #60]
4098 * D/dalvikvm(   86): Exception_Handling:
4099 * D/dalvikvm(   86): 0x4858deb8 (0054): ldr     r1, [r6, #100]
4100 * D/dalvikvm(   86): 0x4858deba (0056): blx     r1
4101 * D/dalvikvm(   86): 0x4858debc (0058): .align4
4102 * D/dalvikvm(   86): -------- chaining cell (hot): 0x0050
4103 * D/dalvikvm(   86): 0x4858debc (0058): b       0x4858dec0
4104 * D/dalvikvm(   86): 0x4858debe (005a): orrs    r0, r0
4105 * D/dalvikvm(   86): 0x4858dec0 (005c): ldr     r0, [r6, #112]
4106 * D/dalvikvm(   86): 0x4858dec2 (005e): blx     r0
4107 * D/dalvikvm(   86): 0x4858dec4 (0060): data    0xefd4(61396)
4108 * D/dalvikvm(   86): 0x4858dec6 (0062): data    0x42be(17086)
4109 * D/dalvikvm(   86): 0x4858dec8 (0064): .align4
4110 * D/dalvikvm(   86): -------- chaining cell (predicted)
4111 * D/dalvikvm(   86): 0x4858dec8 (0064): data    0xe7fe(59390)
4112 * D/dalvikvm(   86): 0x4858deca (0066): data    0x0000(0)
4113 * D/dalvikvm(   86): 0x4858decc (0068): data    0x0000(0)
4114 * D/dalvikvm(   86): 0x4858dece (006a): data    0x0000(0)
4115 * :
4116 */
4117static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir)
4118{
4119    CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
4120    RegLocation rlThis = cUnit->regLocation[mir->dalvikInsn.vC];
4121
4122    rlThis = loadValue(cUnit, rlThis, kCoreReg);
4123    int regPredictedClass = dvmCompilerAllocTemp(cUnit);
4124    loadClassPointer(cUnit, regPredictedClass, (int) callsiteInfo);
4125    genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset,
4126                 NULL);/* null object? */
4127    int regActualClass = dvmCompilerAllocTemp(cUnit);
4128    loadWordDisp(cUnit, rlThis.lowReg, offsetof(Object, clazz), regActualClass);
4129    opRegReg(cUnit, kOpCmp, regPredictedClass, regActualClass);
4130    /*
4131     * Set the misPredBranchOver target so that it will be generated when the
4132     * code for the non-optimized invoke is generated.
4133     */
4134    callsiteInfo->misPredBranchOver = (LIR *) opCondBranch(cUnit, kArmCondNe);
4135}
4136
4137/* Extended MIR instructions like PHI */
4138static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
4139{
4140    int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
4141    char *msg = (char *)dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
4142                                        false);
4143    strcpy(msg, extendedMIROpNames[opOffset]);
4144    newLIR1(cUnit, kArmPseudoExtended, (int) msg);
4145
4146    switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
4147        case kMirOpPhi: {
4148            char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
4149            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
4150            break;
4151        }
4152        case kMirOpNullNRangeUpCheck: {
4153            genHoistedChecksForCountUpLoop(cUnit, mir);
4154            break;
4155        }
4156        case kMirOpNullNRangeDownCheck: {
4157            genHoistedChecksForCountDownLoop(cUnit, mir);
4158            break;
4159        }
4160        case kMirOpLowerBound: {
4161            genHoistedLowerBoundCheck(cUnit, mir);
4162            break;
4163        }
4164        case kMirOpPunt: {
4165            genUnconditionalBranch(cUnit,
4166                                   (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4167            break;
4168        }
4169        case kMirOpCheckInlinePrediction: {
4170            genValidationForPredictedInline(cUnit, mir);
4171            break;
4172        }
4173        default:
4174            break;
4175    }
4176}
4177
4178/*
4179 * Create a PC-reconstruction cell for the starting offset of this trace.
4180 * Since the PCR cell is placed near the end of the compiled code which is
4181 * usually out of range for a conditional branch, we put two branches (one
4182 * branch over to the loop body and one layover branch to the actual PCR) at the
4183 * end of the entry block.
4184 */
4185static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
4186                                ArmLIR *bodyLabel)
4187{
4188    /* Set up the place holder to reconstruct this Dalvik PC */
4189    ArmLIR *pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
4190    pcrLabel->opcode = kArmPseudoPCReconstructionCell;
4191    pcrLabel->operands[0] =
4192        (int) (cUnit->method->insns + entry->startOffset);
4193    pcrLabel->operands[1] = entry->startOffset;
4194    /* Insert the place holder to the growable list */
4195    dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel);
4196
4197    /*
4198     * Next, create two branches - one branch over to the loop body and the
4199     * other branch to the PCR cell to punt.
4200     */
4201    ArmLIR *branchToBody = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
4202    branchToBody->opcode = kThumbBUncond;
4203    branchToBody->generic.target = (LIR *) bodyLabel;
4204    setupResourceMasks(branchToBody);
4205    cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
4206
4207    ArmLIR *branchToPCR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
4208    branchToPCR->opcode = kThumbBUncond;
4209    branchToPCR->generic.target = (LIR *) pcrLabel;
4210    setupResourceMasks(branchToPCR);
4211    cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
4212}
4213
4214#if defined(WITH_SELF_VERIFICATION)
4215static bool selfVerificationPuntOps(MIR *mir)
4216{
4217    DecodedInstruction *decInsn = &mir->dalvikInsn;
4218
4219    /*
4220     * All opcodes that can throw exceptions and use the
4221     * TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace
4222     * under self-verification mode.
4223     */
4224    switch (decInsn->opcode) {
4225        case OP_MONITOR_ENTER:
4226        case OP_MONITOR_EXIT:
4227        case OP_NEW_INSTANCE:
4228        case OP_NEW_INSTANCE_JUMBO:
4229        case OP_NEW_ARRAY:
4230        case OP_NEW_ARRAY_JUMBO:
4231        case OP_CHECK_CAST:
4232        case OP_CHECK_CAST_JUMBO:
4233        case OP_MOVE_EXCEPTION:
4234        case OP_FILL_ARRAY_DATA:
4235        case OP_EXECUTE_INLINE:
4236        case OP_EXECUTE_INLINE_RANGE:
4237            return true;
4238        default:
4239            return false;
4240    }
4241}
4242#endif
4243
4244void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
4245{
4246    /* Used to hold the labels of each block */
4247    ArmLIR *labelList =
4248        (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
4249    ArmLIR *headLIR = NULL;
4250    GrowableList chainingListByType[kChainingCellGap];
4251    int i;
4252
4253    /*
4254     * Initialize various types chaining lists.
4255     */
4256    for (i = 0; i < kChainingCellGap; i++) {
4257        dvmInitGrowableList(&chainingListByType[i], 2);
4258    }
4259
4260    /* Clear the visited flag for each block */
4261    dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerClearVisitedFlag,
4262                                          kAllNodes, false /* isIterative */);
4263
4264    GrowableListIterator iterator;
4265    dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
4266
4267    /* Traces start with a profiling entry point.  Generate it here */
4268    cUnit->profileCodeSize = genTraceProfileEntry(cUnit);
4269
4270    /* Handle the content in each basic block */
4271    for (i = 0; ; i++) {
4272        MIR *mir;
4273        BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
4274        if (bb == NULL) break;
4275        if (bb->visited == true) continue;
4276
4277        labelList[i].operands[0] = bb->startOffset;
4278
4279        if (bb->blockType >= kChainingCellGap) {
4280            if (bb->isFallThroughFromInvoke == true) {
4281                /* Align this block first since it is a return chaining cell */
4282                newLIR0(cUnit, kArmPseudoPseudoAlign4);
4283            }
4284            /*
4285             * Append the label pseudo LIR first. Chaining cells will be handled
4286             * separately afterwards.
4287             */
4288            dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
4289        }
4290
4291        if (bb->blockType == kEntryBlock) {
4292            labelList[i].opcode = kArmPseudoEntryBlock;
4293            if (bb->firstMIRInsn == NULL) {
4294                continue;
4295            } else {
4296              setupLoopEntryBlock(cUnit, bb,
4297                                  &labelList[bb->fallThrough->id]);
4298            }
4299        } else if (bb->blockType == kExitBlock) {
4300            labelList[i].opcode = kArmPseudoExitBlock;
4301            goto gen_fallthrough;
4302        } else if (bb->blockType == kDalvikByteCode) {
4303            if (bb->hidden == true) continue;
4304            labelList[i].opcode = kArmPseudoNormalBlockLabel;
4305            /* Reset the register state */
4306            dvmCompilerResetRegPool(cUnit);
4307            dvmCompilerClobberAllRegs(cUnit);
4308            dvmCompilerResetNullCheck(cUnit);
4309        } else {
4310            switch (bb->blockType) {
4311                case kChainingCellNormal:
4312                    labelList[i].opcode = kArmPseudoChainingCellNormal;
4313                    /* handle the codegen later */
4314                    dvmInsertGrowableList(
4315                        &chainingListByType[kChainingCellNormal], i);
4316                    break;
4317                case kChainingCellInvokeSingleton:
4318                    labelList[i].opcode =
4319                        kArmPseudoChainingCellInvokeSingleton;
4320                    labelList[i].operands[0] =
4321                        (int) bb->containingMethod;
4322                    /* handle the codegen later */
4323                    dvmInsertGrowableList(
4324                        &chainingListByType[kChainingCellInvokeSingleton], i);
4325                    break;
4326                case kChainingCellInvokePredicted:
4327                    labelList[i].opcode =
4328                        kArmPseudoChainingCellInvokePredicted;
4329                    /*
4330                     * Move the cached method pointer from operand 1 to 0.
4331                     * Operand 0 was clobbered earlier in this routine to store
4332                     * the block starting offset, which is not applicable to
4333                     * predicted chaining cell.
4334                     */
4335                    labelList[i].operands[0] = labelList[i].operands[1];
4336                    /* handle the codegen later */
4337                    dvmInsertGrowableList(
4338                        &chainingListByType[kChainingCellInvokePredicted], i);
4339                    break;
4340                case kChainingCellHot:
4341                    labelList[i].opcode =
4342                        kArmPseudoChainingCellHot;
4343                    /* handle the codegen later */
4344                    dvmInsertGrowableList(
4345                        &chainingListByType[kChainingCellHot], i);
4346                    break;
4347                case kPCReconstruction:
4348                    /* Make sure exception handling block is next */
4349                    labelList[i].opcode =
4350                        kArmPseudoPCReconstructionBlockLabel;
4351                    handlePCReconstruction(cUnit,
4352                                           &labelList[cUnit->puntBlock->id]);
4353                    break;
4354                case kExceptionHandling:
4355                    labelList[i].opcode = kArmPseudoEHBlockLabel;
4356                    if (cUnit->pcReconstructionList.numUsed) {
4357                        loadWordDisp(cUnit, r6SELF, offsetof(Thread,
4358                                     jitToInterpEntries.dvmJitToInterpPunt),
4359                                     r1);
4360                        opReg(cUnit, kOpBlx, r1);
4361                    }
4362                    break;
4363                case kChainingCellBackwardBranch:
4364                    labelList[i].opcode =
4365                        kArmPseudoChainingCellBackwardBranch;
4366                    /* handle the codegen later */
4367                    dvmInsertGrowableList(
4368                        &chainingListByType[kChainingCellBackwardBranch],
4369                        i);
4370                    break;
4371                default:
4372                    break;
4373            }
4374            continue;
4375        }
4376
4377        /*
4378         * Try to build a longer optimization unit. Currently if the previous
4379         * block ends with a goto, we continue adding instructions and don't
4380         * reset the register allocation pool.
4381         */
4382        for (BasicBlock *nextBB = bb; nextBB != NULL; nextBB = cUnit->nextCodegenBlock) {
4383            bb = nextBB;
4384            bb->visited = true;
4385            cUnit->nextCodegenBlock = NULL;
4386
4387            for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
4388
4389                dvmCompilerResetRegPool(cUnit);
4390                if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
4391                    dvmCompilerClobberAllRegs(cUnit);
4392                }
4393
4394                if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
4395                    dvmCompilerResetDefTracking(cUnit);
4396                }
4397
4398                if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
4399                    handleExtendedMIR(cUnit, mir);
4400                    continue;
4401                }
4402
4403                Opcode dalvikOpcode = mir->dalvikInsn.opcode;
4404                InstructionFormat dalvikFormat =
4405                    dexGetFormatFromOpcode(dalvikOpcode);
4406                const char *note;
4407                if (mir->OptimizationFlags & MIR_INLINED) {
4408                    note = " (I)";
4409                } else if (mir->OptimizationFlags & MIR_INLINED_PRED) {
4410                    note = " (PI)";
4411                } else if (mir->OptimizationFlags & MIR_CALLEE) {
4412                    note = " (C)";
4413                } else {
4414                    note = NULL;
4415                }
4416
4417                ArmLIR *boundaryLIR;
4418
4419                /*
4420                 * Don't generate the boundary LIR unless we are debugging this
4421                 * trace or we need a scheduling barrier.
4422                 */
4423                if (headLIR == NULL || cUnit->printMe == true) {
4424                    boundaryLIR =
4425                        newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary,
4426                                mir->offset,
4427                                (int) dvmCompilerGetDalvikDisassembly(
4428                                    &mir->dalvikInsn, note));
4429                    /* Remember the first LIR for this block */
4430                    if (headLIR == NULL) {
4431                        headLIR = boundaryLIR;
4432                        /* Set the first boundaryLIR as a scheduling barrier */
4433                        headLIR->defMask = ENCODE_ALL;
4434                    }
4435                }
4436
4437                /*
4438                 * Don't generate the SSA annotation unless verbose mode is on
4439                 */
4440                if (cUnit->printMe && mir->ssaRep) {
4441                    char *ssaString = dvmCompilerGetSSAString(cUnit,
4442                                                              mir->ssaRep);
4443                    newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
4444                }
4445
4446                bool notHandled;
4447                /*
4448                 * Debugging: screen the opcode first to see if it is in the
4449                 * do[-not]-compile list
4450                 */
4451                bool singleStepMe = SINGLE_STEP_OP(dalvikOpcode);
4452#if defined(WITH_SELF_VERIFICATION)
4453              if (singleStepMe == false) {
4454                  singleStepMe = selfVerificationPuntOps(mir);
4455              }
4456#endif
4457                if (singleStepMe || cUnit->allSingleStep) {
4458                    notHandled = false;
4459                    genInterpSingleStep(cUnit, mir);
4460                } else {
4461                    opcodeCoverage[dalvikOpcode]++;
4462                    switch (dalvikFormat) {
4463                        case kFmt10t:
4464                        case kFmt20t:
4465                        case kFmt30t:
4466                            notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
4467                                      mir, bb, labelList);
4468                            break;
4469                        case kFmt10x:
4470                            notHandled = handleFmt10x(cUnit, mir);
4471                            break;
4472                        case kFmt11n:
4473                        case kFmt31i:
4474                            notHandled = handleFmt11n_Fmt31i(cUnit, mir);
4475                            break;
4476                        case kFmt11x:
4477                            notHandled = handleFmt11x(cUnit, mir);
4478                            break;
4479                        case kFmt12x:
4480                            notHandled = handleFmt12x(cUnit, mir);
4481                            break;
4482                        case kFmt20bc:
4483                        case kFmt40sc:
4484                            notHandled = handleFmt20bc_Fmt40sc(cUnit, mir);
4485                            break;
4486                        case kFmt21c:
4487                        case kFmt31c:
4488                        case kFmt41c:
4489                            notHandled = handleFmt21c_Fmt31c_Fmt41c(cUnit, mir);
4490                            break;
4491                        case kFmt21h:
4492                            notHandled = handleFmt21h(cUnit, mir);
4493                            break;
4494                        case kFmt21s:
4495                            notHandled = handleFmt21s(cUnit, mir);
4496                            break;
4497                        case kFmt21t:
4498                            notHandled = handleFmt21t(cUnit, mir, bb,
4499                                                      labelList);
4500                            break;
4501                        case kFmt22b:
4502                        case kFmt22s:
4503                            notHandled = handleFmt22b_Fmt22s(cUnit, mir);
4504                            break;
4505                        case kFmt22c:
4506                        case kFmt52c:
4507                            notHandled = handleFmt22c_Fmt52c(cUnit, mir);
4508                            break;
4509                        case kFmt22cs:
4510                            notHandled = handleFmt22cs(cUnit, mir);
4511                            break;
4512                        case kFmt22t:
4513                            notHandled = handleFmt22t(cUnit, mir, bb,
4514                                                      labelList);
4515                            break;
4516                        case kFmt22x:
4517                        case kFmt32x:
4518                            notHandled = handleFmt22x_Fmt32x(cUnit, mir);
4519                            break;
4520                        case kFmt23x:
4521                            notHandled = handleFmt23x(cUnit, mir);
4522                            break;
4523                        case kFmt31t:
4524                            notHandled = handleFmt31t(cUnit, mir);
4525                            break;
4526                        case kFmt3rc:
4527                        case kFmt35c:
4528                        case kFmt5rc:
4529                            notHandled = handleFmt35c_3rc_5rc(cUnit, mir, bb,
4530                                                          labelList);
4531                            break;
4532                        case kFmt3rms:
4533                        case kFmt35ms:
4534                            notHandled = handleFmt35ms_3rms(cUnit, mir, bb,
4535                                                            labelList);
4536                            break;
4537                        case kFmt35mi:
4538                        case kFmt3rmi:
4539                            notHandled = handleExecuteInline(cUnit, mir);
4540                            break;
4541                        case kFmt51l:
4542                            notHandled = handleFmt51l(cUnit, mir);
4543                            break;
4544                        default:
4545                            notHandled = true;
4546                            break;
4547                    }
4548                }
4549                if (notHandled) {
4550                    LOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled",
4551                         mir->offset,
4552                         dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
4553                         dalvikFormat);
4554                    dvmCompilerAbort(cUnit);
4555                    break;
4556                }
4557            }
4558        }
4559
4560        if (bb->blockType == kEntryBlock) {
4561            dvmCompilerAppendLIR(cUnit,
4562                                 (LIR *) cUnit->loopAnalysis->branchToBody);
4563            dvmCompilerAppendLIR(cUnit,
4564                                 (LIR *) cUnit->loopAnalysis->branchToPCR);
4565        }
4566
4567        if (headLIR) {
4568            /*
4569             * Eliminate redundant loads/stores and delay stores into later
4570             * slots
4571             */
4572            dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4573                                               cUnit->lastLIRInsn);
4574            /* Reset headLIR which is also the optimization boundary */
4575            headLIR = NULL;
4576        }
4577
4578gen_fallthrough:
4579        /*
4580         * Check if the block is terminated due to trace length constraint -
4581         * insert an unconditional branch to the chaining cell.
4582         */
4583        if (bb->needFallThroughBranch) {
4584            genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
4585        }
4586    }
4587
4588    /* Handle the chaining cells in predefined order */
4589    for (i = 0; i < kChainingCellGap; i++) {
4590        size_t j;
4591        int *blockIdList = (int *) chainingListByType[i].elemList;
4592
4593        cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4594
4595        /* No chaining cells of this type */
4596        if (cUnit->numChainingCells[i] == 0)
4597            continue;
4598
4599        /* Record the first LIR for a new type of chaining cell */
4600        cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4601
4602        for (j = 0; j < chainingListByType[i].numUsed; j++) {
4603            int blockId = blockIdList[j];
4604            BasicBlock *chainingBlock =
4605                (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
4606                                                         blockId);
4607
4608            /* Align this chaining cell first */
4609            newLIR0(cUnit, kArmPseudoPseudoAlign4);
4610
4611            /* Insert the pseudo chaining instruction */
4612            dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4613
4614
4615            switch (chainingBlock->blockType) {
4616                case kChainingCellNormal:
4617                    handleNormalChainingCell(cUnit, chainingBlock->startOffset);
4618                    break;
4619                case kChainingCellInvokeSingleton:
4620                    handleInvokeSingletonChainingCell(cUnit,
4621                        chainingBlock->containingMethod);
4622                    break;
4623                case kChainingCellInvokePredicted:
4624                    handleInvokePredictedChainingCell(cUnit);
4625                    break;
4626                case kChainingCellHot:
4627                    handleHotChainingCell(cUnit, chainingBlock->startOffset);
4628                    break;
4629                case kChainingCellBackwardBranch:
4630                    handleBackwardBranchChainingCell(cUnit,
4631                        chainingBlock->startOffset);
4632                    break;
4633                default:
4634                    LOGE("Bad blocktype %d", chainingBlock->blockType);
4635                    dvmCompilerAbort(cUnit);
4636            }
4637        }
4638    }
4639
4640    /* Mark the bottom of chaining cells */
4641    cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kArmChainingCellBottom);
4642
4643    /*
4644     * Generate the branch to the dvmJitToInterpNoChain entry point at the end
4645     * of all chaining cells for the overflow cases.
4646     */
4647    if (cUnit->switchOverflowPad) {
4648        loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad);
4649        loadWordDisp(cUnit, r6SELF, offsetof(Thread,
4650                     jitToInterpEntries.dvmJitToInterpNoChain), r2);
4651        opRegReg(cUnit, kOpAdd, r1, r1);
4652        opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
4653#if defined(WITH_JIT_TUNING)
4654        loadConstant(cUnit, r0, kSwitchOverflow);
4655#endif
4656        opReg(cUnit, kOpBlx, r2);
4657    }
4658
4659    dvmCompilerApplyGlobalOptimizations(cUnit);
4660
4661#if defined(WITH_SELF_VERIFICATION)
4662    selfVerificationBranchInsertPass(cUnit);
4663#endif
4664}
4665
4666/*
4667 * Accept the work and start compiling.  Returns true if compilation
4668 * is attempted.
4669 */
4670bool dvmCompilerDoWork(CompilerWorkOrder *work)
4671{
4672    JitTraceDescription *desc;
4673    bool isCompile;
4674    bool success = true;
4675
4676    if (gDvmJit.codeCacheFull) {
4677        return false;
4678    }
4679
4680    switch (work->kind) {
4681        case kWorkOrderTrace:
4682            isCompile = true;
4683            /* Start compilation with maximally allowed trace length */
4684            desc = (JitTraceDescription *)work->info;
4685            success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
4686                                        work->bailPtr, 0 /* no hints */);
4687            break;
4688        case kWorkOrderTraceDebug: {
4689            bool oldPrintMe = gDvmJit.printMe;
4690            gDvmJit.printMe = true;
4691            isCompile = true;
4692            /* Start compilation with maximally allowed trace length */
4693            desc = (JitTraceDescription *)work->info;
4694            success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
4695                                        work->bailPtr, 0 /* no hints */);
4696            gDvmJit.printMe = oldPrintMe;
4697            break;
4698        }
4699        case kWorkOrderProfileMode:
4700            dvmJitChangeProfileMode((TraceProfilingModes)(int)work->info);
4701            isCompile = false;
4702            break;
4703        default:
4704            isCompile = false;
4705            LOGE("Jit: unknown work order type");
4706            assert(0);  // Bail if debug build, discard otherwise
4707    }
4708    if (!success)
4709        work->result.codeAddress = NULL;
4710    return isCompile;
4711}
4712
4713/* Architectural-specific debugging helpers go here */
4714void dvmCompilerArchDump(void)
4715{
4716    /* Print compiled opcode in this VM instance */
4717    int i, start, streak;
4718    char buf[1024];
4719
4720    streak = i = 0;
4721    buf[0] = 0;
4722    while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
4723        i++;
4724    }
4725    if (i == kNumPackedOpcodes) {
4726        return;
4727    }
4728    for (start = i++, streak = 1; i < kNumPackedOpcodes; i++) {
4729        if (opcodeCoverage[i]) {
4730            streak++;
4731        } else {
4732            if (streak == 1) {
4733                sprintf(buf+strlen(buf), "%x,", start);
4734            } else {
4735                sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4736            }
4737            streak = 0;
4738            while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
4739                i++;
4740            }
4741            if (i < kNumPackedOpcodes) {
4742                streak = 1;
4743                start = i;
4744            }
4745        }
4746    }
4747    if (streak) {
4748        if (streak == 1) {
4749            sprintf(buf+strlen(buf), "%x", start);
4750        } else {
4751            sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4752        }
4753    }
4754    if (strlen(buf)) {
4755        LOGD("dalvik.vm.jit.op = %s", buf);
4756    }
4757}
4758
4759/* Common initialization routine for an architecture family */
4760bool dvmCompilerArchInit()
4761{
4762    int i;
4763
4764    for (i = 0; i < kArmLast; i++) {
4765        if (EncodingMap[i].opcode != i) {
4766            LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
4767                 EncodingMap[i].name, i, EncodingMap[i].opcode);
4768            dvmAbort();  // OK to dvmAbort - build error
4769        }
4770    }
4771
4772    return dvmCompilerArchVariantInit();
4773}
4774
4775void *dvmCompilerGetInterpretTemplate()
4776{
4777      return (void*) ((int)gDvmJit.codeCache +
4778                      templateEntryOffsets[TEMPLATE_INTERPRET]);
4779}
4780
4781JitInstructionSetType dvmCompilerGetInterpretTemplateSet()
4782{
4783    return DALVIK_JIT_ARM;
4784}
4785
4786/* Needed by the Assembler */
4787void dvmCompilerSetupResourceMasks(ArmLIR *lir)
4788{
4789    setupResourceMasks(lir);
4790}
4791
4792/* Needed by the ld/st optmizatons */
4793ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
4794{
4795    return genRegCopyNoInsert(cUnit, rDest, rSrc);
4796}
4797
4798/* Needed by the register allocator */
4799ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
4800{
4801    return genRegCopy(cUnit, rDest, rSrc);
4802}
4803
4804/* Needed by the register allocator */
4805void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
4806                            int srcLo, int srcHi)
4807{
4808    genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
4809}
4810
4811void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
4812                             int displacement, int rSrc, OpSize size)
4813{
4814    storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
4815}
4816
4817void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
4818                                 int displacement, int rSrcLo, int rSrcHi)
4819{
4820    storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
4821}
4822