OSDN Git Service

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