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