OSDN Git Service

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