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