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