OSDN Git Service

Jit: Sapphire tuning - mostly scheduling.
[android-x86/dalvik.git] / vm / compiler / codegen / arm / CodegenDriver.c
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * This file contains codegen and support common to all supported
19  * ARM variants.  It is included by:
20  *
21  *        Codegen-$(TARGET_ARCH_VARIANT).c
22  *
23  * which combines this common code with specific support found in the
24  * applicable directory below this one.
25  */
26
27 static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
28                                      int srcSize, int tgtSize)
29 {
30     /*
31      * Don't optimize the register usage since it calls out to template
32      * functions
33      */
34     RegLocation rlSrc;
35     RegLocation rlDest;
36     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
37     if (srcSize == 1) {
38         rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
39         loadValueDirectFixed(cUnit, rlSrc, r0);
40     } else {
41         rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
42         loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
43     }
44     loadConstant(cUnit, r2, (int)funct);
45     opReg(cUnit, kOpBlx, r2);
46     dvmCompilerClobberCallRegs(cUnit);
47     if (tgtSize == 1) {
48         RegLocation rlResult;
49         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
50         rlResult = dvmCompilerGetReturn(cUnit);
51         storeValue(cUnit, rlDest, rlResult);
52     } else {
53         RegLocation rlResult;
54         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
55         rlResult = dvmCompilerGetReturnWide(cUnit);
56         storeValueWide(cUnit, rlDest, rlResult);
57     }
58     return false;
59 }
60
61
62 static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
63                                     RegLocation rlDest, RegLocation rlSrc1,
64                                     RegLocation rlSrc2)
65 {
66     RegLocation rlResult;
67     void* funct;
68
69     /* TODO: use a proper include file to define these */
70     float __aeabi_fadd(float a, float b);
71     float __aeabi_fsub(float a, float b);
72     float __aeabi_fdiv(float a, float b);
73     float __aeabi_fmul(float a, float b);
74     float fmodf(float a, float b);
75
76     switch (mir->dalvikInsn.opCode) {
77         case OP_ADD_FLOAT_2ADDR:
78         case OP_ADD_FLOAT:
79             funct = (void*) __aeabi_fadd;
80             break;
81         case OP_SUB_FLOAT_2ADDR:
82         case OP_SUB_FLOAT:
83             funct = (void*) __aeabi_fsub;
84             break;
85         case OP_DIV_FLOAT_2ADDR:
86         case OP_DIV_FLOAT:
87             funct = (void*) __aeabi_fdiv;
88             break;
89         case OP_MUL_FLOAT_2ADDR:
90         case OP_MUL_FLOAT:
91             funct = (void*) __aeabi_fmul;
92             break;
93         case OP_REM_FLOAT_2ADDR:
94         case OP_REM_FLOAT:
95             funct = (void*) fmodf;
96             break;
97         case OP_NEG_FLOAT: {
98             genNegFloat(cUnit, rlDest, rlSrc1);
99             return false;
100         }
101         default:
102             return true;
103     }
104     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
105     loadValueDirectFixed(cUnit, rlSrc1, r0);
106     loadValueDirectFixed(cUnit, rlSrc2, r1);
107     loadConstant(cUnit, r2, (int)funct);
108     opReg(cUnit, kOpBlx, r2);
109     dvmCompilerClobberCallRegs(cUnit);
110     rlResult = dvmCompilerGetReturn(cUnit);
111     storeValue(cUnit, rlDest, rlResult);
112     return false;
113 }
114
115 static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
116                                      RegLocation rlDest, RegLocation rlSrc1,
117                                      RegLocation rlSrc2)
118 {
119     RegLocation rlResult;
120     void* funct;
121
122     /* TODO: use a proper include file to define these */
123     double __aeabi_dadd(double a, double b);
124     double __aeabi_dsub(double a, double b);
125     double __aeabi_ddiv(double a, double b);
126     double __aeabi_dmul(double a, double b);
127     double fmod(double a, double b);
128
129     switch (mir->dalvikInsn.opCode) {
130         case OP_ADD_DOUBLE_2ADDR:
131         case OP_ADD_DOUBLE:
132             funct = (void*) __aeabi_dadd;
133             break;
134         case OP_SUB_DOUBLE_2ADDR:
135         case OP_SUB_DOUBLE:
136             funct = (void*) __aeabi_dsub;
137             break;
138         case OP_DIV_DOUBLE_2ADDR:
139         case OP_DIV_DOUBLE:
140             funct = (void*) __aeabi_ddiv;
141             break;
142         case OP_MUL_DOUBLE_2ADDR:
143         case OP_MUL_DOUBLE:
144             funct = (void*) __aeabi_dmul;
145             break;
146         case OP_REM_DOUBLE_2ADDR:
147         case OP_REM_DOUBLE:
148             funct = (void*) fmod;
149             break;
150         case OP_NEG_DOUBLE: {
151             genNegDouble(cUnit, rlDest, rlSrc1);
152             return false;
153         }
154         default:
155             return true;
156     }
157     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
158     loadConstant(cUnit, rlr, (int)funct);
159     loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
160     loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
161     opReg(cUnit, kOpBlx, rlr);
162     dvmCompilerClobberCallRegs(cUnit);
163     rlResult = dvmCompilerGetReturnWide(cUnit);
164     storeValueWide(cUnit, rlDest, rlResult);
165     return false;
166 }
167
168 static 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)
211 static 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
222 static 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 */
245 static 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 */
253 static 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 */
280 static 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  */
306 static 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  */
333 static 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  */
357 static 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  */
429 static 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
503 static 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
536 static 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         dvmCompilerClobberCallRegs(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
636 static 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         dvmCompilerClobberCallRegs(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
763 static 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 */
822 static 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 */
832 static 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_* */
840 static 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
860 static 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
893 static 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  */
986 static 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  */
1048 static 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  */
1156 static 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 */
1208 static 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  */
1223 static 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  */
1257 static 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         opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */
1280         ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
1281         loadConstant(cUnit, r0,
1282                      (int) (cUnit->method->insns + mir->offset +
1283                      dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_EXIT)));
1284         genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1285         ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1286         target->defMask = ENCODE_ALL;
1287         branchOver->generic.target = (LIR *) target;
1288         dvmCompilerClobberCallRegs(cUnit);
1289     }
1290 }
1291
1292 /*
1293  * The following are the first-level codegen routines that analyze the format
1294  * of each bytecode then either dispatch special purpose codegen routines
1295  * or produce corresponding Thumb instructions directly.
1296  */
1297
1298 static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
1299                                        BasicBlock *bb, ArmLIR *labelList)
1300 {
1301     /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1302     genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1303     return false;
1304 }
1305
1306 static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1307 {
1308     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1309     if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1310         ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EB))) {
1311         LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1312         return true;
1313     }
1314     switch (dalvikOpCode) {
1315         case OP_RETURN_VOID:
1316             genReturnCommon(cUnit,mir);
1317             break;
1318         case OP_UNUSED_73:
1319         case OP_UNUSED_79:
1320         case OP_UNUSED_7A:
1321             LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1322             return true;
1323         case OP_NOP:
1324             break;
1325         default:
1326             return true;
1327     }
1328     return false;
1329 }
1330
1331 static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1332 {
1333     RegLocation rlDest;
1334     RegLocation rlResult;
1335     if (mir->ssaRep->numDefs == 2) {
1336         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1337     } else {
1338         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1339     }
1340
1341     switch (mir->dalvikInsn.opCode) {
1342         case OP_CONST:
1343         case OP_CONST_4: {
1344             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1345             loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1346             storeValue(cUnit, rlDest, rlResult);
1347             break;
1348         }
1349         case OP_CONST_WIDE_32: {
1350             //TUNING: single routine to load constant pair for support doubles
1351             //TUNING: load 0/-1 separately to avoid load dependency
1352             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1353             loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1354             opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1355                         rlResult.lowReg, 31);
1356             storeValueWide(cUnit, rlDest, rlResult);
1357             break;
1358         }
1359         default:
1360             return true;
1361     }
1362     return false;
1363 }
1364
1365 static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1366 {
1367     RegLocation rlDest;
1368     RegLocation rlResult;
1369     if (mir->ssaRep->numDefs == 2) {
1370         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1371     } else {
1372         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1373     }
1374     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1375
1376     switch (mir->dalvikInsn.opCode) {
1377         case OP_CONST_HIGH16: {
1378             loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
1379             storeValue(cUnit, rlDest, rlResult);
1380             break;
1381         }
1382         case OP_CONST_WIDE_HIGH16: {
1383             loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1384                                   0, mir->dalvikInsn.vB << 16);
1385             storeValueWide(cUnit, rlDest, rlResult);
1386             break;
1387         }
1388         default:
1389             return true;
1390     }
1391     return false;
1392 }
1393
1394 static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1395 {
1396     /* For OP_THROW_VERIFICATION_ERROR */
1397     genInterpSingleStep(cUnit, mir);
1398     return false;
1399 }
1400
1401 static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1402 {
1403     RegLocation rlResult;
1404     RegLocation rlDest;
1405     RegLocation rlSrc;
1406
1407     switch (mir->dalvikInsn.opCode) {
1408         case OP_CONST_STRING_JUMBO:
1409         case OP_CONST_STRING: {
1410             void *strPtr = (void*)
1411               (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1412             assert(strPtr != NULL);
1413             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1414             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1415             loadConstantValue(cUnit, rlResult.lowReg, (int) strPtr );
1416             storeValue(cUnit, rlDest, rlResult);
1417             break;
1418         }
1419         case OP_CONST_CLASS: {
1420             void *classPtr = (void*)
1421               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1422             assert(classPtr != NULL);
1423             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1424             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1425             loadConstantValue(cUnit, rlResult.lowReg, (int) classPtr );
1426             storeValue(cUnit, rlDest, rlResult);
1427             break;
1428         }
1429         case OP_SGET_OBJECT:
1430         case OP_SGET_BOOLEAN:
1431         case OP_SGET_CHAR:
1432         case OP_SGET_BYTE:
1433         case OP_SGET_SHORT:
1434         case OP_SGET: {
1435             int valOffset = offsetof(StaticField, value);
1436             int tReg = dvmCompilerAllocTemp(cUnit);
1437             void *fieldPtr = (void*)
1438               (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1439             assert(fieldPtr != NULL);
1440             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1441             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1442             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
1443 #if defined(WITH_SELF_VERIFICATION)
1444             cUnit->heapMemOp = true;
1445 #endif
1446             loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
1447 #if defined(WITH_SELF_VERIFICATION)
1448             cUnit->heapMemOp = false;
1449 #endif
1450             storeValue(cUnit, rlDest, rlResult);
1451             break;
1452         }
1453         case OP_SGET_WIDE: {
1454             int valOffset = offsetof(StaticField, value);
1455             void *fieldPtr = (void*)
1456               (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1457             int tReg = dvmCompilerAllocTemp(cUnit);
1458             assert(fieldPtr != NULL);
1459             rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1460             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1461             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
1462 #if defined(WITH_SELF_VERIFICATION)
1463             cUnit->heapMemOp = true;
1464 #endif
1465             loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
1466 #if defined(WITH_SELF_VERIFICATION)
1467             cUnit->heapMemOp = false;
1468 #endif
1469             storeValueWide(cUnit, rlDest, rlResult);
1470             break;
1471         }
1472         case OP_SPUT_OBJECT:
1473         case OP_SPUT_BOOLEAN:
1474         case OP_SPUT_CHAR:
1475         case OP_SPUT_BYTE:
1476         case OP_SPUT_SHORT:
1477         case OP_SPUT: {
1478             int valOffset = offsetof(StaticField, value);
1479             int tReg = dvmCompilerAllocTemp(cUnit);
1480             void *fieldPtr = (void*)
1481               (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1482
1483             assert(fieldPtr != NULL);
1484             rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1485             rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1486             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
1487 #if defined(WITH_SELF_VERIFICATION)
1488             cUnit->heapMemOp = true;
1489 #endif
1490             storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
1491 #if defined(WITH_SELF_VERIFICATION)
1492             cUnit->heapMemOp = false;
1493 #endif
1494             break;
1495         }
1496         case OP_SPUT_WIDE: {
1497             int tReg = dvmCompilerAllocTemp(cUnit);
1498             int valOffset = offsetof(StaticField, value);
1499             void *fieldPtr = (void*)
1500               (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1501
1502             assert(fieldPtr != NULL);
1503             rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1504             rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1505             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
1506 #if defined(WITH_SELF_VERIFICATION)
1507             cUnit->heapMemOp = true;
1508 #endif
1509             storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
1510 #if defined(WITH_SELF_VERIFICATION)
1511             cUnit->heapMemOp = false;
1512 #endif
1513             break;
1514         }
1515         case OP_NEW_INSTANCE: {
1516             /*
1517              * Obey the calling convention and don't mess with the register
1518              * usage.
1519              */
1520             ClassObject *classPtr = (void*)
1521               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1522             assert(classPtr != NULL);
1523             assert(classPtr->status & CLASS_INITIALIZED);
1524             /*
1525              * If it is going to throw, it should not make to the trace to begin
1526              * with.  However, Alloc might throw, so we need to genExportPC()
1527              */
1528             assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
1529             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
1530             genExportPC(cUnit, mir);
1531             loadConstant(cUnit, r2, (int)dvmAllocObject);
1532             loadConstant(cUnit, r0, (int) classPtr);
1533             loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
1534             opReg(cUnit, kOpBlx, r2);
1535             dvmCompilerClobberCallRegs(cUnit);
1536             /* generate a branch over if allocation is successful */
1537             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
1538             ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
1539             /*
1540              * OOM exception needs to be thrown here and cannot re-execute
1541              */
1542             loadConstant(cUnit, r0,
1543                          (int) (cUnit->method->insns + mir->offset));
1544             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1545             /* noreturn */
1546
1547             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1548             target->defMask = ENCODE_ALL;
1549             branchOver->generic.target = (LIR *) target;
1550             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1551             rlResult = dvmCompilerGetReturn(cUnit);
1552             storeValue(cUnit, rlDest, rlResult);
1553             break;
1554         }
1555         case OP_CHECK_CAST: {
1556             /*
1557              * Obey the calling convention and don't mess with the register
1558              * usage.
1559              */
1560             ClassObject *classPtr =
1561               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1562             /*
1563              * Note: It is possible that classPtr is NULL at this point,
1564              * even though this instruction has been successfully interpreted.
1565              * If the previous interpretation had a null source, the
1566              * interpreter would not have bothered to resolve the clazz.
1567              * Bail out to the interpreter in this case, and log it
1568              * so that we can tell if it happens frequently.
1569              */
1570             if (classPtr == NULL) {
1571                  LOGD("null clazz in OP_CHECK_CAST, single-stepping");
1572                  genInterpSingleStep(cUnit, mir);
1573                  return false;
1574             }
1575             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
1576             loadConstant(cUnit, r1, (int) classPtr );
1577             rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1578             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1579             opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);   /* Null? */
1580             ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
1581             /*
1582              *  rlSrc.lowReg now contains object->clazz.  Note that
1583              *  it could have been allocated r0, but we're okay so long
1584              *  as we don't do anything desctructive until r0 is loaded
1585              *  with clazz.
1586              */
1587             /* r0 now contains object->clazz */
1588             loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
1589             loadConstant(cUnit, r2, (int)dvmInstanceofNonTrivial);
1590             opRegReg(cUnit, kOpCmp, r0, r1);
1591             ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
1592             opReg(cUnit, kOpBlx, r2);
1593             dvmCompilerClobberCallRegs(cUnit);
1594             /*
1595              * If null, check cast failed - punt to the interpreter.  Because
1596              * interpreter will be the one throwing, we don't need to
1597              * genExportPC() here.
1598              */
1599             genZeroCheck(cUnit, r0, mir->offset, NULL);
1600             /* check cast passed - branch target here */
1601             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1602             target->defMask = ENCODE_ALL;
1603             branch1->generic.target = (LIR *)target;
1604             branch2->generic.target = (LIR *)target;
1605             break;
1606         }
1607         default:
1608             return true;
1609     }
1610     return false;
1611 }
1612
1613 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1614 {
1615     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1616     RegLocation rlResult;
1617     switch (dalvikOpCode) {
1618         case OP_MOVE_EXCEPTION: {
1619             int offset = offsetof(InterpState, self);
1620             int exOffset = offsetof(Thread, exception);
1621             int selfReg = dvmCompilerAllocTemp(cUnit);
1622             int resetReg = dvmCompilerAllocTemp(cUnit);
1623             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1624             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1625             loadWordDisp(cUnit, rGLUE, offset, selfReg);
1626             loadConstant(cUnit, resetReg, 0);
1627             loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg);
1628             storeWordDisp(cUnit, selfReg, exOffset, resetReg);
1629             storeValue(cUnit, rlDest, rlResult);
1630            break;
1631         }
1632         case OP_MOVE_RESULT:
1633         case OP_MOVE_RESULT_OBJECT: {
1634             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1635             RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
1636             rlSrc.fp = rlDest.fp;
1637             storeValue(cUnit, rlDest, rlSrc);
1638             break;
1639         }
1640         case OP_MOVE_RESULT_WIDE: {
1641             RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1642             RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
1643             rlSrc.fp = rlDest.fp;
1644             storeValueWide(cUnit, rlDest, rlSrc);
1645             break;
1646         }
1647         case OP_RETURN_WIDE: {
1648             RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1649             RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
1650             rlDest.fp = rlSrc.fp;
1651             storeValueWide(cUnit, rlDest, rlSrc);
1652             genReturnCommon(cUnit,mir);
1653             break;
1654         }
1655         case OP_RETURN:
1656         case OP_RETURN_OBJECT: {
1657             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1658             RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
1659             rlDest.fp = rlSrc.fp;
1660             storeValue(cUnit, rlDest, rlSrc);
1661             genReturnCommon(cUnit,mir);
1662             break;
1663         }
1664         case OP_MONITOR_EXIT:
1665         case OP_MONITOR_ENTER:
1666 #if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
1667             genMonitorPortable(cUnit, mir);
1668 #else
1669             genMonitor(cUnit, mir);
1670 #endif
1671             break;
1672         case OP_THROW: {
1673             genInterpSingleStep(cUnit, mir);
1674             break;
1675         }
1676         default:
1677             return true;
1678     }
1679     return false;
1680 }
1681
1682 static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1683 {
1684     OpCode opCode = mir->dalvikInsn.opCode;
1685     RegLocation rlDest;
1686     RegLocation rlSrc;
1687     RegLocation rlResult;
1688
1689     if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1690         return genArithOp( cUnit, mir );
1691     }
1692
1693     if (mir->ssaRep->numUses == 2)
1694         rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1695     else
1696         rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1697     if (mir->ssaRep->numDefs == 2)
1698         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1699     else
1700         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1701
1702     switch (opCode) {
1703         case OP_DOUBLE_TO_INT:
1704         case OP_INT_TO_FLOAT:
1705         case OP_FLOAT_TO_INT:
1706         case OP_DOUBLE_TO_FLOAT:
1707         case OP_FLOAT_TO_DOUBLE:
1708         case OP_INT_TO_DOUBLE:
1709         case OP_FLOAT_TO_LONG:
1710         case OP_LONG_TO_FLOAT:
1711         case OP_DOUBLE_TO_LONG:
1712         case OP_LONG_TO_DOUBLE:
1713             return genConversion(cUnit, mir);
1714         case OP_NEG_INT:
1715         case OP_NOT_INT:
1716             return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
1717         case OP_NEG_LONG:
1718         case OP_NOT_LONG:
1719             return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
1720         case OP_NEG_FLOAT:
1721             return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
1722         case OP_NEG_DOUBLE:
1723             return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
1724         case OP_MOVE_WIDE:
1725             storeValueWide(cUnit, rlDest, rlSrc);
1726             break;
1727         case OP_INT_TO_LONG:
1728             rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
1729             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1730             //TUNING: shouldn't loadValueDirect already check for phys reg?
1731             if (rlSrc.location == kLocPhysReg) {
1732                 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
1733             } else {
1734                 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
1735             }
1736             opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1737                         rlResult.lowReg, 31);
1738             storeValueWide(cUnit, rlDest, rlResult);
1739             break;
1740         case OP_LONG_TO_INT:
1741             rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
1742             rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc);
1743             // Intentional fallthrough
1744         case OP_MOVE:
1745         case OP_MOVE_OBJECT:
1746             storeValue(cUnit, rlDest, rlSrc);
1747             break;
1748         case OP_INT_TO_BYTE:
1749             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1750             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1751             opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
1752             storeValue(cUnit, rlDest, rlResult);
1753             break;
1754         case OP_INT_TO_SHORT:
1755             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1756             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1757             opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
1758             storeValue(cUnit, rlDest, rlResult);
1759             break;
1760         case OP_INT_TO_CHAR:
1761             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1762             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1763             opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
1764             storeValue(cUnit, rlDest, rlResult);
1765             break;
1766         case OP_ARRAY_LENGTH: {
1767             int lenOffset = offsetof(ArrayObject, length);
1768             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1769             genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
1770                          mir->offset, NULL);
1771             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1772             loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
1773                          rlResult.lowReg);
1774             storeValue(cUnit, rlDest, rlResult);
1775             break;
1776         }
1777         default:
1778             return true;
1779     }
1780     return false;
1781 }
1782
1783 static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
1784 {
1785     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1786     RegLocation rlDest;
1787     RegLocation rlResult;
1788     int BBBB = mir->dalvikInsn.vB;
1789     if (dalvikOpCode == OP_CONST_WIDE_16) {
1790         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1791         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1792         loadConstantValue(cUnit, rlResult.lowReg, BBBB);
1793         //TUNING: do high separately to avoid load dependency
1794         opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1795         storeValueWide(cUnit, rlDest, rlResult);
1796     } else if (dalvikOpCode == OP_CONST_16) {
1797         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1798         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1799         loadConstantValue(cUnit, rlResult.lowReg, BBBB);
1800         storeValue(cUnit, rlDest, rlResult);
1801     } else
1802         return true;
1803     return false;
1804 }
1805
1806 /* Compare agaist zero */
1807 static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
1808                          ArmLIR *labelList)
1809 {
1810     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1811     ArmConditionCode cond;
1812     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1813     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1814     opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
1815
1816 //TUNING: break this out to allow use of Thumb2 CB[N]Z
1817     switch (dalvikOpCode) {
1818         case OP_IF_EQZ:
1819             cond = kArmCondEq;
1820             break;
1821         case OP_IF_NEZ:
1822             cond = kArmCondNe;
1823             break;
1824         case OP_IF_LTZ:
1825             cond = kArmCondLt;
1826             break;
1827         case OP_IF_GEZ:
1828             cond = kArmCondGe;
1829             break;
1830         case OP_IF_GTZ:
1831             cond = kArmCondGt;
1832             break;
1833         case OP_IF_LEZ:
1834             cond = kArmCondLe;
1835             break;
1836         default:
1837             cond = 0;
1838             LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
1839             dvmAbort();
1840     }
1841     genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1842     /* This mostly likely will be optimized away in a later phase */
1843     genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1844     return false;
1845 }
1846
1847 static bool isPowerOfTwo(int x)
1848 {
1849     return (x & (x - 1)) == 0;
1850 }
1851
1852 // Returns true if no more than two bits are set in 'x'.
1853 static bool isPopCountLE2(unsigned int x)
1854 {
1855     x &= x - 1;
1856     return (x & (x - 1)) == 0;
1857 }
1858
1859 // Returns the index of the lowest set bit in 'x'.
1860 static int lowestSetBit(unsigned int x) {
1861     int bit_posn = 0;
1862     while ((x & 0xf) == 0) {
1863         bit_posn += 4;
1864         x >>= 4;
1865     }
1866     while ((x & 1) == 0) {
1867         bit_posn++;
1868         x >>= 1;
1869     }
1870     return bit_posn;
1871 }
1872
1873 // Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1874 // and store the result in 'rlDest'.
1875 static bool handleEasyMultiply(CompilationUnit *cUnit,
1876                                RegLocation rlSrc, RegLocation rlDest, int lit)
1877 {
1878     // Can we simplify this multiplication?
1879     bool powerOfTwo = false;
1880     bool popCountLE2 = false;
1881     bool powerOfTwoMinusOne = false;
1882     if (lit < 2) {
1883         // Avoid special cases.
1884         return false;
1885     } else if (isPowerOfTwo(lit)) {
1886         powerOfTwo = true;
1887     } else if (isPopCountLE2(lit)) {
1888         popCountLE2 = true;
1889     } else if (isPowerOfTwo(lit + 1)) {
1890         powerOfTwoMinusOne = true;
1891     } else {
1892         return false;
1893     }
1894     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1895     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1896     if (powerOfTwo) {
1897         // Shift.
1898         opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1899                     lowestSetBit(lit));
1900     } else if (popCountLE2) {
1901         // Shift and add and shift.
1902         int firstBit = lowestSetBit(lit);
1903         int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1904         genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1905                                       firstBit, secondBit);
1906     } else {
1907         // Reverse subtract: (src << (shift + 1)) - src.
1908         assert(powerOfTwoMinusOne);
1909         // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1910         int tReg = dvmCompilerAllocTemp(cUnit);
1911         opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1912         opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1913     }
1914     storeValue(cUnit, rlDest, rlResult);
1915     return true;
1916 }
1917
1918 static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
1919 {
1920     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1921     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1922     RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1923     RegLocation rlResult;
1924     int lit = mir->dalvikInsn.vC;
1925     OpKind op = 0;      /* Make gcc happy */
1926     int shiftOp = false;
1927     bool isDiv = false;
1928
1929     int __aeabi_idivmod(int op1, int op2);
1930     int __aeabi_idiv(int op1, int op2);
1931
1932     switch (dalvikOpCode) {
1933         case OP_RSUB_INT_LIT8:
1934         case OP_RSUB_INT: {
1935             int tReg;
1936             //TUNING: add support for use of Arm rsub op
1937             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1938             tReg = dvmCompilerAllocTemp(cUnit);
1939             loadConstant(cUnit, tReg, lit);
1940             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1941             opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1942                         tReg, rlSrc.lowReg);
1943             storeValue(cUnit, rlDest, rlResult);
1944             return false;
1945             break;
1946         }
1947
1948         case OP_ADD_INT_LIT8:
1949         case OP_ADD_INT_LIT16:
1950             op = kOpAdd;
1951             break;
1952         case OP_MUL_INT_LIT8:
1953         case OP_MUL_INT_LIT16: {
1954             if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1955                 return false;
1956             }
1957             op = kOpMul;
1958             break;
1959         }
1960         case OP_AND_INT_LIT8:
1961         case OP_AND_INT_LIT16:
1962             op = kOpAnd;
1963             break;
1964         case OP_OR_INT_LIT8:
1965         case OP_OR_INT_LIT16:
1966             op = kOpOr;
1967             break;
1968         case OP_XOR_INT_LIT8:
1969         case OP_XOR_INT_LIT16:
1970             op = kOpXor;
1971             break;
1972         case OP_SHL_INT_LIT8:
1973             lit &= 31;
1974             shiftOp = true;
1975             op = kOpLsl;
1976             break;
1977         case OP_SHR_INT_LIT8:
1978             lit &= 31;
1979             shiftOp = true;
1980             op = kOpAsr;
1981             break;
1982         case OP_USHR_INT_LIT8:
1983             lit &= 31;
1984             shiftOp = true;
1985             op = kOpLsr;
1986             break;
1987
1988         case OP_DIV_INT_LIT8:
1989         case OP_DIV_INT_LIT16:
1990         case OP_REM_INT_LIT8:
1991         case OP_REM_INT_LIT16:
1992             if (lit == 0) {
1993                 /* Let the interpreter deal with div by 0 */
1994                 genInterpSingleStep(cUnit, mir);
1995                 return false;
1996             }
1997             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
1998             loadValueDirectFixed(cUnit, rlSrc, r0);
1999             dvmCompilerClobber(cUnit, r0);
2000             if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
2001                 (dalvikOpCode == OP_DIV_INT_LIT16)) {
2002                 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2003                 isDiv = true;
2004             } else {
2005                 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2006                 isDiv = false;
2007             }
2008             loadConstant(cUnit, r1, lit);
2009             opReg(cUnit, kOpBlx, r2);
2010             dvmCompilerClobberCallRegs(cUnit);
2011             if (isDiv)
2012                 rlResult = dvmCompilerGetReturn(cUnit);
2013             else
2014                 rlResult = dvmCompilerGetReturnAlt(cUnit);
2015             storeValue(cUnit, rlDest, rlResult);
2016             return false;
2017             break;
2018         default:
2019             return true;
2020     }
2021     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2022     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2023     // Avoid shifts by literal 0 - no support in Thumb.  Change to copy
2024     if (shiftOp && (lit == 0)) {
2025         genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2026     } else {
2027         opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2028     }
2029     storeValue(cUnit, rlDest, rlResult);
2030     return false;
2031 }
2032
2033 static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2034 {
2035     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2036     int fieldOffset;
2037
2038     if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2039         InstField *pInstField = (InstField *)
2040             cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2041
2042         assert(pInstField != NULL);
2043         fieldOffset = pInstField->byteOffset;
2044     } else {
2045         /* Deliberately break the code while make the compiler happy */
2046         fieldOffset = -1;
2047     }
2048     switch (dalvikOpCode) {
2049         case OP_NEW_ARRAY: {
2050             // Generates a call - use explicit registers
2051             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2052             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2053             RegLocation rlResult;
2054             void *classPtr = (void*)
2055               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2056             assert(classPtr != NULL);
2057             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2058             genExportPC(cUnit, mir);
2059             loadValueDirectFixed(cUnit, rlSrc, r1);   /* Len */
2060             loadConstant(cUnit, r0, (int) classPtr );
2061             loadConstant(cUnit, r3, (int)dvmAllocArrayByClass);
2062             /*
2063              * "len < 0": bail to the interpreter to re-execute the
2064              * instruction
2065              */
2066             ArmLIR *pcrLabel =
2067                 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
2068             loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2069             opReg(cUnit, kOpBlx, r3);
2070             dvmCompilerClobberCallRegs(cUnit);
2071             /* generate a branch over if allocation is successful */
2072             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2073             ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
2074             /*
2075              * OOM exception needs to be thrown here and cannot re-execute
2076              */
2077             loadConstant(cUnit, r0,
2078                          (int) (cUnit->method->insns + mir->offset));
2079             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2080             /* noreturn */
2081
2082             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2083             target->defMask = ENCODE_ALL;
2084             branchOver->generic.target = (LIR *) target;
2085             rlResult = dvmCompilerGetReturn(cUnit);
2086             storeValue(cUnit, rlDest, rlResult);
2087             break;
2088         }
2089         case OP_INSTANCE_OF: {
2090             // May generate a call - use explicit registers
2091             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2092             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2093             RegLocation rlResult;
2094             ClassObject *classPtr =
2095               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2096             /*
2097              * Note: It is possible that classPtr is NULL at this point,
2098              * even though this instruction has been successfully interpreted.
2099              * If the previous interpretation had a null source, the
2100              * interpreter would not have bothered to resolve the clazz.
2101              * Bail out to the interpreter in this case, and log it
2102              * so that we can tell if it happens frequently.
2103              */
2104             if (classPtr == NULL) {
2105                 LOGD("null clazz in OP_INSTANCE_OF, single-stepping");
2106                 genInterpSingleStep(cUnit, mir);
2107                 break;
2108             }
2109             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2110             loadValueDirectFixed(cUnit, rlSrc, r0);  /* Ref */
2111             loadConstant(cUnit, r2, (int) classPtr );
2112 //TUNING: compare to 0 primative to allow use of CB[N]Z
2113             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2114             /* When taken r0 has NULL which can be used for store directly */
2115             ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
2116             /* r1 now contains object->clazz */
2117             loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
2118             /* r1 now contains object->clazz */
2119             loadConstant(cUnit, r3, (int)dvmInstanceofNonTrivial);
2120             loadConstant(cUnit, r0, 1);                /* Assume true */
2121             opRegReg(cUnit, kOpCmp, r1, r2);
2122             ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
2123             genRegCopy(cUnit, r0, r1);
2124             genRegCopy(cUnit, r1, r2);
2125             opReg(cUnit, kOpBlx, r3);
2126             dvmCompilerClobberCallRegs(cUnit);
2127             /* branch target here */
2128             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2129             target->defMask = ENCODE_ALL;
2130             rlResult = dvmCompilerGetReturn(cUnit);
2131             storeValue(cUnit, rlDest, rlResult);
2132             branch1->generic.target = (LIR *)target;
2133             branch2->generic.target = (LIR *)target;
2134             break;
2135         }
2136         case OP_IGET_WIDE:
2137             genIGetWide(cUnit, mir, fieldOffset);
2138             break;
2139         case OP_IGET:
2140         case OP_IGET_OBJECT:
2141             genIGet(cUnit, mir, kWord, fieldOffset);
2142             break;
2143         case OP_IGET_BOOLEAN:
2144             genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
2145             break;
2146         case OP_IGET_BYTE:
2147             genIGet(cUnit, mir, kSignedByte, fieldOffset);
2148             break;
2149         case OP_IGET_CHAR:
2150             genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
2151             break;
2152         case OP_IGET_SHORT:
2153             genIGet(cUnit, mir, kSignedHalf, fieldOffset);
2154             break;
2155         case OP_IPUT_WIDE:
2156             genIPutWide(cUnit, mir, fieldOffset);
2157             break;
2158         case OP_IPUT:
2159         case OP_IPUT_OBJECT:
2160             genIPut(cUnit, mir, kWord, fieldOffset);
2161             break;
2162         case OP_IPUT_SHORT:
2163         case OP_IPUT_CHAR:
2164             genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
2165             break;
2166         case OP_IPUT_BYTE:
2167         case OP_IPUT_BOOLEAN:
2168             genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
2169             break;
2170         default:
2171             return true;
2172     }
2173     return false;
2174 }
2175
2176 static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2177 {
2178     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2179     int fieldOffset =  mir->dalvikInsn.vC;
2180     switch (dalvikOpCode) {
2181         case OP_IGET_QUICK:
2182         case OP_IGET_OBJECT_QUICK:
2183             genIGet(cUnit, mir, kWord, fieldOffset);
2184             break;
2185         case OP_IPUT_QUICK:
2186         case OP_IPUT_OBJECT_QUICK:
2187             genIPut(cUnit, mir, kWord, fieldOffset);
2188             break;
2189         case OP_IGET_WIDE_QUICK:
2190             genIGetWide(cUnit, mir, fieldOffset);
2191             break;
2192         case OP_IPUT_WIDE_QUICK:
2193             genIPutWide(cUnit, mir, fieldOffset);
2194             break;
2195         default:
2196             return true;
2197     }
2198     return false;
2199
2200 }
2201
2202 /* Compare agaist zero */
2203 static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2204                          ArmLIR *labelList)
2205 {
2206     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2207     ArmConditionCode cond;
2208     RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2209     RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
2210
2211     rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
2212     rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
2213     opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
2214
2215     switch (dalvikOpCode) {
2216         case OP_IF_EQ:
2217             cond = kArmCondEq;
2218             break;
2219         case OP_IF_NE:
2220             cond = kArmCondNe;
2221             break;
2222         case OP_IF_LT:
2223             cond = kArmCondLt;
2224             break;
2225         case OP_IF_GE:
2226             cond = kArmCondGe;
2227             break;
2228         case OP_IF_GT:
2229             cond = kArmCondGt;
2230             break;
2231         case OP_IF_LE:
2232             cond = kArmCondLe;
2233             break;
2234         default:
2235             cond = 0;
2236             LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2237             dvmAbort();
2238     }
2239     genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2240     /* This mostly likely will be optimized away in a later phase */
2241     genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2242     return false;
2243 }
2244
2245 static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2246 {
2247     OpCode opCode = mir->dalvikInsn.opCode;
2248
2249     switch (opCode) {
2250         case OP_MOVE_16:
2251         case OP_MOVE_OBJECT_16:
2252         case OP_MOVE_FROM16:
2253         case OP_MOVE_OBJECT_FROM16: {
2254             storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0),
2255                        dvmCompilerGetSrc(cUnit, mir, 0));
2256             break;
2257         }
2258         case OP_MOVE_WIDE_16:
2259         case OP_MOVE_WIDE_FROM16: {
2260             storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1),
2261                            dvmCompilerGetSrcWide(cUnit, mir, 0, 1));
2262             break;
2263         }
2264         default:
2265             return true;
2266     }
2267     return false;
2268 }
2269
2270 static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2271 {
2272     OpCode opCode = mir->dalvikInsn.opCode;
2273     RegLocation rlSrc1;
2274     RegLocation rlSrc2;
2275     RegLocation rlDest;
2276
2277     if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2278         return genArithOp( cUnit, mir );
2279     }
2280
2281     /* APUTs have 3 sources and no targets */
2282     if (mir->ssaRep->numDefs == 0) {
2283         if (mir->ssaRep->numUses == 3) {
2284             rlDest = dvmCompilerGetSrc(cUnit, mir, 0);
2285             rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1);
2286             rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
2287         } else {
2288             assert(mir->ssaRep->numUses == 4);
2289             rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2290             rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2);
2291             rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3);
2292         }
2293     } else {
2294         /* Two sources and 1 dest.  Deduce the operand sizes */
2295         if (mir->ssaRep->numUses == 4) {
2296             rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2297             rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
2298         } else {
2299             assert(mir->ssaRep->numUses == 2);
2300             rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2301             rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
2302         }
2303         if (mir->ssaRep->numDefs == 2) {
2304             rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
2305         } else {
2306             assert(mir->ssaRep->numDefs == 1);
2307             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2308         }
2309     }
2310
2311
2312     switch (opCode) {
2313         case OP_CMPL_FLOAT:
2314         case OP_CMPG_FLOAT:
2315         case OP_CMPL_DOUBLE:
2316         case OP_CMPG_DOUBLE:
2317             return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2318         case OP_CMP_LONG:
2319             genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2320             break;
2321         case OP_AGET_WIDE:
2322             genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
2323             break;
2324         case OP_AGET:
2325         case OP_AGET_OBJECT:
2326             genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
2327             break;
2328         case OP_AGET_BOOLEAN:
2329             genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
2330             break;
2331         case OP_AGET_BYTE:
2332             genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
2333             break;
2334         case OP_AGET_CHAR:
2335             genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2336             break;
2337         case OP_AGET_SHORT:
2338             genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2339             break;
2340         case OP_APUT_WIDE:
2341             genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
2342             break;
2343         case OP_APUT:
2344         case OP_APUT_OBJECT:
2345             genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
2346             break;
2347         case OP_APUT_SHORT:
2348         case OP_APUT_CHAR:
2349             genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2350             break;
2351         case OP_APUT_BYTE:
2352         case OP_APUT_BOOLEAN:
2353             genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
2354             break;
2355         default:
2356             return true;
2357     }
2358     return false;
2359 }
2360
2361 /*
2362  * Find the matching case.
2363  *
2364  * return values:
2365  * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
2366  *    including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
2367  * r1 (high 32-bit): the branch offset of the matching case (only for indexes
2368  *    above MAX_CHAINED_SWITCH_CASES).
2369  *
2370  * Instructions around the call are:
2371  *
2372  * mov r2, pc
2373  * blx &findPackedSwitchIndex
2374  * mov pc, r0
2375  * .align4
2376  * chaining cell for case 0 [8 bytes]
2377  * chaining cell for case 1 [8 bytes]
2378  *               :
2379  * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [8 bytes]
2380  * chaining cell for case default [8 bytes]
2381  * noChain exit
2382  */
2383 s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
2384 {
2385     int size;
2386     int firstKey;
2387     const int *entries;
2388     int index;
2389     int jumpIndex;
2390     int caseDPCOffset = 0;
2391     /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
2392     int chainingPC = (pc + 4) & ~3;
2393
2394     /*
2395      * Packed switch data format:
2396      *  ushort ident = 0x0100   magic value
2397      *  ushort size             number of entries in the table
2398      *  int first_key           first (and lowest) switch case value
2399      *  int targets[size]       branch targets, relative to switch opcode
2400      *
2401      * Total size is (4+size*2) 16-bit code units.
2402      */
2403     size = switchData[1];
2404     assert(size > 0);
2405
2406     firstKey = switchData[2];
2407     firstKey |= switchData[3] << 16;
2408
2409
2410     /* The entries are guaranteed to be aligned on a 32-bit boundary;
2411      * we can treat them as a native int array.
2412      */
2413     entries = (const int*) &switchData[4];
2414     assert(((u4)entries & 0x3) == 0);
2415
2416     index = testVal - firstKey;
2417
2418     /* Jump to the default cell */
2419     if (index < 0 || index >= size) {
2420         jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
2421     /* Jump to the non-chaining exit point */
2422     } else if (index >= MAX_CHAINED_SWITCH_CASES) {
2423         jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
2424         caseDPCOffset = entries[index];
2425     /* Jump to the inline chaining cell */
2426     } else {
2427         jumpIndex = index;
2428     }
2429
2430     chainingPC += jumpIndex * 8;
2431     return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
2432 }
2433
2434 /* See comments for findPackedSwitchIndex */
2435 s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
2436 {
2437     int size;
2438     const int *keys;
2439     const int *entries;
2440     int chainingPC = (pc + 4) & ~3;
2441     int i;
2442
2443     /*
2444      * Sparse switch data format:
2445      *  ushort ident = 0x0200   magic value
2446      *  ushort size             number of entries in the table; > 0
2447      *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
2448      *  int targets[size]       branch targets, relative to switch opcode
2449      *
2450      * Total size is (2+size*4) 16-bit code units.
2451      */
2452
2453     size = switchData[1];
2454     assert(size > 0);
2455
2456     /* The keys are guaranteed to be aligned on a 32-bit boundary;
2457      * we can treat them as a native int array.
2458      */
2459     keys = (const int*) &switchData[2];
2460     assert(((u4)keys & 0x3) == 0);
2461
2462     /* The entries are guaranteed to be aligned on a 32-bit boundary;
2463      * we can treat them as a native int array.
2464      */
2465     entries = keys + size;
2466     assert(((u4)entries & 0x3) == 0);
2467
2468     /*
2469      * Run through the list of keys, which are guaranteed to
2470      * be sorted low-to-high.
2471      *
2472      * Most tables have 3-4 entries.  Few have more than 10.  A binary
2473      * search here is probably not useful.
2474      */
2475     for (i = 0; i < size; i++) {
2476         int k = keys[i];
2477         if (k == testVal) {
2478             /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
2479             int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
2480                            i : MAX_CHAINED_SWITCH_CASES + 1;
2481             chainingPC += jumpIndex * 8;
2482             return (((s8) entries[i]) << 32) | (u8) chainingPC;
2483         } else if (k > testVal) {
2484             break;
2485         }
2486     }
2487     return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 8;
2488 }
2489
2490 static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2491 {
2492     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2493     switch (dalvikOpCode) {
2494         case OP_FILL_ARRAY_DATA: {
2495             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2496             // Making a call - use explicit registers
2497             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2498             genExportPC(cUnit, mir);
2499             loadValueDirectFixed(cUnit, rlSrc, r0);
2500             loadConstant(cUnit, r2, (int)dvmInterpHandleFillArrayData);
2501             loadConstant(cUnit, r1,
2502                (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
2503             opReg(cUnit, kOpBlx, r2);
2504             dvmCompilerClobberCallRegs(cUnit);
2505             /* generate a branch over if successful */
2506             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2507             ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
2508             loadConstant(cUnit, r0,
2509                          (int) (cUnit->method->insns + mir->offset));
2510             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2511             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2512             target->defMask = ENCODE_ALL;
2513             branchOver->generic.target = (LIR *) target;
2514             break;
2515         }
2516         /*
2517          * Compute the goto target of up to
2518          * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
2519          * See the comment before findPackedSwitchIndex for the code layout.
2520          */
2521         case OP_PACKED_SWITCH:
2522         case OP_SPARSE_SWITCH: {
2523             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2524             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2525             loadValueDirectFixed(cUnit, rlSrc, r1);
2526             dvmCompilerLockAllTemps(cUnit);
2527             const u2 *switchData =
2528                 cUnit->method->insns + mir->offset + mir->dalvikInsn.vB;
2529             u2 size = switchData[1];
2530
2531             if (dalvikOpCode == OP_PACKED_SWITCH) {
2532                 loadConstant(cUnit, r4PC, (int)findPackedSwitchIndex);
2533             } else {
2534                 loadConstant(cUnit, r4PC, (int)findSparseSwitchIndex);
2535             }
2536             /* r0 <- Addr of the switch data */
2537             loadConstant(cUnit, r0,
2538                (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
2539             /* r2 <- pc of the instruction following the blx */
2540             opRegReg(cUnit, kOpMov, r2, rpc);
2541             opReg(cUnit, kOpBlx, r4PC);
2542             dvmCompilerClobberCallRegs(cUnit);
2543             /* pc <- computed goto target */
2544             opRegReg(cUnit, kOpMov, rpc, r0);
2545             break;
2546         }
2547         default:
2548             return true;
2549     }
2550     return false;
2551 }
2552
2553 static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2554                              ArmLIR *labelList)
2555 {
2556     ArmLIR *retChainingCell = NULL;
2557     ArmLIR *pcrLabel = NULL;
2558
2559     if (bb->fallThrough != NULL)
2560         retChainingCell = &labelList[bb->fallThrough->id];
2561
2562     DecodedInstruction *dInsn = &mir->dalvikInsn;
2563     switch (mir->dalvikInsn.opCode) {
2564         /*
2565          * calleeMethod = this->clazz->vtable[
2566          *     method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2567          * ]
2568          */
2569         case OP_INVOKE_VIRTUAL:
2570         case OP_INVOKE_VIRTUAL_RANGE: {
2571             ArmLIR *predChainingCell = &labelList[bb->taken->id];
2572             int methodIndex =
2573                 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2574                 methodIndex;
2575
2576             if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2577                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2578             else
2579                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2580
2581             genInvokeVirtualCommon(cUnit, mir, methodIndex,
2582                                    retChainingCell,
2583                                    predChainingCell,
2584                                    pcrLabel);
2585             break;
2586         }
2587         /*
2588          * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2589          *                ->pResMethods[BBBB]->methodIndex]
2590          */
2591         /* TODO - not excersized in RunPerf.jar */
2592         case OP_INVOKE_SUPER:
2593         case OP_INVOKE_SUPER_RANGE: {
2594             int mIndex = cUnit->method->clazz->pDvmDex->
2595                 pResMethods[dInsn->vB]->methodIndex;
2596             const Method *calleeMethod =
2597                 cUnit->method->clazz->super->vtable[mIndex];
2598
2599             if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2600                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2601             else
2602                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2603
2604             /* r0 = calleeMethod */
2605             loadConstant(cUnit, r0, (int) calleeMethod);
2606
2607             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2608                                      calleeMethod);
2609             break;
2610         }
2611         /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2612         case OP_INVOKE_DIRECT:
2613         case OP_INVOKE_DIRECT_RANGE: {
2614             const Method *calleeMethod =
2615                 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2616
2617             if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2618                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2619             else
2620                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2621
2622             /* r0 = calleeMethod */
2623             loadConstant(cUnit, r0, (int) calleeMethod);
2624
2625             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2626                                      calleeMethod);
2627             break;
2628         }
2629         /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2630         case OP_INVOKE_STATIC:
2631         case OP_INVOKE_STATIC_RANGE: {
2632             const Method *calleeMethod =
2633                 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2634
2635             if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2636                 genProcessArgsNoRange(cUnit, mir, dInsn,
2637                                       NULL /* no null check */);
2638             else
2639                 genProcessArgsRange(cUnit, mir, dInsn,
2640                                     NULL /* no null check */);
2641
2642             /* r0 = calleeMethod */
2643             loadConstant(cUnit, r0, (int) calleeMethod);
2644
2645             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2646                                      calleeMethod);
2647             break;
2648         }
2649     /*
2650          * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2651          *                    BBBB, method, method->clazz->pDvmDex)
2652          *
2653          *  Given "invoke-interface {v0}", the following is the generated code:
2654          *
2655          * 0x426a9abe : ldr     r0, [r5, #0]   --+
2656          * 0x426a9ac0 : mov     r7, r5           |
2657          * 0x426a9ac2 : sub     r7, #24          |
2658          * 0x426a9ac4 : cmp     r0, #0           | genProcessArgsNoRange
2659          * 0x426a9ac6 : beq     0x426a9afe       |
2660          * 0x426a9ac8 : stmia   r7, <r0>       --+
2661          * 0x426a9aca : ldr     r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2662          * 0x426a9acc : add     r1, pc, #52    --> r1 <- &retChainingCell
2663          * 0x426a9ace : add     r2, pc, #60    --> r2 <- &predictedChainingCell
2664          * 0x426a9ad0 : blx_1   0x426a918c     --+ TEMPLATE_INVOKE_METHOD_
2665          * 0x426a9ad2 : blx_2   see above      --+     PREDICTED_CHAIN
2666          * 0x426a9ad4 : b       0x426a9b0c     --> off to the predicted chain
2667          * 0x426a9ad6 : b       0x426a9afe     --> punt to the interpreter
2668          * 0x426a9ad8 : mov     r8, r1         --+
2669          * 0x426a9ada : mov     r9, r2           |
2670          * 0x426a9adc : mov     r10, r3          |
2671          * 0x426a9ade : mov     r0, r3           |
2672          * 0x426a9ae0 : mov     r1, #74          | dvmFindInterfaceMethodInCache
2673          * 0x426a9ae2 : ldr     r2, [pc, #76]    |
2674          * 0x426a9ae4 : ldr     r3, [pc, #68]    |
2675          * 0x426a9ae6 : ldr     r7, [pc, #64]    |
2676          * 0x426a9ae8 : blx     r7             --+
2677          * 0x426a9aea : mov     r1, r8         --> r1 <- rechain count
2678          * 0x426a9aec : cmp     r1, #0         --> compare against 0
2679          * 0x426a9aee : bgt     0x426a9af8     --> >=0? don't rechain
2680          * 0x426a9af0 : ldr     r7, [r6, #96]  --+
2681          * 0x426a9af2 : mov     r2, r9           | dvmJitToPatchPredictedChain
2682          * 0x426a9af4 : mov     r3, r10          |
2683          * 0x426a9af6 : blx     r7             --+
2684          * 0x426a9af8 : add     r1, pc, #8     --> r1 <- &retChainingCell
2685          * 0x426a9afa : blx_1   0x426a9098     --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2686          * 0x426a9afc : blx_2   see above      --+
2687          * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
2688          * 0x426a9afe (0042): ldr     r0, [pc, #52]
2689          * Exception_Handling:
2690          * 0x426a9b00 (0044): ldr     r1, [r6, #84]
2691          * 0x426a9b02 (0046): blx     r1
2692          * 0x426a9b04 (0048): .align4
2693          * -------- chaining cell (hot): 0x0021
2694          * 0x426a9b04 (0048): ldr     r0, [r6, #92]
2695          * 0x426a9b06 (004a): blx     r0
2696          * 0x426a9b08 (004c): data    0x7872(30834)
2697          * 0x426a9b0a (004e): data    0x428b(17035)
2698          * 0x426a9b0c (0050): .align4
2699          * -------- chaining cell (predicted)
2700          * 0x426a9b0c (0050): data    0x0000(0) --> will be patched into bx
2701          * 0x426a9b0e (0052): data    0x0000(0)
2702          * 0x426a9b10 (0054): data    0x0000(0) --> class
2703          * 0x426a9b12 (0056): data    0x0000(0)
2704          * 0x426a9b14 (0058): data    0x0000(0) --> method
2705          * 0x426a9b16 (005a): data    0x0000(0)
2706          * 0x426a9b18 (005c): data    0x0000(0) --> reset count
2707          * 0x426a9b1a (005e): data    0x0000(0)
2708          * 0x426a9b28 (006c): .word (0xad0392a5)
2709          * 0x426a9b2c (0070): .word (0x6e750)
2710          * 0x426a9b30 (0074): .word (0x4109a618)
2711          * 0x426a9b34 (0078): .word (0x428b786c)
2712          */
2713         case OP_INVOKE_INTERFACE:
2714         case OP_INVOKE_INTERFACE_RANGE: {
2715             ArmLIR *predChainingCell = &labelList[bb->taken->id];
2716             int methodIndex = dInsn->vB;
2717
2718             /* Ensure that nothing is both live and dirty */
2719             dvmCompilerFlushAllRegs(cUnit);
2720
2721             if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2722                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2723             else
2724                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2725
2726             /* "this" is already left in r0 by genProcessArgs* */
2727
2728             /* r4PC = dalvikCallsite */
2729             loadConstant(cUnit, r4PC,
2730                          (int) (cUnit->method->insns + mir->offset));
2731
2732             /* r1 = &retChainingCell */
2733             ArmLIR *addrRetChain =
2734                 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
2735             addrRetChain->generic.target = (LIR *) retChainingCell;
2736
2737             /* r2 = &predictedChainingCell */
2738             ArmLIR *predictedChainingCell =
2739                 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
2740             predictedChainingCell->generic.target = (LIR *) predChainingCell;
2741
2742             genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2743
2744             /* return through lr - jump to the chaining cell */
2745             genUnconditionalBranch(cUnit, predChainingCell);
2746
2747             /*
2748              * null-check on "this" may have been eliminated, but we still need
2749              * a PC-reconstruction label for stack overflow bailout.
2750              */
2751             if (pcrLabel == NULL) {
2752                 int dPC = (int) (cUnit->method->insns + mir->offset);
2753                 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
2754                 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
2755                 pcrLabel->operands[0] = dPC;
2756                 pcrLabel->operands[1] = mir->offset;
2757                 /* Insert the place holder to the growable list */
2758                 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2759             }
2760
2761             /* return through lr+2 - punt to the interpreter */
2762             genUnconditionalBranch(cUnit, pcrLabel);
2763
2764             /*
2765              * return through lr+4 - fully resolve the callee method.
2766              * r1 <- count
2767              * r2 <- &predictedChainCell
2768              * r3 <- this->class
2769              * r4 <- dPC
2770              * r7 <- this->class->vtable
2771              */
2772
2773             /* Save count, &predictedChainCell, and class to high regs first */
2774             genRegCopy(cUnit, r8, r1);
2775             genRegCopy(cUnit, r9, r2);
2776             genRegCopy(cUnit, r10, r3);
2777
2778             /* r0 now contains this->clazz */
2779             genRegCopy(cUnit, r0, r3);
2780
2781             /* r1 = BBBB */
2782             loadConstant(cUnit, r1, dInsn->vB);
2783
2784             /* r2 = method (caller) */
2785             loadConstant(cUnit, r2, (int) cUnit->method);
2786
2787             /* r3 = pDvmDex */
2788             loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
2789
2790             loadConstant(cUnit, r7,
2791                          (intptr_t) dvmFindInterfaceMethodInCache);
2792             opReg(cUnit, kOpBlx, r7);
2793
2794             /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
2795
2796             genRegCopy(cUnit, r1, r8);
2797
2798             /* Check if rechain limit is reached */
2799             opRegImm(cUnit, kOpCmp, r1, 0);
2800
2801             ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
2802
2803             loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2804                          jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
2805
2806             genRegCopy(cUnit, r2, r9);
2807             genRegCopy(cUnit, r3, r10);
2808
2809             /*
2810              * r0 = calleeMethod
2811              * r2 = &predictedChainingCell
2812              * r3 = class
2813              *
2814              * &returnChainingCell has been loaded into r1 but is not needed
2815              * when patching the chaining cell and will be clobbered upon
2816              * returning so it will be reconstructed again.
2817              */
2818             opReg(cUnit, kOpBlx, r7);
2819
2820             /* r1 = &retChainingCell */
2821             addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
2822             addrRetChain->generic.target = (LIR *) retChainingCell;
2823
2824             bypassRechaining->generic.target = (LIR *) addrRetChain;
2825
2826             /*
2827              * r0 = this, r1 = calleeMethod,
2828              * r1 = &ChainingCell,
2829              * r4PC = callsiteDPC,
2830              */
2831             genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2832 #if defined(INVOKE_STATS)
2833             gDvmJit.invokePredictedChain++;
2834 #endif
2835             /* Handle exceptions using the interpreter */
2836             genTrap(cUnit, mir->offset, pcrLabel);
2837             break;
2838         }
2839         /* NOP */
2840         case OP_INVOKE_DIRECT_EMPTY: {
2841             return false;
2842         }
2843         case OP_FILLED_NEW_ARRAY:
2844         case OP_FILLED_NEW_ARRAY_RANGE: {
2845             /* Just let the interpreter deal with these */
2846             genInterpSingleStep(cUnit, mir);
2847             break;
2848         }
2849         default:
2850             return true;
2851     }
2852     return false;
2853 }
2854
2855 static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
2856                                BasicBlock *bb, ArmLIR *labelList)
2857 {
2858     ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
2859     ArmLIR *predChainingCell = &labelList[bb->taken->id];
2860     ArmLIR *pcrLabel = NULL;
2861
2862     DecodedInstruction *dInsn = &mir->dalvikInsn;
2863     switch (mir->dalvikInsn.opCode) {
2864         /* calleeMethod = this->clazz->vtable[BBBB] */
2865         case OP_INVOKE_VIRTUAL_QUICK_RANGE:
2866         case OP_INVOKE_VIRTUAL_QUICK: {
2867             int methodIndex = dInsn->vB;
2868             if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
2869                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2870             else
2871                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2872
2873             genInvokeVirtualCommon(cUnit, mir, methodIndex,
2874                                    retChainingCell,
2875                                    predChainingCell,
2876                                    pcrLabel);
2877             break;
2878         }
2879         /* calleeMethod = method->clazz->super->vtable[BBBB] */
2880         case OP_INVOKE_SUPER_QUICK:
2881         case OP_INVOKE_SUPER_QUICK_RANGE: {
2882             const Method *calleeMethod =
2883                 cUnit->method->clazz->super->vtable[dInsn->vB];
2884
2885             if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
2886                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2887             else
2888                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2889
2890             /* r0 = calleeMethod */
2891             loadConstant(cUnit, r0, (int) calleeMethod);
2892
2893             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2894                                      calleeMethod);
2895             /* Handle exceptions using the interpreter */
2896             genTrap(cUnit, mir->offset, pcrLabel);
2897             break;
2898         }
2899         default:
2900             return true;
2901     }
2902     return false;
2903 }
2904
2905 /*
2906  * This operation is complex enough that we'll do it partly inline
2907  * and partly with a handler.  NOTE: the handler uses hardcoded
2908  * values for string object offsets and must be revisitied if the
2909  * layout changes.
2910  */
2911 static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
2912 {
2913 #if defined(USE_GLOBAL_STRING_DEFS)
2914     return false;
2915 #else
2916     ArmLIR *rollback;
2917     RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
2918     RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1);
2919
2920     loadValueDirectFixed(cUnit, rlThis, r0);
2921     loadValueDirectFixed(cUnit, rlComp, r1);
2922     /* Test objects for NULL */
2923     rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
2924     genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback);
2925     /*
2926      * TUNING: we could check for object pointer equality before invoking
2927      * handler. Unclear whether the gain would be worth the added code size
2928      * expansion.
2929      */
2930     genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
2931     storeValue(cUnit, inlinedTarget(cUnit, mir, false),
2932                dvmCompilerGetReturn(cUnit));
2933     return true;
2934 #endif
2935 }
2936
2937 static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
2938 {
2939 #if defined(USE_GLOBAL_STRING_DEFS)
2940     return false;
2941 #else
2942     RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
2943     RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1);
2944
2945     loadValueDirectFixed(cUnit, rlThis, r0);
2946     loadValueDirectFixed(cUnit, rlChar, r1);
2947     if (!singleI) {
2948         RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
2949         loadValueDirectFixed(cUnit, rlStart, r2);
2950     } else {
2951         loadConstant(cUnit, r2, 0);
2952     }
2953     /* Test objects for NULL */
2954     genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
2955     genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
2956     storeValue(cUnit, inlinedTarget(cUnit, mir, false),
2957                dvmCompilerGetReturn(cUnit));
2958     return true;
2959 #endif
2960 }
2961
2962 static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
2963 {
2964     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
2965     RegLocation rlDest = inlinedTarget(cUnit, mir, false);
2966     rlObj = loadValue(cUnit, rlObj, kCoreReg);
2967     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2968     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
2969     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
2970                  rlResult.lowReg);
2971     storeValue(cUnit, rlDest, rlResult);
2972     return false;
2973 }
2974
2975 static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
2976 {
2977     int contents = offsetof(ArrayObject, contents);
2978     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
2979     RegLocation rlIdx = dvmCompilerGetSrc(cUnit, mir, 1);
2980     RegLocation rlDest = inlinedTarget(cUnit, mir, false);
2981     RegLocation rlResult;
2982     rlObj = loadValue(cUnit, rlObj, kCoreReg);
2983     rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
2984     int regMax = dvmCompilerAllocTemp(cUnit);
2985     int regOff = dvmCompilerAllocTemp(cUnit);
2986     int regPtr = dvmCompilerAllocTemp(cUnit);
2987     ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
2988                                     mir->offset, NULL);
2989     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
2990     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
2991     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
2992     genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
2993     dvmCompilerFreeTemp(cUnit, regMax);
2994     opRegImm(cUnit, kOpAdd, regPtr, contents);
2995     opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
2996     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2997     loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
2998     storeValue(cUnit, rlDest, rlResult);
2999     return false;
3000 }
3001
3002 static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
3003 {
3004     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
3005     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
3006     RegLocation rlDest = inlinedTarget(cUnit, mir, false);;
3007     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3008     int signReg = dvmCompilerAllocTemp(cUnit);
3009     /*
3010      * abs(x) = y<=x>>31, (x+y)^y.
3011      * Thumb2's IT block also yields 3 instructions, but imposes
3012      * scheduling constraints.
3013      */
3014     opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
3015     opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
3016     opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
3017     storeValue(cUnit, rlDest, rlResult);
3018     return false;
3019 }
3020
3021 static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
3022 {
3023     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
3024     RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
3025     rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
3026     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3027     int signReg = dvmCompilerAllocTemp(cUnit);
3028     /*
3029      * abs(x) = y<=x>>31, (x+y)^y.
3030      * Thumb2 IT block allows slightly shorter sequence,
3031      * but introduces a scheduling barrier.  Stick with this
3032      * mechanism for now.
3033      */
3034     opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
3035     opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
3036     opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg);
3037     opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
3038     opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
3039     storeValueWide(cUnit, rlDest, rlResult);
3040     return false;
3041 }
3042
3043 /*
3044  * NOTE: Handles both range and non-range versions (arguments
3045  * have already been normalized by this point).
3046  */
3047 static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
3048 {
3049     DecodedInstruction *dInsn = &mir->dalvikInsn;
3050     switch( mir->dalvikInsn.opCode) {
3051         case OP_EXECUTE_INLINE_RANGE:
3052         case OP_EXECUTE_INLINE: {
3053             unsigned int i;
3054             const InlineOperation* inLineTable = dvmGetInlineOpsTable();
3055             int offset = offsetof(InterpState, retval);
3056             int operation = dInsn->vB;
3057             int tReg1;
3058             int tReg2;
3059             switch (operation) {
3060                 case INLINE_EMPTYINLINEMETHOD:
3061                     return false;  /* Nop */
3062                 case INLINE_STRING_LENGTH:
3063                     return genInlinedStringLength(cUnit, mir);
3064                 case INLINE_MATH_ABS_INT:
3065                     return genInlinedAbsInt(cUnit, mir);
3066                 case INLINE_MATH_ABS_LONG:
3067                     return genInlinedAbsLong(cUnit, mir);
3068                 case INLINE_MATH_MIN_INT:
3069                     return genInlinedMinMaxInt(cUnit, mir, true);
3070                 case INLINE_MATH_MAX_INT:
3071                     return genInlinedMinMaxInt(cUnit, mir, false);
3072                 case INLINE_STRING_CHARAT:
3073                     return genInlinedStringCharAt(cUnit, mir);
3074                 case INLINE_MATH_SQRT:
3075                     if (genInlineSqrt(cUnit, mir))
3076                         return false;
3077                     else
3078                         break;   /* Handle with C routine */
3079                 case INLINE_MATH_ABS_FLOAT:
3080                     if (genInlinedAbsFloat(cUnit, mir))
3081                         return false;
3082                     else
3083                         break;
3084                 case INLINE_MATH_ABS_DOUBLE:
3085                     if (genInlinedAbsDouble(cUnit, mir))
3086                         return false;
3087                     else
3088                         break;
3089                 case INLINE_STRING_COMPARETO:
3090                     if (genInlinedCompareTo(cUnit, mir))
3091                         return false;
3092                     else
3093                         break;
3094                 case INLINE_STRING_INDEXOF_I:
3095                     if (genInlinedIndexOf(cUnit, mir, true /* I */))
3096                         return false;
3097                     else
3098                         break;
3099                 case INLINE_STRING_INDEXOF_II:
3100                     if (genInlinedIndexOf(cUnit, mir, false /* I */))
3101                         return false;
3102                     else
3103                         break;
3104                 case INLINE_STRING_EQUALS:
3105                 case INLINE_MATH_COS:
3106                 case INLINE_MATH_SIN:
3107                     break;   /* Handle with C routine */
3108                 default:
3109                     dvmAbort();
3110             }
3111             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
3112             dvmCompilerClobberCallRegs(cUnit);
3113             dvmCompilerClobber(cUnit, r4PC);
3114             dvmCompilerClobber(cUnit, r7);
3115             opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
3116             opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
3117             loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3118             genExportPC(cUnit, mir);
3119             for (i=0; i < dInsn->vA; i++) {
3120                 loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i);
3121             }
3122             opReg(cUnit, kOpBlx, r4PC);
3123             opRegImm(cUnit, kOpAdd, r13, 8);
3124             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3125             ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
3126             loadConstant(cUnit, r0,
3127                          (int) (cUnit->method->insns + mir->offset));
3128             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3129             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3130             target->defMask = ENCODE_ALL;
3131             branchOver->generic.target = (LIR *) target;
3132             break;
3133         }
3134         default:
3135             return true;
3136     }
3137     return false;
3138 }
3139
3140 static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3141 {
3142     //TUNING: We're using core regs here - not optimal when target is a double
3143     RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
3144     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3145     loadConstantValue(cUnit, rlResult.lowReg,
3146                       mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3147     loadConstantValue(cUnit, rlResult.highReg,
3148                       (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3149     storeValueWide(cUnit, rlDest, rlResult);
3150     return false;
3151 }
3152
3153 /*
3154  * The following are special processing routines that handle transfer of
3155  * controls between compiled code and the interpreter. Certain VM states like
3156  * Dalvik PC and special-purpose registers are reconstructed here.
3157  */
3158
3159 /* Chaining cell for code that may need warmup. */
3160 static void handleNormalChainingCell(CompilationUnit *cUnit,
3161                                      unsigned int offset)
3162 {
3163     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3164                  jitToInterpEntries.dvmJitToInterpNormal), r0);
3165     opReg(cUnit, kOpBlx, r0);
3166     addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3167 }
3168
3169 /*
3170  * Chaining cell for instructions that immediately following already translated
3171  * code.
3172  */
3173 static void handleHotChainingCell(CompilationUnit *cUnit,
3174                                   unsigned int offset)
3175 {
3176     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3177                  jitToInterpEntries.dvmJitToInterpTraceSelect), r0);
3178     opReg(cUnit, kOpBlx, r0);
3179     addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3180 }
3181
3182 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
3183 /* Chaining cell for branches that branch back into the same basic block */
3184 static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3185                                              unsigned int offset)
3186 {
3187 #if defined(WITH_SELF_VERIFICATION)
3188     newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
3189         offsetof(InterpState,
3190                  jitToInterpEntries.dvmJitToInterpBackwardBranch) >> 2);
3191 #else
3192     newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
3193         offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3194 #endif
3195     newLIR1(cUnit, kThumbBlxR, r0);
3196     addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3197 }
3198
3199 #endif
3200 /* Chaining cell for monomorphic method invocations. */
3201 static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3202                                               const Method *callee)
3203 {
3204     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3205                  jitToInterpEntries.dvmJitToInterpTraceSelect), r0);
3206     opReg(cUnit, kOpBlx, r0);
3207     addWordData(cUnit, (int) (callee->insns), true);
3208 }
3209
3210 /* Chaining cell for monomorphic method invocations. */
3211 static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3212 {
3213
3214     /* Should not be executed in the initial state */
3215     addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3216     /* To be filled: class */
3217     addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3218     /* To be filled: method */
3219     addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3220     /*
3221      * Rechain count. The initial value of 0 here will trigger chaining upon
3222      * the first invocation of this callsite.
3223      */
3224     addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3225 }
3226
3227 /* Load the Dalvik PC into r0 and jump to the specified target */
3228 static void handlePCReconstruction(CompilationUnit *cUnit,
3229                                    ArmLIR *targetLabel)
3230 {
3231     ArmLIR **pcrLabel =
3232         (ArmLIR **) cUnit->pcReconstructionList.elemList;
3233     int numElems = cUnit->pcReconstructionList.numUsed;
3234     int i;
3235     for (i = 0; i < numElems; i++) {
3236         dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3237         /* r0 = dalvik PC */
3238         loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3239         genUnconditionalBranch(cUnit, targetLabel);
3240     }
3241 }
3242
3243 static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
3244     "kMirOpPhi",
3245     "kMirOpNullNRangeUpCheck",
3246     "kMirOpNullNRangeDownCheck",
3247     "kMirOpLowerBound",
3248     "kMirOpPunt",
3249 };
3250
3251 /*
3252  * vA = arrayReg;
3253  * vB = idxReg;
3254  * vC = endConditionReg;
3255  * arg[0] = maxC
3256  * arg[1] = minC
3257  * arg[2] = loopBranchConditionCode
3258  */
3259 static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3260 {
3261     /*
3262      * NOTE: these synthesized blocks don't have ssa names assigned
3263      * for Dalvik registers.  However, because they dominate the following
3264      * blocks we can simply use the Dalvik name w/ subscript 0 as the
3265      * ssa name.
3266      */
3267     DecodedInstruction *dInsn = &mir->dalvikInsn;
3268     const int lenOffset = offsetof(ArrayObject, length);
3269     const int maxC = dInsn->arg[0];
3270     const int minC = dInsn->arg[1];
3271     int regLength;
3272     RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3273     RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
3274
3275     /* regArray <- arrayRef */
3276     rlArray = loadValue(cUnit, rlArray, kCoreReg);
3277     rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
3278     genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
3279                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3280
3281     /* regLength <- len(arrayRef) */
3282     regLength = dvmCompilerAllocTemp(cUnit);
3283     loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
3284
3285     int delta = maxC;
3286     /*
3287      * If the loop end condition is ">=" instead of ">", then the largest value
3288      * of the index is "endCondition - 1".
3289      */
3290     if (dInsn->arg[2] == OP_IF_GE) {
3291         delta--;
3292     }
3293
3294     if (delta) {
3295         int tReg = dvmCompilerAllocTemp(cUnit);
3296         opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
3297         rlIdxEnd.lowReg = tReg;
3298         dvmCompilerFreeTemp(cUnit, tReg);
3299     }
3300     /* Punt if "regIdxEnd < len(Array)" is false */
3301     genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
3302                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3303 }
3304
3305 /*
3306  * vA = arrayReg;
3307  * vB = idxReg;
3308  * vC = endConditionReg;
3309  * arg[0] = maxC
3310  * arg[1] = minC
3311  * arg[2] = loopBranchConditionCode
3312  */
3313 static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3314 {
3315     DecodedInstruction *dInsn = &mir->dalvikInsn;
3316     const int lenOffset = offsetof(ArrayObject, length);
3317     const int regLength = dvmCompilerAllocTemp(cUnit);
3318     const int maxC = dInsn->arg[0];
3319     const int minC = dInsn->arg[1];
3320     RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3321     RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
3322
3323     /* regArray <- arrayRef */
3324     rlArray = loadValue(cUnit, rlArray, kCoreReg);
3325     rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
3326     genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
3327                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3328
3329     /* regLength <- len(arrayRef) */
3330     loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
3331
3332     if (maxC) {
3333         int tReg = dvmCompilerAllocTemp(cUnit);
3334         opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
3335         rlIdxInit.lowReg = tReg;
3336         dvmCompilerFreeTemp(cUnit, tReg);
3337     }
3338
3339     /* Punt if "regIdxInit < len(Array)" is false */
3340     genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
3341                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3342 }
3343
3344 /*
3345  * vA = idxReg;
3346  * vB = minC;
3347  */
3348 static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3349 {
3350     DecodedInstruction *dInsn = &mir->dalvikInsn;
3351     const int minC = dInsn->vB;
3352     RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
3353
3354     /* regIdx <- initial index value */
3355     rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
3356
3357     /* Punt if "regIdxInit + minC >= 0" is false */
3358     genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
3359                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3360 }
3361
3362 /* Extended MIR instructions like PHI */
3363 static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3364 {
3365     int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
3366     char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3367                                false);
3368     strcpy(msg, extendedMIROpNames[opOffset]);
3369     newLIR1(cUnit, kArmPseudoExtended, (int) msg);
3370
3371     switch (mir->dalvikInsn.opCode) {
3372         case kMirOpPhi: {
3373             char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3374             newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
3375             break;
3376         }
3377         case kMirOpNullNRangeUpCheck: {
3378             genHoistedChecksForCountUpLoop(cUnit, mir);
3379             break;
3380         }
3381         case kMirOpNullNRangeDownCheck: {
3382             genHoistedChecksForCountDownLoop(cUnit, mir);
3383             break;
3384         }
3385         case kMirOpLowerBound: {
3386             genHoistedLowerBoundCheck(cUnit, mir);
3387             break;
3388         }
3389         case kMirOpPunt: {
3390             genUnconditionalBranch(cUnit,
3391                                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3392             break;
3393         }
3394         default:
3395             break;
3396     }
3397 }
3398
3399 /*
3400  * Create a PC-reconstruction cell for the starting offset of this trace.
3401  * Since the PCR cell is placed near the end of the compiled code which is
3402  * usually out of range for a conditional branch, we put two branches (one
3403  * branch over to the loop body and one layover branch to the actual PCR) at the
3404  * end of the entry block.
3405  */
3406 static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3407                                 ArmLIR *bodyLabel)
3408 {
3409     /* Set up the place holder to reconstruct this Dalvik PC */
3410     ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3411     pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
3412     pcrLabel->operands[0] =
3413         (int) (cUnit->method->insns + entry->startOffset);
3414     pcrLabel->operands[1] = entry->startOffset;
3415     /* Insert the place holder to the growable list */
3416     dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3417
3418     /*
3419      * Next, create two branches - one branch over to the loop body and the
3420      * other branch to the PCR cell to punt.
3421      */
3422     ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
3423     branchToBody->opCode = kThumbBUncond;
3424     branchToBody->generic.target = (LIR *) bodyLabel;
3425     setupResourceMasks(branchToBody);
3426     cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3427
3428     ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
3429     branchToPCR->opCode = kThumbBUncond;
3430     branchToPCR->generic.target = (LIR *) pcrLabel;
3431     setupResourceMasks(branchToPCR);
3432     cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3433 }
3434
3435 void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3436 {
3437     /* Used to hold the labels of each block */
3438     ArmLIR *labelList =
3439         dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
3440     GrowableList chainingListByType[kChainingCellGap];
3441     int i;
3442
3443     /*
3444      * Initialize various types chaining lists.
3445      */
3446     for (i = 0; i < kChainingCellGap; i++) {
3447         dvmInitGrowableList(&chainingListByType[i], 2);
3448     }
3449
3450     BasicBlock **blockList = cUnit->blockList;
3451
3452     if (cUnit->executionCount) {
3453         /*
3454          * Reserve 6 bytes at the beginning of the trace
3455          *        +----------------------------+
3456          *        | execution count (4 bytes)  |
3457          *        +----------------------------+
3458          *        | chain cell offset (2 bytes)|
3459          *        +----------------------------+
3460          * ...and then code to increment the execution
3461          * count:
3462          *       mov   r0, pc       @ move adr of "mov r0,pc" + 4 to r0
3463          *       sub   r0, #10      @ back up to addr of executionCount
3464          *       ldr   r1, [r0]
3465          *       add   r1, #1
3466          *       str   r1, [r0]
3467          */
3468         newLIR1(cUnit, kArm16BitData, 0);
3469         newLIR1(cUnit, kArm16BitData, 0);
3470         cUnit->chainCellOffsetLIR =
3471             (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
3472         cUnit->headerSize = 6;
3473         /* Thumb instruction used directly here to ensure correct size */
3474         newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc);
3475         newLIR2(cUnit, kThumbSubRI8, r0, 10);
3476         newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
3477         newLIR2(cUnit, kThumbAddRI8, r1, 1);
3478         newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
3479     } else {
3480          /* Just reserve 2 bytes for the chain cell offset */
3481         cUnit->chainCellOffsetLIR =
3482             (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
3483         cUnit->headerSize = 2;
3484     }
3485
3486     /* Handle the content in each basic block */
3487     for (i = 0; i < cUnit->numBlocks; i++) {
3488         blockList[i]->visited = true;
3489         MIR *mir;
3490
3491         labelList[i].operands[0] = blockList[i]->startOffset;
3492
3493         if (blockList[i]->blockType >= kChainingCellGap) {
3494             /*
3495              * Append the label pseudo LIR first. Chaining cells will be handled
3496              * separately afterwards.
3497              */
3498             dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3499         }
3500
3501         if (blockList[i]->blockType == kEntryBlock) {
3502             labelList[i].opCode = ARM_PSEUDO_kEntryBlock;
3503             if (blockList[i]->firstMIRInsn == NULL) {
3504                 continue;
3505             } else {
3506               setupLoopEntryBlock(cUnit, blockList[i],
3507                                   &labelList[blockList[i]->fallThrough->id]);
3508             }
3509         } else if (blockList[i]->blockType == kExitBlock) {
3510             labelList[i].opCode = ARM_PSEUDO_kExitBlock;
3511             goto gen_fallthrough;
3512         } else if (blockList[i]->blockType == kDalvikByteCode) {
3513             labelList[i].opCode = kArmPseudoNormalBlockLabel;
3514             /* Reset the register state */
3515             dvmCompilerResetRegPool(cUnit);
3516             dvmCompilerClobberAllRegs(cUnit);
3517             dvmCompilerResetNullCheck(cUnit);
3518         } else {
3519             switch (blockList[i]->blockType) {
3520                 case kChainingCellNormal:
3521                     labelList[i].opCode = ARM_PSEUDO_kChainingCellNormal;
3522                     /* handle the codegen later */
3523                     dvmInsertGrowableList(
3524                         &chainingListByType[kChainingCellNormal], (void *) i);
3525                     break;
3526                 case kChainingCellInvokeSingleton:
3527                     labelList[i].opCode =
3528                         ARM_PSEUDO_kChainingCellInvokeSingleton;
3529                     labelList[i].operands[0] =
3530                         (int) blockList[i]->containingMethod;
3531                     /* handle the codegen later */
3532                     dvmInsertGrowableList(
3533                         &chainingListByType[kChainingCellInvokeSingleton],
3534                         (void *) i);
3535                     break;
3536                 case kChainingCellInvokePredicted:
3537                     labelList[i].opCode =
3538                         ARM_PSEUDO_kChainingCellInvokePredicted;
3539                     /* handle the codegen later */
3540                     dvmInsertGrowableList(
3541                         &chainingListByType[kChainingCellInvokePredicted],
3542                         (void *) i);
3543                     break;
3544                 case kChainingCellHot:
3545                     labelList[i].opCode =
3546                         ARM_PSEUDO_kChainingCellHot;
3547                     /* handle the codegen later */
3548                     dvmInsertGrowableList(
3549                         &chainingListByType[kChainingCellHot],
3550                         (void *) i);
3551                     break;
3552                 case kPCReconstruction:
3553                     /* Make sure exception handling block is next */
3554                     labelList[i].opCode =
3555                         ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL;
3556                     assert (i == cUnit->numBlocks - 2);
3557                     handlePCReconstruction(cUnit, &labelList[i+1]);
3558                     break;
3559                 case kExceptionHandling:
3560                     labelList[i].opCode = kArmPseudoEHBlockLabel;
3561                     if (cUnit->pcReconstructionList.numUsed) {
3562                         loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3563                                      jitToInterpEntries.dvmJitToInterpPunt),
3564                                      r1);
3565                         opReg(cUnit, kOpBlx, r1);
3566                     }
3567                     break;
3568 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
3569                 case kChainingCellBackwardBranch:
3570                     labelList[i].opCode =
3571                         ARM_PSEUDO_kChainingCellBackwardBranch;
3572                     /* handle the codegen later */
3573                     dvmInsertGrowableList(
3574                         &chainingListByType[kChainingCellBackwardBranch],
3575                         (void *) i);
3576                     break;
3577 #endif
3578                 default:
3579                     break;
3580             }
3581             continue;
3582         }
3583
3584         ArmLIR *headLIR = NULL;
3585
3586         for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
3587
3588             dvmCompilerResetRegPool(cUnit);
3589             if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
3590                 dvmCompilerClobberAllRegs(cUnit);
3591             }
3592
3593             if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
3594                 dvmCompilerResetDefTracking(cUnit);
3595             }
3596
3597             if (mir->dalvikInsn.opCode >= kMirOpFirst) {
3598                 handleExtendedMIR(cUnit, mir);
3599                 continue;
3600             }
3601
3602
3603             OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3604             InstructionFormat dalvikFormat =
3605                 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
3606             ArmLIR *boundaryLIR =
3607                 newLIR2(cUnit, ARM_PSEUDO_kDalvikByteCode_BOUNDARY,
3608                         mir->offset,
3609                         (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
3610                        );
3611             if (mir->ssaRep) {
3612                 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3613                 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
3614             }
3615
3616             /* Remember the first LIR for this block */
3617             if (headLIR == NULL) {
3618                 headLIR = boundaryLIR;
3619                 /* Set the first boundaryLIR as a scheduling barrier */
3620                 headLIR->defMask = ENCODE_ALL;
3621             }
3622
3623             bool notHandled;
3624             /*
3625              * Debugging: screen the opcode first to see if it is in the
3626              * do[-not]-compile list
3627              */
3628             bool singleStepMe =
3629                 gDvmJit.includeSelectedOp !=
3630                 ((gDvmJit.opList[dalvikOpCode >> 3] &
3631                   (1 << (dalvikOpCode & 0x7))) !=
3632                  0);
3633             if (singleStepMe || cUnit->allSingleStep) {
3634                 notHandled = false;
3635                 genInterpSingleStep(cUnit, mir);
3636             } else {
3637                 opcodeCoverage[dalvikOpCode]++;
3638                 switch (dalvikFormat) {
3639                     case kFmt10t:
3640                     case kFmt20t:
3641                     case kFmt30t:
3642                         notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3643                                   mir, blockList[i], labelList);
3644                         break;
3645                     case kFmt10x:
3646                         notHandled = handleFmt10x(cUnit, mir);
3647                         break;
3648                     case kFmt11n:
3649                     case kFmt31i:
3650                         notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3651                         break;
3652                     case kFmt11x:
3653                         notHandled = handleFmt11x(cUnit, mir);
3654                         break;
3655                     case kFmt12x:
3656                         notHandled = handleFmt12x(cUnit, mir);
3657                         break;
3658                     case kFmt20bc:
3659                         notHandled = handleFmt20bc(cUnit, mir);
3660                         break;
3661                     case kFmt21c:
3662                     case kFmt31c:
3663                         notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3664                         break;
3665                     case kFmt21h:
3666                         notHandled = handleFmt21h(cUnit, mir);
3667                         break;
3668                     case kFmt21s:
3669                         notHandled = handleFmt21s(cUnit, mir);
3670                         break;
3671                     case kFmt21t:
3672                         notHandled = handleFmt21t(cUnit, mir, blockList[i],
3673                                                   labelList);
3674                         break;
3675                     case kFmt22b:
3676                     case kFmt22s:
3677                         notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3678                         break;
3679                     case kFmt22c:
3680                         notHandled = handleFmt22c(cUnit, mir);
3681                         break;
3682                     case kFmt22cs:
3683                         notHandled = handleFmt22cs(cUnit, mir);
3684                         break;
3685                     case kFmt22t:
3686                         notHandled = handleFmt22t(cUnit, mir, blockList[i],
3687                                                   labelList);
3688                         break;
3689                     case kFmt22x:
3690                     case kFmt32x:
3691                         notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3692                         break;
3693                     case kFmt23x:
3694                         notHandled = handleFmt23x(cUnit, mir);
3695                         break;
3696                     case kFmt31t:
3697                         notHandled = handleFmt31t(cUnit, mir);
3698                         break;
3699                     case kFmt3rc:
3700                     case kFmt35c:
3701                         notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3702                                                       labelList);
3703                         break;
3704                     case kFmt3rms:
3705                     case kFmt35ms:
3706                         notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3707                                                         labelList);
3708                         break;
3709                     case kFmt3inline:
3710                     case kFmt3rinline:
3711                         notHandled = handleExecuteInline(cUnit, mir);
3712                         break;
3713                     case kFmt51l:
3714                         notHandled = handleFmt51l(cUnit, mir);
3715                         break;
3716                     default:
3717                         notHandled = true;
3718                         break;
3719                 }
3720             }
3721             if (notHandled) {
3722                 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3723                      mir->offset,
3724                      dalvikOpCode, getOpcodeName(dalvikOpCode),
3725                      dalvikFormat);
3726                 dvmAbort();
3727                 break;
3728             }
3729         }
3730
3731         if (blockList[i]->blockType == kEntryBlock) {
3732             dvmCompilerAppendLIR(cUnit,
3733                                  (LIR *) cUnit->loopAnalysis->branchToBody);
3734             dvmCompilerAppendLIR(cUnit,
3735                                  (LIR *) cUnit->loopAnalysis->branchToPCR);
3736         }
3737
3738         if (headLIR) {
3739             /*
3740              * Eliminate redundant loads/stores and delay stores into later
3741              * slots
3742              */
3743             dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3744                                                cUnit->lastLIRInsn);
3745         }
3746
3747 gen_fallthrough:
3748         /*
3749          * Check if the block is terminated due to trace length constraint -
3750          * insert an unconditional branch to the chaining cell.
3751          */
3752         if (blockList[i]->needFallThroughBranch) {
3753             genUnconditionalBranch(cUnit,
3754                                    &labelList[blockList[i]->fallThrough->id]);
3755         }
3756
3757     }
3758
3759     /* Handle the chaining cells in predefined order */
3760     for (i = 0; i < kChainingCellGap; i++) {
3761         size_t j;
3762         int *blockIdList = (int *) chainingListByType[i].elemList;
3763
3764         cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3765
3766         /* No chaining cells of this type */
3767         if (cUnit->numChainingCells[i] == 0)
3768             continue;
3769
3770         /* Record the first LIR for a new type of chaining cell */
3771         cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3772
3773         for (j = 0; j < chainingListByType[i].numUsed; j++) {
3774             int blockId = blockIdList[j];
3775
3776             /* Align this chaining cell first */
3777             newLIR0(cUnit, kArmPseudoPseudoAlign4);
3778
3779             /* Insert the pseudo chaining instruction */
3780             dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3781
3782
3783             switch (blockList[blockId]->blockType) {
3784                 case kChainingCellNormal:
3785                     handleNormalChainingCell(cUnit,
3786                       blockList[blockId]->startOffset);
3787                     break;
3788                 case kChainingCellInvokeSingleton:
3789                     handleInvokeSingletonChainingCell(cUnit,
3790                         blockList[blockId]->containingMethod);
3791                     break;
3792                 case kChainingCellInvokePredicted:
3793                     handleInvokePredictedChainingCell(cUnit);
3794                     break;
3795                 case kChainingCellHot:
3796                     handleHotChainingCell(cUnit,
3797                         blockList[blockId]->startOffset);
3798                     break;
3799 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
3800                 case kChainingCellBackwardBranch:
3801                     handleBackwardBranchChainingCell(cUnit,
3802                         blockList[blockId]->startOffset);
3803                     break;
3804 #endif
3805                 default:
3806                     LOGE("Bad blocktype %d", blockList[blockId]->blockType);
3807                     dvmAbort();
3808                     break;
3809             }
3810         }
3811     }
3812
3813     /* Mark the bottom of chaining cells */
3814     cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kArmChainingCellBottom);
3815
3816     /*
3817      * Generate the branch to the dvmJitToInterpNoChain entry point at the end
3818      * of all chaining cells for the overflow cases.
3819      */
3820     if (cUnit->switchOverflowPad) {
3821         loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad);
3822         loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3823                      jitToInterpEntries.dvmJitToInterpNoChain), r2);
3824         opRegReg(cUnit, kOpAdd, r1, r1);
3825         opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
3826 #if defined(EXIT_STATS)
3827         loadConstant(cUnit, r0, kSwitchOverflow);
3828 #endif
3829         opReg(cUnit, kOpBlx, r2);
3830     }
3831
3832     dvmCompilerApplyGlobalOptimizations(cUnit);
3833
3834 #if defined(WITH_SELF_VERIFICATION)
3835     selfVerificationBranchInsertPass(cUnit);
3836 #endif
3837 }
3838
3839 /* Accept the work and start compiling */
3840 bool dvmCompilerDoWork(CompilerWorkOrder *work)
3841 {
3842     bool res;
3843
3844     if (gDvmJit.codeCacheFull) {
3845         return false;
3846     }
3847
3848     switch (work->kind) {
3849         case kWorkOrderMethod:
3850             res = dvmCompileMethod(work->info, &work->result);
3851             break;
3852         case kWorkOrderTrace:
3853             /* Start compilation with maximally allowed trace length */
3854             res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
3855             break;
3856         case kWorkOrderTraceDebug: {
3857             bool oldPrintMe = gDvmJit.printMe;
3858             gDvmJit.printMe = true;
3859             /* Start compilation with maximally allowed trace length */
3860             res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
3861             gDvmJit.printMe = oldPrintMe;;
3862             break;
3863         }
3864         default:
3865             res = false;
3866             dvmAbort();
3867     }
3868     return res;
3869 }
3870
3871 /* Architectural-specific debugging helpers go here */
3872 void dvmCompilerArchDump(void)
3873 {
3874     /* Print compiled opcode in this VM instance */
3875     int i, start, streak;
3876     char buf[1024];
3877
3878     streak = i = 0;
3879     buf[0] = 0;
3880     while (opcodeCoverage[i] == 0 && i < 256) {
3881         i++;
3882     }
3883     if (i == 256) {
3884         return;
3885     }
3886     for (start = i++, streak = 1; i < 256; i++) {
3887         if (opcodeCoverage[i]) {
3888             streak++;
3889         } else {
3890             if (streak == 1) {
3891                 sprintf(buf+strlen(buf), "%x,", start);
3892             } else {
3893                 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3894             }
3895             streak = 0;
3896             while (opcodeCoverage[i] == 0 && i < 256) {
3897                 i++;
3898             }
3899             if (i < 256) {
3900                 streak = 1;
3901                 start = i;
3902             }
3903         }
3904     }
3905     if (streak) {
3906         if (streak == 1) {
3907             sprintf(buf+strlen(buf), "%x", start);
3908         } else {
3909             sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3910         }
3911     }
3912     if (strlen(buf)) {
3913         LOGD("dalvik.vm.jit.op = %s", buf);
3914     }
3915 }
3916
3917 /* Common initialization routine for an architecture family */
3918 bool dvmCompilerArchInit()
3919 {
3920     int i;
3921
3922     for (i = 0; i < kArmLast; i++) {
3923         if (EncodingMap[i].opCode != i) {
3924             LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
3925                  EncodingMap[i].name, i, EncodingMap[i].opCode);
3926             dvmAbort();
3927         }
3928     }
3929
3930     return dvmCompilerArchVariantInit();
3931 }
3932
3933 void *dvmCompilerGetInterpretTemplate()
3934 {
3935       return (void*) ((int)gDvmJit.codeCache +
3936                       templateEntryOffsets[TEMPLATE_INTERPRET]);
3937 }
3938
3939 /* Needed by the ld/st optmizatons */
3940 ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
3941 {
3942     return genRegCopyNoInsert(cUnit, rDest, rSrc);
3943 }
3944
3945 /* Needed by the register allocator */
3946 ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
3947 {
3948     return genRegCopy(cUnit, rDest, rSrc);
3949 }
3950
3951 /* Needed by the register allocator */
3952 void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
3953                             int srcLo, int srcHi)
3954 {
3955     genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
3956 }
3957
3958 void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
3959                              int displacement, int rSrc, OpSize size)
3960 {
3961     storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
3962 }
3963
3964 void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
3965                                  int displacement, int rSrcLo, int rSrcHi)
3966 {
3967     storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
3968 }