2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * This file contains codegen and support common to all supported
19 * ARM variants. It is included by:
21 * Codegen-$(TARGET_ARCH_VARIANT).c
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
27 #include "compiler/Loop.h"
29 /* Array holding the entry offset of each template relative to the first one */
30 static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
32 /* Track exercised opcodes */
33 static int opcodeCoverage[256];
35 #if defined(WITH_SELF_VERIFICATION)
36 /* Prevent certain opcodes from being jitted */
37 static inline bool selfVerificationPuntOps(OpCode op)
39 return (op == OP_MONITOR_ENTER || op == OP_MONITOR_EXIT ||
40 op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY);
44 * The following are used to keep compiled loads and stores from modifying
45 * memory during self verification mode.
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
52 * Loads check heapSpace first and return data from there if an entry exists.
53 * Otherwise, data is loaded from memory as usual.
56 /* Decode contents of heapArgSpace to determine addr to load from */
57 static void selfVerificationLoadDecode(HeapArgSpace* heapArgSpace, int* addr)
59 int reg = heapArgSpace->regMap & 0xFF;
62 *addr = heapArgSpace->coreRegs[reg];
64 assert(!DOUBLEREG(reg));
65 *addr = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
69 /* Decode contents of heapArgSpace to determine reg to load into */
70 static void selfVerificationLoadDecodeData(HeapArgSpace* heapArgSpace,
75 heapArgSpace->coreRegs[reg] = data;
77 assert(!DOUBLEREG(reg));
78 heapArgSpace->fpRegs[(reg & FP_REG_MASK)] = data;
82 static void selfVerificationLoad(InterpState* interpState)
84 Thread *self = dvmThreadSelf();
85 ShadowHeap *heapSpacePtr;
86 ShadowSpace *shadowSpace = self->shadowSpace;
87 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
90 selfVerificationLoadDecode(heapArgSpace, &addr);
92 for (heapSpacePtr = shadowSpace->heapSpace;
93 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
94 if (heapSpacePtr->addr == addr) {
95 data = heapSpacePtr->data;
100 if (heapSpacePtr == shadowSpace->heapSpaceTail)
101 data = *((unsigned int*) addr);
103 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
105 // LOGD("*** HEAP LOAD: Reg:%d Addr: 0x%x Data: 0x%x", reg, addr, data);
107 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
110 static void selfVerificationLoadByte(InterpState* interpState)
112 Thread *self = dvmThreadSelf();
113 ShadowHeap *heapSpacePtr;
114 ShadowSpace *shadowSpace = self->shadowSpace;
115 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
118 selfVerificationLoadDecode(heapArgSpace, &addr);
120 int maskedAddr = addr & 0xFFFFFFFC;
121 int alignment = addr & 0x3;
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);
132 if (heapSpacePtr == shadowSpace->heapSpaceTail)
133 data = *((unsigned char*) addr);
135 //LOGD("*** HEAP LOAD BYTE: Addr: 0x%x Data: 0x%x", addr, data);
137 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
138 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
141 static void selfVerificationLoadHalfword(InterpState* interpState)
143 Thread *self = dvmThreadSelf();
144 ShadowHeap *heapSpacePtr;
145 ShadowSpace *shadowSpace = self->shadowSpace;
146 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
149 selfVerificationLoadDecode(heapArgSpace, &addr);
151 int maskedAddr = addr & 0xFFFFFFFC;
152 int alignment = addr & 0x2;
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);
163 if (heapSpacePtr == shadowSpace->heapSpaceTail)
164 data = *((unsigned short*) addr);
166 //LOGD("*** HEAP LOAD kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
168 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
169 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
172 static void selfVerificationLoadSignedByte(InterpState* interpState)
174 Thread *self = dvmThreadSelf();
175 ShadowHeap* heapSpacePtr;
176 ShadowSpace* shadowSpace = self->shadowSpace;
177 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
180 selfVerificationLoadDecode(heapArgSpace, &addr);
182 int maskedAddr = addr & 0xFFFFFFFC;
183 int alignment = addr & 0x3;
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);
194 if (heapSpacePtr == shadowSpace->heapSpaceTail)
195 data = *((signed char*) addr);
197 //LOGD("*** HEAP LOAD SIGNED BYTE: Addr: 0x%x Data: 0x%x", addr, data);
199 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
200 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
203 static void selfVerificationLoadSignedHalfword(InterpState* interpState)
205 Thread *self = dvmThreadSelf();
206 ShadowHeap* heapSpacePtr;
207 ShadowSpace* shadowSpace = self->shadowSpace;
208 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
211 selfVerificationLoadDecode(heapArgSpace, &addr);
213 int maskedAddr = addr & 0xFFFFFFFC;
214 int alignment = addr & 0x2;
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);
225 if (heapSpacePtr == shadowSpace->heapSpaceTail)
226 data = *((signed short*) addr);
228 //LOGD("*** HEAP LOAD SIGNED kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
230 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
231 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
234 static void selfVerificationLoadDoubleword(InterpState* interpState)
236 Thread *self = dvmThreadSelf();
237 ShadowHeap* heapSpacePtr;
238 ShadowSpace* shadowSpace = self->shadowSpace;
239 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
242 selfVerificationLoadDecode(heapArgSpace, &addr);
245 unsigned int data = *((unsigned int*) addr);
246 unsigned int data2 = *((unsigned int*) addr2);
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;
257 // LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
258 // addr, data, data2);
260 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
261 int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
262 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
263 selfVerificationLoadDecodeData(heapArgSpace, data2, reg2);
266 /* Decode contents of heapArgSpace to determine arguments to store. */
267 static void selfVerificationStoreDecode(HeapArgSpace* heapArgSpace,
272 *value = heapArgSpace->coreRegs[reg];
274 assert(!DOUBLEREG(reg));
275 *value = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
279 static void selfVerificationStore(InterpState* interpState)
281 Thread *self = dvmThreadSelf();
282 ShadowHeap *heapSpacePtr;
283 ShadowSpace *shadowSpace = self->shadowSpace;
284 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
287 int reg0 = heapArgSpace->regMap & 0xFF;
288 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
289 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
290 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
292 //LOGD("*** HEAP STORE: Addr: 0x%x Data: 0x%x", addr, data);
294 for (heapSpacePtr = shadowSpace->heapSpace;
295 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
296 if (heapSpacePtr->addr == addr) break;
299 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
300 heapSpacePtr->addr = addr;
301 shadowSpace->heapSpaceTail++;
304 heapSpacePtr->data = data;
307 static void selfVerificationStoreByte(InterpState* interpState)
309 Thread *self = dvmThreadSelf();
310 ShadowHeap *heapSpacePtr;
311 ShadowSpace *shadowSpace = self->shadowSpace;
312 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
315 int reg0 = heapArgSpace->regMap & 0xFF;
316 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
317 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
318 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
320 int maskedAddr = addr & 0xFFFFFFFC;
321 int alignment = addr & 0x3;
323 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Data: 0x%x", addr, data);
325 for (heapSpacePtr = shadowSpace->heapSpace;
326 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
327 if (heapSpacePtr->addr == maskedAddr) break;
330 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
331 heapSpacePtr->addr = maskedAddr;
332 heapSpacePtr->data = *((unsigned int*) maskedAddr);
333 shadowSpace->heapSpaceTail++;
336 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
337 *((unsigned char*) addr) = (char) data;
339 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Final Data: 0x%x",
340 // addr, heapSpacePtr->data);
343 static void selfVerificationStoreHalfword(InterpState* interpState)
345 Thread *self = dvmThreadSelf();
346 ShadowHeap *heapSpacePtr;
347 ShadowSpace *shadowSpace = self->shadowSpace;
348 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
351 int reg0 = heapArgSpace->regMap & 0xFF;
352 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
353 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
354 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
356 int maskedAddr = addr & 0xFFFFFFFC;
357 int alignment = addr & 0x2;
359 //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
361 for (heapSpacePtr = shadowSpace->heapSpace;
362 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
363 if (heapSpacePtr->addr == maskedAddr) break;
366 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
367 heapSpacePtr->addr = maskedAddr;
368 heapSpacePtr->data = *((unsigned int*) maskedAddr);
369 shadowSpace->heapSpaceTail++;
372 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
373 *((unsigned short*) addr) = (short) data;
375 //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Final Data: 0x%x",
376 // addr, heapSpacePtr->data);
379 static void selfVerificationStoreDoubleword(InterpState* interpState)
381 Thread *self = dvmThreadSelf();
382 ShadowHeap *heapSpacePtr;
383 ShadowSpace *shadowSpace = self->shadowSpace;
384 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
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);
395 bool store1 = false, store2 = false;
397 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: 0x%x Data: 0x%x, Data2: 0x%x",
398 // addr, data, data2);
400 for (heapSpacePtr = shadowSpace->heapSpace;
401 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
402 if (heapSpacePtr->addr == addr) {
403 heapSpacePtr->data = data;
405 } else if (heapSpacePtr->addr == addr2) {
406 heapSpacePtr->data = data2;
412 shadowSpace->heapSpaceTail->addr = addr;
413 shadowSpace->heapSpaceTail->data = data;
414 shadowSpace->heapSpaceTail++;
417 shadowSpace->heapSpaceTail->addr = addr2;
418 shadowSpace->heapSpaceTail->data = data2;
419 shadowSpace->heapSpaceTail++;
423 /* Common wrapper function for all memory operations */
424 static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
427 /* push r0 and r7 to give us a foothold */
428 newLIR1(cUnit, kThumbPush, (1 << r0) | (1 << r7));
430 /* Let the save handler know where the save record is */
431 loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace));
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);
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);
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);
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.
454 static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
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);
463 assert(rlSrc.location == kLocDalvikFrame);
464 loadWordDisp(cUnit, rFP, sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
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.
474 static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
477 clobberReg(cUnit, reg1);
478 markRegInUse(cUnit, reg1);
479 loadValueDirect(cUnit, rlSrc, reg1);
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.
487 static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
488 int regLo, int regHi)
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);
497 assert(rlSrc.location == kLocDalvikFrame);
498 loadBaseDispWide(cUnit, NULL, rFP,
499 sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
500 regLo, regHi, false, INVALID_SREG);
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.
509 static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
510 int regLo, int regHi)
512 clobberReg(cUnit, regLo);
513 clobberReg(cUnit, regHi);
514 markRegInUse(cUnit, regLo);
515 markRegInUse(cUnit, regHi);
516 loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
519 static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
520 RegisterClass opKind)
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);
536 static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
537 RegisterClass opKind)
539 RegisterInfo *pRegLo;
540 RegisterInfo *pRegHi;
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);
558 static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
561 RegisterInfo *pRegLo;
564 assert(!rlDest.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);
575 // Just re-assign the registers. Dest gets Src's regs
576 rlDest.lowReg = rlSrc.lowReg;
577 clobberReg(cUnit, rlSrc.lowReg);
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);
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);
590 if (rlDest.location == kLocRetval) {
591 storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval),
592 rlDest.lowReg, kWord);
593 clobberReg(cUnit, rlDest.lowReg);
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);
607 static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
610 RegisterInfo *pRegLo;
611 RegisterInfo *pRegHi;
614 bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg);
615 assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
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);
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);
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,
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);
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);
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,
662 markRegClean(cUnit, rlDest.lowReg);
663 markRegClean(cUnit, rlDest.highReg);
664 defEnd = (LIR *)cUnit->lastLIRInsn;
665 markDefWide(cUnit, rlDest, defStart, defEnd);
671 * Load an immediate value into a fixed or temp register. Target
672 * register is clobbered, and marked inUse.
674 static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
676 if (isTemp(cUnit, rDest)) {
677 clobberReg(cUnit, rDest);
678 markRegInUse(cUnit, rDest);
680 return loadConstantValue(cUnit, rDest, value);
684 * Mark load/store instructions that access Dalvik registers through rFP +
687 static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
690 lir->useMask |= ENCODE_DALVIK_REG;
692 lir->defMask |= ENCODE_DALVIK_REG;
696 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
699 lir->aliasInfo = regId;
700 if (DOUBLEREG(lir->operands[0])) {
701 lir->aliasInfo |= 0x80000000;
706 * Decode the register id and mark the corresponding bit(s).
708 static inline void setupRegMask(u8 *mask, int reg)
712 int regId = reg & 0x1f;
715 * Each double register is equal to a pair of single-precision FP registers
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 */
722 *mask |= seed << shift;
726 * Set up the proper fields in the resource mask
728 static void setupResourceMasks(ArmLIR *lir)
730 int opCode = lir->opCode;
734 lir->useMask = lir->defMask = 0;
738 flags = EncodingMap[lir->opCode].flags;
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;
746 if (flags & REG_DEF0) {
747 setupRegMask(&lir->defMask, lir->operands[0]);
750 if (flags & REG_DEF1) {
751 setupRegMask(&lir->defMask, lir->operands[1]);
754 if (flags & REG_DEF_SP) {
755 lir->defMask |= ENCODE_REG_SP;
758 if (flags & REG_DEF_SP) {
759 lir->defMask |= ENCODE_REG_LR;
762 if (flags & REG_DEF_LIST0) {
763 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
766 if (flags & REG_DEF_LIST1) {
767 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
770 if (flags & SETS_CCODES) {
771 lir->defMask |= ENCODE_CCODE;
774 /* Conservatively treat the IT block */
776 lir->defMask = ENCODE_ALL;
779 /* Set up the mask for resources that are used */
780 if (flags & IS_BRANCH) {
781 lir->useMask |= ENCODE_REG_PC;
784 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
787 for (i = 0; i < 4; i++) {
788 if (flags & (1 << (kRegUse0 + i))) {
789 setupRegMask(&lir->useMask, lir->operands[i]);
794 if (flags & REG_USE_PC) {
795 lir->useMask |= ENCODE_REG_PC;
798 if (flags & REG_USE_SP) {
799 lir->useMask |= ENCODE_REG_SP;
802 if (flags & REG_USE_LIST0) {
803 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
806 if (flags & REG_USE_LIST1) {
807 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
810 if (flags & USES_CCODES) {
811 lir->useMask |= ENCODE_CCODE;
816 * The following are building blocks to construct low-level IRs with 0 - 4
819 static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
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);
829 static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
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);
841 static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
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);
855 static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
856 int dest, int src1, int src2)
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);
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);
873 static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
874 int dest, int src1, int src2, int info)
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);
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.
894 static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
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);
903 RegLocation res = LOC_DALVIK_RETURN_VAL;
909 static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
913 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE)) {
914 mir->next->dalvikInsn.opCode = OP_NOP;
915 return getDestLocWide(cUnit, mir->next, 0, 1);
917 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
924 * The following are building blocks to insert constants into the pool or
925 * instruction streams.
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)
931 /* Add the constant to the literal pool */
933 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
934 newValue->operands[0] = value;
935 newValue->generic.next = cUnit->wordList;
936 cUnit->wordList = (LIR *) newValue;
939 /* Add the constant in the middle of code stream */
940 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
941 newLIR1(cUnit, kArm16BitData, (value >> 16));
947 * Search the existing constants in the literal pool for an exact or close match
948 * within specified delta (greater or equal to 0).
950 static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
953 LIR *dataTarget = cUnit->wordList;
955 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
957 return (ArmLIR *) dataTarget;
958 dataTarget = dataTarget->next;
963 /* Create the PC reconstruction slot if not already done */
964 static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
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);
978 /* Branch to the PC reconstruction code */
979 branch->generic.target = (LIR *) pcrLabel;
985 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
988 static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
989 ArmConditionCode cond,
990 int reg1, int reg2, int dOffset,
994 res = opRegReg(cUnit, kOpCmp, reg1, reg2);
995 ArmLIR *branch = opCondBranch(cUnit, cond);
996 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
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.
1005 static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
1006 int dOffset, ArmLIR *pcrLabel)
1008 /* This particular Dalvik register has been null-checked */
1009 if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
1012 dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
1013 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
1017 * Perform zero-check on a register. Similar to genNullCheck but the value being
1018 * checked does not have a corresponding Dalvik register.
1020 static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
1021 int dOffset, ArmLIR *pcrLabel)
1023 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
1026 /* Perform bound check on two registers */
1027 static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
1028 int rBound, int dOffset, ArmLIR *pcrLabel)
1030 return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
1034 /* Generate a unconditional branch to go to the interpreter */
1035 static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
1038 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
1039 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
1042 /* Load a wide field from an object instance */
1043 static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
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);
1052 assert(rlDest.wide);
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);
1061 int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
1062 selfVerificationMemOpWrapper(cUnit, regMap,
1063 &selfVerificationLoadDoubleword);
1065 freeTemp(cUnit, regPtr);
1066 storeValueWide(cUnit, rlDest, rlResult);
1069 /* Store a wide field to an object instance */
1070 static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
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);
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);
1085 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
1086 selfVerificationMemOpWrapper(cUnit, regMap,
1087 &selfVerificationStoreDoubleword);
1089 freeTemp(cUnit, regPtr);
1093 * Load a field from an object instance
1096 static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
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);
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);
1116 int regMap = rlResult.lowReg << 8 | regPtr;
1117 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
1118 freeTemp(cUnit, regPtr);
1120 storeValue(cUnit, rlDest, rlResult);
1124 * Store a field to an object instance
1127 static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
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);
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);
1141 /* Combine address and offset */
1142 regPtr = allocTemp(cUnit);
1143 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1145 int regMap = rlSrc.lowReg << 8 | regPtr;
1146 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
1152 * Generate array load
1154 static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
1155 RegLocation rlArray, RegLocation rlIndex,
1156 RegLocation rlDest, int scale)
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);
1166 ArmLIR * pcrLabel = NULL;
1168 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
1169 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
1170 rlArray.lowReg, mir->offset, NULL);
1173 regPtr = allocTemp(cUnit);
1175 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1176 int regLen = allocTemp(cUnit);
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,
1183 freeTemp(cUnit, regLen);
1185 /* regPtr -> array data */
1186 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1188 #if !defined(WITH_SELF_VERIFICATION)
1189 if ((size == kLong) || (size == kDouble)) {
1191 int rNewIndex = allocTemp(cUnit);
1192 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1193 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1194 freeTemp(cUnit, rNewIndex);
1196 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1198 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1199 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1200 freeTemp(cUnit, regPtr);
1201 storeValueWide(cUnit, rlDest, rlResult);
1203 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1204 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1206 freeTemp(cUnit, regPtr);
1207 storeValue(cUnit, rlDest, rlResult);
1210 //TODO: probably want to move this into loadBaseIndexed
1215 funct = (void*) &selfVerificationLoadDoubleword;
1218 funct = (void*) &selfVerificationLoad;
1221 funct = (void*) &selfVerificationLoadHalfword;
1224 funct = (void*) &selfVerificationLoadSignedHalfword;
1227 funct = (void*) &selfVerificationLoadByte;
1230 funct = (void*) &selfVerificationLoadSignedByte;
1236 /* Combine address and index */
1238 int regTmp = allocTemp(cUnit);
1239 opRegRegImm(cUnit, kOpLsl, regTmp, rlIndex.lowReg, scale);
1240 opRegReg(cUnit, kOpAdd, regPtr, regTmp);
1241 freeTemp(cUnit, regTmp);
1243 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1246 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1247 int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
1248 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1250 freeTemp(cUnit, regPtr);
1251 if ((size == kLong) || (size == kDouble))
1252 storeValueWide(cUnit, rlDest, rlResult);
1254 storeValue(cUnit, rlDest, rlResult);
1259 * Generate array store
1262 static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
1263 RegLocation rlArray, RegLocation rlIndex,
1264 RegLocation rlSrc, int scale)
1266 int lenOffset = offsetof(ArrayObject, length);
1267 int dataOffset = offsetof(ArrayObject, contents);
1270 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1271 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1273 if (isTemp(cUnit, rlArray.lowReg)) {
1274 clobberReg(cUnit, rlArray.lowReg);
1275 regPtr = rlArray.lowReg;
1277 regPtr = allocTemp(cUnit);
1278 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1282 ArmLIR * pcrLabel = NULL;
1284 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
1285 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
1289 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1290 int regLen = allocTemp(cUnit);
1291 //NOTE: max live temps(4) here.
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,
1298 freeTemp(cUnit, regLen);
1300 /* regPtr -> array data */
1301 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
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
1308 int rNewIndex = allocTemp(cUnit);
1309 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1310 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1311 freeTemp(cUnit, rNewIndex);
1313 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1315 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1316 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1317 freeTemp(cUnit, regPtr);
1319 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1320 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1324 //TODO: probably want to move this into storeBaseIndexed
1329 funct = (void*) &selfVerificationStoreDoubleword;
1332 funct = (void*) &selfVerificationStore;
1336 funct = (void*) &selfVerificationStoreHalfword;
1340 funct = (void*) &selfVerificationStoreByte;
1348 int regTmpIndex = allocTemp(cUnit);
1350 opRegRegImm(cUnit, kOpLsl, regTmpIndex, rlIndex.lowReg, scale);
1351 opRegReg(cUnit, kOpAdd, regPtr, regTmpIndex);
1352 freeTemp(cUnit, regTmpIndex);
1354 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1356 /* Combine address and index */
1357 if ((size == kLong) || (size == kDouble)) {
1358 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1360 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1363 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
1364 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1369 static bool handleShiftOpLong(CompilationUnit *cUnit, MIR *mir,
1370 RegLocation rlDest, RegLocation rlSrc1,
1371 RegLocation rlShift)
1374 * Don't mess with the regsiters here as there is a particular calling
1375 * convention to the out-of-line handler.
1377 RegLocation rlResult;
1379 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1380 loadValueDirect(cUnit, rlShift, r2);
1381 switch( mir->dalvikInsn.opCode) {
1383 case OP_SHL_LONG_2ADDR:
1384 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
1387 case OP_SHR_LONG_2ADDR:
1388 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
1391 case OP_USHR_LONG_2ADDR:
1392 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1397 rlResult = getReturnLocWide(cUnit);
1398 storeValueWide(cUnit, rlDest, rlResult);
1401 bool handleArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1402 RegLocation rlDest, RegLocation rlSrc1,
1405 RegLocation rlResult;
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);
1415 switch (mir->dalvikInsn.opCode) {
1416 case OP_ADD_FLOAT_2ADDR:
1418 funct = (void*) __aeabi_fadd;
1420 case OP_SUB_FLOAT_2ADDR:
1422 funct = (void*) __aeabi_fsub;
1424 case OP_DIV_FLOAT_2ADDR:
1426 funct = (void*) __aeabi_fdiv;
1428 case OP_MUL_FLOAT_2ADDR:
1430 funct = (void*) __aeabi_fmul;
1432 case OP_REM_FLOAT_2ADDR:
1434 funct = (void*) fmodf;
1436 case OP_NEG_FLOAT: {
1437 genNegFloat(cUnit, rlDest, rlSrc1);
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);
1454 bool handleArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1455 RegLocation rlDest, RegLocation rlSrc1,
1458 RegLocation rlResult;
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);
1468 switch (mir->dalvikInsn.opCode) {
1469 case OP_ADD_DOUBLE_2ADDR:
1471 funct = (void*) __aeabi_dadd;
1473 case OP_SUB_DOUBLE_2ADDR:
1475 funct = (void*) __aeabi_dsub;
1477 case OP_DIV_DOUBLE_2ADDR:
1479 funct = (void*) __aeabi_ddiv;
1481 case OP_MUL_DOUBLE_2ADDR:
1483 funct = (void*) __aeabi_dmul;
1485 case OP_REM_DOUBLE_2ADDR:
1487 funct = (void*) fmod;
1489 case OP_NEG_DOUBLE: {
1490 genNegDouble(cUnit, rlDest, rlSrc1);
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);
1507 static bool handleArithOpLong(CompilationUnit *cUnit, MIR *mir,
1508 RegLocation rlDest, RegLocation rlSrc1,
1511 RegLocation rlResult;
1512 OpKind firstOp = kOpBkpt;
1513 OpKind secondOp = kOpBkpt;
1514 bool callOut = false;
1517 /* TODO - find proper .h file to declare these */
1518 long long __aeabi_ldivmod(long long op1, long long op2);
1520 switch (mir->dalvikInsn.opCode) {
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);
1530 case OP_ADD_LONG_2ADDR:
1535 case OP_SUB_LONG_2ADDR:
1540 case OP_MUL_LONG_2ADDR:
1541 genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
1544 case OP_DIV_LONG_2ADDR:
1547 callTgt = (void*)__aeabi_ldivmod;
1549 /* NOTE - result is in r2/r3 instead of r0/r1 */
1551 case OP_REM_LONG_2ADDR:
1553 callTgt = (void*)__aeabi_ldivmod;
1556 case OP_AND_LONG_2ADDR:
1562 case OP_OR_LONG_2ADDR:
1567 case OP_XOR_LONG_2ADDR:
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);
1582 LOGE("Invalid long arith op");
1586 genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
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);
1596 rlResult = getReturnLocWide(cUnit);
1598 rlResult = getReturnLocWideAlt(cUnit);
1599 storeValueWide(cUnit, rlDest, rlResult);
1604 static bool handleArithOpInt(CompilationUnit *cUnit, MIR *mir,
1605 RegLocation rlDest, RegLocation rlSrc1,
1608 OpKind op = kOpBkpt;
1609 bool callOut = false;
1610 bool checkZero = false;
1614 RegLocation rlResult;
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);
1620 switch (mir->dalvikInsn.opCode) {
1630 case OP_ADD_INT_2ADDR:
1634 case OP_SUB_INT_2ADDR:
1638 case OP_MUL_INT_2ADDR:
1642 case OP_DIV_INT_2ADDR:
1645 callTgt = __aeabi_idiv;
1648 /* NOTE: returns in r1 */
1650 case OP_REM_INT_2ADDR:
1653 callTgt = __aeabi_idivmod;
1657 case OP_AND_INT_2ADDR:
1661 case OP_OR_INT_2ADDR:
1665 case OP_XOR_INT_2ADDR:
1669 case OP_SHL_INT_2ADDR:
1673 case OP_SHR_INT_2ADDR:
1677 case OP_USHR_INT_2ADDR:
1681 LOGE("Invalid word arith op: 0x%x(%d)",
1682 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1686 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1688 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1689 opRegReg(cUnit, op, rlResult.lowReg,
1692 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1693 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1694 opRegRegReg(cUnit, op, rlResult.lowReg,
1695 rlSrc1.lowReg, rlSrc2.lowReg);
1697 storeValue(cUnit, rlDest, rlResult);
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);
1705 genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
1707 opReg(cUnit, kOpBlx, r2);
1708 clobberCallRegs(cUnit);
1710 rlResult = getReturnLoc(cUnit);
1712 rlResult = getReturnLocAlt(cUnit);
1713 storeValue(cUnit, rlDest, rlResult);
1718 static bool handleArithOp(CompilationUnit *cUnit, MIR *mir)
1720 OpCode opCode = mir->dalvikInsn.opCode;
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);
1732 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
1733 rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
1734 assert(mir->ssaRep->numUses == 4);
1736 if (mir->ssaRep->numDefs == 1) {
1737 rlDest = getDestLoc(cUnit, mir, 0);
1739 assert(mir->ssaRep->numDefs == 2);
1740 rlDest = getDestLocWide(cUnit, mir, 0, 1);
1743 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
1744 return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
1746 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
1747 return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
1749 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
1750 return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
1752 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
1753 return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
1755 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
1756 return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
1758 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
1759 return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
1761 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
1762 return handleArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
1764 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
1765 return handleArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
1767 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1768 return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
1770 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
1771 return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
1776 /* Generate conditional branch instructions */
1777 static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1778 ArmConditionCode cond,
1781 ArmLIR *branch = opCondBranch(cUnit, cond);
1782 branch->generic.target = (LIR *) target;
1786 /* Generate unconditional branch instructions */
1787 static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1789 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
1790 branch->generic.target = (LIR *) target;
1795 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
1798 static void genBarrier(CompilationUnit *cUnit)
1800 ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
1801 /* Mark all resources as being clobbered */
1802 barrier->defMask = -1;
1805 /* Perform the actual operation for OP_RETURN_* */
1806 static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
1808 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
1809 #if defined(INVOKE_STATS)
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;
1826 static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1827 int srcSize, int tgtSize)
1830 * Don't optimize the register usage since it calls out to template
1835 flushAllRegs(cUnit); /* Send everything to home location */
1837 rlSrc = getSrcLoc(cUnit, mir, 0);
1838 loadValueDirectFixed(cUnit, rlSrc, r0);
1840 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
1841 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
1843 loadConstant(cUnit, r2, (int)funct);
1844 opReg(cUnit, kOpBlx, r2);
1845 clobberCallRegs(cUnit);
1847 RegLocation rlResult;
1848 rlDest = getDestLoc(cUnit, mir, 0);
1849 rlResult = getReturnLoc(cUnit);
1850 storeValue(cUnit, rlDest, rlResult);
1852 RegLocation rlResult;
1853 rlDest = getDestLocWide(cUnit, mir, 0, 1);
1854 rlResult = getReturnLocWide(cUnit);
1855 storeValueWide(cUnit, rlDest, rlResult);
1860 static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1861 DecodedInstruction *dInsn,
1865 unsigned int regMask = 0;
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.
1874 lockAllTemps(cUnit);
1875 for (i = 0; i < dInsn->vA; i++) {
1877 rlArg = getSrcLoc(cUnit, mir, numDone++);
1878 loadValueDirectFixed(cUnit, rlArg, i);
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 */
1886 *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
1889 storeMultiple(cUnit, r7, regMask);
1893 static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1894 DecodedInstruction *dInsn,
1897 int srcOffset = dInsn->vC << 2;
1898 int numArgs = dInsn->vA;
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.
1908 lockAllTemps(cUnit);
1914 opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
1915 /* load [r0 .. min(numArgs,4)] */
1916 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
1918 * Protect the loadMultiple instruction from being reordered with other
1919 * Dalvik stack accesses.
1921 loadMultiple(cUnit, r4PC, regMask);
1923 opRegRegImm(cUnit, kOpSub, r7, rFP,
1924 sizeof(StackSaveArea) + (numArgs << 2));
1925 /* generate null check */
1927 *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
1932 * Handle remaining 4n arguments:
1933 * store previously loaded 4 values and load the next 4 values
1936 ArmLIR *loopLabel = NULL;
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.
1941 opImm(cUnit, kOpPush, (1 << r0 | 1 << rFP));
1942 /* No need to generate the loop structure if numArgs <= 11 */
1944 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
1945 loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
1946 loopLabel->defMask = ENCODE_ALL;
1948 storeMultiple(cUnit, r7, regMask);
1950 * Protect the loadMultiple instruction from being reordered with other
1951 * Dalvik stack accesses.
1953 loadMultiple(cUnit, r4PC, regMask);
1954 /* No need to generate the loop structure if numArgs <= 11 */
1956 opRegImm(cUnit, kOpSub, rFP, 4);
1957 genConditionalBranch(cUnit, kArmCondNe, loopLabel);
1961 /* Save the last batch of loaded values */
1962 storeMultiple(cUnit, r7, regMask);
1964 /* Generate the loop epilogue - don't use r0 */
1965 if ((numArgs > 4) && (numArgs % 4)) {
1966 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
1968 * Protect the loadMultiple instruction from being reordered with other
1969 * Dalvik stack accesses.
1971 loadMultiple(cUnit, r4PC, regMask);
1974 opImm(cUnit, kOpPop, (1 << r0 | 1 << rFP));
1976 /* Save the modulo 4 arguments */
1977 if ((numArgs > 4) && (numArgs % 4)) {
1978 storeMultiple(cUnit, r7, regMask);
1983 * Generate code to setup the call stack then jump to the chaining cell if it
1984 * is not a native method.
1986 static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
1987 BasicBlock *bb, ArmLIR *labelList,
1989 const Method *calleeMethod)
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.
1996 lockAllTemps(cUnit);
1997 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
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;
2007 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
2008 * r1 = &ChainingCell
2009 * r4PC = callsiteDPC
2011 if (dvmIsNativeMethod(calleeMethod)) {
2012 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
2013 #if defined(INVOKE_STATS)
2014 gDvmJit.invokeNative++;
2017 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
2018 #if defined(INVOKE_STATS)
2019 gDvmJit.invokeChain++;
2021 /* Branch to the chaining cell */
2022 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2024 /* Handle exceptions using the interpreter */
2025 genTrap(cUnit, mir->offset, pcrLabel);
2029 * Generate code to check the validity of a predicted chain and take actions
2030 * based on the result.
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 --+
2048 static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
2050 ArmLIR *retChainingCell,
2051 ArmLIR *predChainingCell,
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.
2060 lockAllTemps(cUnit);
2062 /* "this" is already left in r0 by genProcessArgs* */
2064 /* r4PC = dalvikCallsite */
2065 loadConstant(cUnit, r4PC,
2066 (int) (cUnit->method->insns + mir->offset));
2068 /* r1 = &retChainingCell */
2069 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
2070 addrRetChain->generic.target = (LIR *) retChainingCell;
2072 /* r2 = &predictedChainingCell */
2073 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
2074 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2076 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2078 /* return through lr - jump to the chaining cell */
2079 genUnconditionalBranch(cUnit, predChainingCell);
2082 * null-check on "this" may have been eliminated, but we still need a PC-
2083 * reconstruction label for stack overflow bailout.
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);
2095 /* return through lr+2 - punt to the interpreter */
2096 genUnconditionalBranch(cUnit, pcrLabel);
2099 * return through lr+4 - fully resolve the callee method.
2101 * r2 <- &predictedChainCell
2104 * r7 <- this->class->vtable
2107 /* r0 <- calleeMethod */
2108 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
2110 /* Check if rechain limit is reached */
2111 opRegImm(cUnit, kOpCmp, r1, 0);
2113 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
2115 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2116 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
2120 * r2 = &predictedChainingCell
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.
2127 opReg(cUnit, kOpBlx, r7);
2129 /* r1 = &retChainingCell */
2130 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
2131 addrRetChain->generic.target = (LIR *) retChainingCell;
2133 bypassRechaining->generic.target = (LIR *) addrRetChain;
2135 * r0 = calleeMethod,
2136 * r1 = &ChainingCell,
2137 * r4PC = callsiteDPC,
2139 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2140 #if defined(INVOKE_STATS)
2141 gDvmJit.invokePredictedChain++;
2143 /* Handle exceptions using the interpreter */
2144 genTrap(cUnit, mir->offset, pcrLabel);
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.
2153 * The return LIR is a branch based on the comparison result. The actual branch
2154 * target will be setup in the caller.
2156 static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
2157 ArmLIR *predChainingCell,
2158 ArmLIR *retChainingCell,
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.
2166 lockAllTemps(cUnit);
2168 /* r3 now contains this->clazz */
2169 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
2172 * r2 now contains predicted class. The starting offset of the
2173 * cached value is 4 bytes into the chaining cell.
2175 ArmLIR *getPredictedClass =
2176 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
2177 getPredictedClass->generic.target = (LIR *) predChainingCell;
2180 * r0 now contains predicted method. The starting offset of the
2181 * cached value is 8 bytes into the chaining cell.
2183 ArmLIR *getPredictedMethod =
2184 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
2185 getPredictedMethod->generic.target = (LIR *) predChainingCell;
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;
2193 /* r4PC = dalvikCallsite */
2194 loadConstant(cUnit, r4PC,
2195 (int) (cUnit->method->insns + mir->offset));
2197 /* r1 = &retChainingCell */
2198 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
2199 addrRetChain->generic.target = (LIR *) retChainingCell;
2201 /* Check if r2 (predicted class) == r3 (actual class) */
2202 opRegReg(cUnit, kOpCmp, r2, r3);
2204 return opCondBranch(cUnit, kArmCondEq);
2207 /* Geneate a branch to go back to the interpreter */
2208 static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
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);
2220 * Attempt to single step one instruction using the interpreter and return
2221 * to the compiled code for the next Dalvik instruction
2223 static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
2225 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
2226 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
2229 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them
2230 flushAllRegs(cUnit);
2232 if ((mir->next == NULL) || (flags & flagsToCheck)) {
2233 genPuntToInterp(cUnit, mir->offset);
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);
2246 static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir)
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);
2256 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2258 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
2260 opReg(cUnit, kOpBlx, r2);
2261 clobberCallRegs(cUnit);
2264 /* Load a word at base + displacement. Displacement must be word multiple */
2265 static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
2268 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord, false,
2272 static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
2273 int displacement, int rSrc)
2275 return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
2278 static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
2280 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
2281 dvmCompilerAppendLIR(cUnit, (LIR*)res);
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.
2291 static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
2292 BasicBlock *bb, ArmLIR *labelList)
2294 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
2295 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2299 static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
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);
2307 switch (dalvikOpCode) {
2308 case OP_RETURN_VOID:
2309 genReturnCommon(cUnit,mir);
2314 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2324 static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
2327 RegLocation rlResult;
2328 if (mir->ssaRep->numDefs == 2) {
2329 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2331 rlDest = getDestLoc(cUnit, mir, 0);
2334 switch (mir->dalvikInsn.opCode) {
2337 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2338 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
2339 storeValue(cUnit, rlDest, rlResult);
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);
2357 static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
2360 RegLocation rlResult;
2361 if (mir->ssaRep->numDefs == 2) {
2362 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2364 rlDest = getDestLoc(cUnit, mir, 0);
2366 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2368 switch (mir->dalvikInsn.opCode) {
2369 case OP_CONST_HIGH16: {
2370 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
2371 storeValue(cUnit, rlDest, rlResult);
2374 case OP_CONST_WIDE_HIGH16: {
2375 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
2376 0, mir->dalvikInsn.vB << 16);
2377 storeValueWide(cUnit, rlDest, rlResult);
2386 static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
2388 /* For OP_THROW_VERIFICATION_ERROR */
2389 genInterpSingleStep(cUnit, mir);
2393 static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
2395 RegLocation rlResult;
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);
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);
2421 case OP_SGET_OBJECT:
2422 case OP_SGET_BOOLEAN:
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);
2438 int regMap = rlResult.lowReg << 8 | tReg;
2439 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2442 storeValue(cUnit, rlDest, rlResult);
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);
2457 int regMap = rlResult.highReg << 16 |
2458 rlResult.lowReg << 8 | tReg;
2459 selfVerificationMemOpWrapper(cUnit, regMap,
2460 &selfVerificationLoadDoubleword);
2463 storeValueWide(cUnit, rlDest, rlResult);
2466 case OP_SPUT_OBJECT:
2467 case OP_SPUT_BOOLEAN:
2472 int valOffset = offsetof(StaticField, value);
2473 int tReg = allocTemp(cUnit);
2474 void *fieldPtr = (void*)
2475 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
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);
2484 int regMap = rlSrc.lowReg << 8 | tReg;
2485 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
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]);
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);
2502 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | tReg;
2503 selfVerificationMemOpWrapper(cUnit, regMap,
2504 &selfVerificationStoreDoubleword);
2508 case OP_NEW_INSTANCE: {
2510 * Obey the calling convention and don't mess with the register
2513 ClassObject *classPtr = (void*)
2514 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2515 assert(classPtr != NULL);
2516 assert(classPtr->status & CLASS_INITIALIZED);
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()
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);
2533 * OOM exception needs to be thrown here and cannot re-execute
2535 loadConstant(cUnit, r0,
2536 (int) (cUnit->method->insns + mir->offset));
2537 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
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);
2548 case OP_CHECK_CAST: {
2550 * Obey the calling convention and don't mess with the register
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);
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
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);
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.
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;
2593 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
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);
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);
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);
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);
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);
2641 case OP_MONITOR_EXIT:
2642 case OP_MONITOR_ENTER:
2643 #if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
2644 handleMonitorPortable(cUnit, mir);
2646 handleMonitor(cUnit, mir);
2650 genInterpSingleStep(cUnit, mir);
2659 static bool handleConversionPortable(CompilationUnit *cUnit, MIR *mir)
2661 OpCode opCode = mir->dalvikInsn.opCode;
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 );
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);
2701 static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2703 OpCode opCode = mir->dalvikInsn.opCode;
2706 RegLocation rlResult;
2708 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
2709 return handleArithOp( cUnit, mir );
2712 if (mir->ssaRep->numUses == 2)
2713 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2715 rlSrc = getSrcLoc(cUnit, mir, 0);
2716 if (mir->ssaRep->numDefs == 2)
2717 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2719 rlDest = getDestLoc(cUnit, mir, 0);
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);
2735 return handleArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
2738 return handleArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
2740 return handleArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
2742 return handleArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
2744 storeValueWide(cUnit, rlDest, rlSrc);
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);
2752 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
2754 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
2755 rlResult.lowReg, 31);
2756 storeValueWide(cUnit, rlDest, rlResult);
2758 case OP_LONG_TO_INT:
2759 rlSrc = updateLocWide(cUnit, rlSrc);
2760 rlSrc = wideToNarrowLoc(cUnit, rlSrc);
2761 // Intentional fallthrough
2763 case OP_MOVE_OBJECT:
2764 storeValue(cUnit, rlDest, rlSrc);
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);
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);
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);
2784 case OP_ARRAY_LENGTH: {
2785 int lenOffset = offsetof(ArrayObject, length);
2786 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2787 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
2789 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2790 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
2792 storeValue(cUnit, rlDest, rlResult);
2801 static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2803 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
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);
2823 /* Compare agaist zero */
2824 static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
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);
2833 //TUNING: break this out to allow use of Thumb2 CB[N]Z
2834 switch (dalvikOpCode) {
2855 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
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]);
2864 static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
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;
2875 int __aeabi_idivmod(int op1, int op2);
2876 int __aeabi_idiv(int op1, int op2);
2878 switch (dalvikOpCode) {
2879 case OP_RSUB_INT_LIT8:
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);
2894 case OP_ADD_INT_LIT8:
2895 case OP_ADD_INT_LIT16:
2898 case OP_MUL_INT_LIT8:
2899 case OP_MUL_INT_LIT16:
2902 case OP_AND_INT_LIT8:
2903 case OP_AND_INT_LIT16:
2906 case OP_OR_INT_LIT8:
2907 case OP_OR_INT_LIT16:
2910 case OP_XOR_INT_LIT8:
2911 case OP_XOR_INT_LIT16:
2914 case OP_SHL_INT_LIT8:
2918 case OP_SHR_INT_LIT8:
2922 case OP_USHR_INT_LIT8:
2927 case OP_DIV_INT_LIT8:
2928 case OP_DIV_INT_LIT16:
2929 case OP_REM_INT_LIT8:
2930 case OP_REM_INT_LIT16:
2932 /* Let the interpreter deal with div by 0 */
2933 genInterpSingleStep(cUnit, mir);
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);
2944 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2947 loadConstant(cUnit, r1, lit);
2948 opReg(cUnit, kOpBlx, r2);
2949 clobberCallRegs(cUnit);
2951 rlResult = getReturnLoc(cUnit);
2953 rlResult = getReturnLocAlt(cUnit);
2954 storeValue(cUnit, rlDest, rlResult);
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);
2966 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2968 storeValue(cUnit, rlDest, rlResult);
2972 static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2974 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2977 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2978 InstField *pInstField = (InstField *)
2979 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2981 assert(pInstField != NULL);
2982 fieldOffset = pInstField->byteOffset;
2984 /* Deliberately break the code while make the compiler happy */
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);
3002 * "len < 0": bail to the interpreter to re-execute the
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);
3014 * OOM exception needs to be thrown here and cannot re-execute
3016 loadConstant(cUnit, r0,
3017 (int) (cUnit->method->insns + mir->offset));
3018 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
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);
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;
3064 genIGetWide(cUnit, mir, fieldOffset);
3067 case OP_IGET_OBJECT:
3068 genIGet(cUnit, mir, kWord, fieldOffset);
3070 case OP_IGET_BOOLEAN:
3071 genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
3074 genIGet(cUnit, mir, kSignedByte, fieldOffset);
3077 genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
3080 genIGet(cUnit, mir, kSignedHalf, fieldOffset);
3083 genIPutWide(cUnit, mir, fieldOffset);
3086 case OP_IPUT_OBJECT:
3087 genIPut(cUnit, mir, kWord, fieldOffset);
3091 genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
3094 case OP_IPUT_BOOLEAN:
3095 genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
3103 static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
3105 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3106 int fieldOffset = mir->dalvikInsn.vC;
3107 switch (dalvikOpCode) {
3109 case OP_IGET_OBJECT_QUICK:
3110 genIGet(cUnit, mir, kWord, fieldOffset);
3113 case OP_IPUT_OBJECT_QUICK:
3114 genIPut(cUnit, mir, kWord, fieldOffset);
3116 case OP_IGET_WIDE_QUICK:
3117 genIGetWide(cUnit, mir, fieldOffset);
3119 case OP_IPUT_WIDE_QUICK:
3120 genIPutWide(cUnit, mir, fieldOffset);
3129 /* Compare agaist zero */
3130 static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
3133 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3134 ArmConditionCode cond;
3135 RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
3136 RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
3138 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
3139 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
3140 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
3142 switch (dalvikOpCode) {
3163 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
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]);
3172 static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
3174 OpCode opCode = mir->dalvikInsn.opCode;
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));
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));
3197 static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
3199 OpCode opCode = mir->dalvikInsn.opCode;
3204 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
3205 return handleArithOp( cUnit, mir );
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);
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);
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);
3226 assert(mir->ssaRep->numUses == 2);
3227 rlSrc1 = getSrcLoc(cUnit, mir, 0);
3228 rlSrc2 = getSrcLoc(cUnit, mir, 1);
3230 if (mir->ssaRep->numDefs == 2) {
3231 rlDest = getDestLocWide(cUnit, mir, 0, 1);
3233 assert(mir->ssaRep->numDefs == 1);
3234 rlDest = getDestLoc(cUnit, mir, 0);
3242 case OP_CMPL_DOUBLE:
3243 case OP_CMPG_DOUBLE:
3244 return handleCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
3246 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
3249 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
3252 case OP_AGET_OBJECT:
3253 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
3255 case OP_AGET_BOOLEAN:
3256 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
3259 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
3262 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
3265 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
3268 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
3271 case OP_APUT_OBJECT:
3272 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
3276 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
3279 case OP_APUT_BOOLEAN:
3280 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
3289 * Find the matching case.
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).
3297 * Instructions around the call are:
3300 * blx &findPackedSwitchIndex
3303 * chaining cell for case 0 [8 bytes]
3304 * chaining cell for case 1 [8 bytes]
3306 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [8 bytes]
3307 * chaining cell for case default [8 bytes]
3310 s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
3317 int caseDPCOffset = 0;
3318 /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
3319 int chainingPC = (pc + 4) & ~3;
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
3328 * Total size is (4+size*2) 16-bit code units.
3330 size = switchData[1];
3333 firstKey = switchData[2];
3334 firstKey |= switchData[3] << 16;
3337 /* The entries are guaranteed to be aligned on a 32-bit boundary;
3338 * we can treat them as a native int array.
3340 entries = (const int*) &switchData[4];
3341 assert(((u4)entries & 0x3) == 0);
3343 index = testVal - firstKey;
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 */
3357 chainingPC += jumpIndex * 8;
3358 return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
3361 /* See comments for findPackedSwitchIndex */
3362 s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
3367 int chainingPC = (pc + 4) & ~3;
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
3377 * Total size is (2+size*4) 16-bit code units.
3380 size = switchData[1];
3383 /* The keys are guaranteed to be aligned on a 32-bit boundary;
3384 * we can treat them as a native int array.
3386 keys = (const int*) &switchData[2];
3387 assert(((u4)keys & 0x3) == 0);
3389 /* The entries are guaranteed to be aligned on a 32-bit boundary;
3390 * we can treat them as a native int array.
3392 entries = keys + size;
3393 assert(((u4)entries & 0x3) == 0);
3396 * Run through the list of keys, which are guaranteed to
3397 * be sorted low-to-high.
3399 * Most tables have 3-4 entries. Few have more than 10. A binary
3400 * search here is probably not useful.
3402 for (i = 0; i < size; i++) {
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) {
3414 return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 8;
3417 static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
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;
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.
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];
3458 if (dalvikOpCode == OP_PACKED_SWITCH) {
3459 loadConstant(cUnit, r4PC, (int)findPackedSwitchIndex);
3461 loadConstant(cUnit, r4PC, (int)findSparseSwitchIndex);
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);
3480 static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
3483 ArmLIR *retChainingCell = NULL;
3484 ArmLIR *pcrLabel = NULL;
3486 if (bb->fallThrough != NULL)
3487 retChainingCell = &labelList[bb->fallThrough->id];
3489 DecodedInstruction *dInsn = &mir->dalvikInsn;
3490 switch (mir->dalvikInsn.opCode) {
3492 * calleeMethod = this->clazz->vtable[
3493 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3496 case OP_INVOKE_VIRTUAL:
3497 case OP_INVOKE_VIRTUAL_RANGE: {
3498 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3500 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3503 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
3504 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3506 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3508 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3515 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3516 * ->pResMethods[BBBB]->methodIndex]
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];
3526 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
3527 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3529 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3531 /* r0 = calleeMethod */
3532 loadConstant(cUnit, r0, (int) calleeMethod);
3534 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
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];
3544 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
3545 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3547 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3549 /* r0 = calleeMethod */
3550 loadConstant(cUnit, r0, (int) calleeMethod);
3552 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
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];
3562 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
3563 genProcessArgsNoRange(cUnit, mir, dInsn,
3564 NULL /* no null check */);
3566 genProcessArgsRange(cUnit, mir, dInsn,
3567 NULL /* no null check */);
3569 /* r0 = calleeMethod */
3570 loadConstant(cUnit, r0, (int) calleeMethod);
3572 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3577 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3578 * BBBB, method, method->clazz->pDvmDex)
3580 * Given "invoke-interface {v0}", the following is the generated code:
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)
3640 case OP_INVOKE_INTERFACE:
3641 case OP_INVOKE_INTERFACE_RANGE: {
3642 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3643 int methodIndex = dInsn->vB;
3645 /* Ensure that nothing is both live and dirty */
3646 flushAllRegs(cUnit);
3648 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3649 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3651 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3653 /* "this" is already left in r0 by genProcessArgs* */
3655 /* r4PC = dalvikCallsite */
3656 loadConstant(cUnit, r4PC,
3657 (int) (cUnit->method->insns + mir->offset));
3659 /* r1 = &retChainingCell */
3660 ArmLIR *addrRetChain =
3661 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
3662 addrRetChain->generic.target = (LIR *) retChainingCell;
3664 /* r2 = &predictedChainingCell */
3665 ArmLIR *predictedChainingCell =
3666 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
3667 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3669 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3671 /* return through lr - jump to the chaining cell */
3672 genUnconditionalBranch(cUnit, predChainingCell);
3675 * null-check on "this" may have been eliminated, but we still need
3676 * a PC-reconstruction label for stack overflow bailout.
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);
3688 /* return through lr+2 - punt to the interpreter */
3689 genUnconditionalBranch(cUnit, pcrLabel);
3692 * return through lr+4 - fully resolve the callee method.
3694 * r2 <- &predictedChainCell
3697 * r7 <- this->class->vtable
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);
3705 /* r0 now contains this->clazz */
3706 genRegCopy(cUnit, r0, r3);
3709 loadConstant(cUnit, r1, dInsn->vB);
3711 /* r2 = method (caller) */
3712 loadConstant(cUnit, r2, (int) cUnit->method);
3715 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3717 loadConstant(cUnit, r7,
3718 (intptr_t) dvmFindInterfaceMethodInCache);
3719 opReg(cUnit, kOpBlx, r7);
3721 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3723 genRegCopy(cUnit, r1, r8);
3725 /* Check if rechain limit is reached */
3726 opRegImm(cUnit, kOpCmp, r1, 0);
3728 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
3730 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3731 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
3733 genRegCopy(cUnit, r2, r9);
3734 genRegCopy(cUnit, r3, r10);
3738 * r2 = &predictedChainingCell
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.
3745 opReg(cUnit, kOpBlx, r7);
3747 /* r1 = &retChainingCell */
3748 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
3749 addrRetChain->generic.target = (LIR *) retChainingCell;
3751 bypassRechaining->generic.target = (LIR *) addrRetChain;
3754 * r0 = this, r1 = calleeMethod,
3755 * r1 = &ChainingCell,
3756 * r4PC = callsiteDPC,
3758 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3759 #if defined(INVOKE_STATS)
3760 gDvmJit.invokePredictedChain++;
3762 /* Handle exceptions using the interpreter */
3763 genTrap(cUnit, mir->offset, pcrLabel);
3767 case OP_INVOKE_DIRECT_EMPTY: {
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);
3782 static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
3783 BasicBlock *bb, ArmLIR *labelList)
3785 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3786 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3787 ArmLIR *pcrLabel = NULL;
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);
3798 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3800 genInvokeVirtualCommon(cUnit, mir, methodIndex,
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];
3812 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3813 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3815 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3817 /* r0 = calleeMethod */
3818 loadConstant(cUnit, r0, (int) calleeMethod);
3820 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3822 /* Handle exceptions using the interpreter */
3823 genTrap(cUnit, mir->offset, pcrLabel);
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
3838 static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
3841 //Back out temporarily
3844 #if defined(USE_GLOBAL_STRING_DEFS)
3848 RegLocation rlThis = getSrcLoc(cUnit, mir, 0);
3849 RegLocation rlComp = getSrcLoc(cUnit, mir, 1);
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);
3857 * TUNING: we could check for object pointer equality before invoking
3858 * handler. Unclear whether the gain would be worth the added code size
3861 genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
3862 storeValue(cUnit, inlinedTarget(cUnit, mir, false), getReturnLoc(cUnit));
3867 static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
3870 //Back out temporarily
3873 #if defined(USE_GLOBAL_STRING_DEFS)
3876 RegLocation rlThis = getSrcLoc(cUnit, mir, 0);
3877 RegLocation rlChar = getSrcLoc(cUnit, mir, 1);
3879 loadValueDirectFixed(cUnit, rlThis, r0);
3880 loadValueDirectFixed(cUnit, rlChar, r1);
3882 RegLocation rlStart = getSrcLoc(cUnit, mir, 2);
3883 loadValueDirectFixed(cUnit, rlStart, r2);
3885 loadConstant(cUnit, r2, 0);
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));
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.
3902 static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3904 DecodedInstruction *dInsn = &mir->dalvikInsn;
3905 switch( mir->dalvikInsn.opCode) {
3906 case OP_EXECUTE_INLINE: {
3908 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
3909 int offset = offsetof(InterpState, retval);
3910 int operation = dInsn->vB;
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))
3932 break; /* Handle with C routine */
3933 case INLINE_MATH_ABS_FLOAT:
3934 if (genInlinedAbsFloat(cUnit, mir))
3938 case INLINE_MATH_ABS_DOUBLE:
3939 if (genInlinedAbsDouble(cUnit, mir))
3943 case INLINE_STRING_COMPARETO:
3944 if (genInlinedCompareTo(cUnit, mir))
3948 case INLINE_STRING_INDEXOF_I:
3949 if (genInlinedIndexOf(cUnit, mir, true /* I */))
3953 case INLINE_STRING_INDEXOF_II:
3954 if (genInlinedIndexOf(cUnit, mir, false /* I */))
3958 case INLINE_STRING_EQUALS:
3959 case INLINE_MATH_COS:
3960 case INLINE_MATH_SIN:
3961 break; /* Handle with C routine */
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);
3976 opReg(cUnit, kOpBlx, r4PC);
3977 opRegImm(cUnit, kOpAdd, r13, 8);
3978 genZeroCheck(cUnit, r0, mir->offset, NULL);
3987 static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
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);
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.
4006 /* Chaining cell for code that may need warmup. */
4007 static void handleNormalChainingCell(CompilationUnit *cUnit,
4008 unsigned int offset)
4010 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4011 jitToInterpEntries.dvmJitToInterpNormal), r0);
4012 opReg(cUnit, kOpBlx, r0);
4013 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4017 * Chaining cell for instructions that immediately following already translated
4020 static void handleHotChainingCell(CompilationUnit *cUnit,
4021 unsigned int offset)
4023 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4024 jitToInterpEntries.dvmJitToTraceSelect), r0);
4025 opReg(cUnit, kOpBlx, r0);
4026 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
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)
4034 #if defined(WITH_SELF_VERIFICATION)
4035 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
4036 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
4038 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
4039 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
4041 newLIR1(cUnit, kThumbBlxR, r0);
4042 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4046 /* Chaining cell for monomorphic method invocations. */
4047 static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
4048 const Method *callee)
4050 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4051 jitToInterpEntries.dvmJitToTraceSelect), r0);
4052 opReg(cUnit, kOpBlx, r0);
4053 addWordData(cUnit, (int) (callee->insns), true);
4056 /* Chaining cell for monomorphic method invocations. */
4057 static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
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);
4067 * Rechain count. The initial value of 0 here will trigger chaining upon
4068 * the first invocation of this callsite.
4070 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
4073 /* Load the Dalvik PC into r0 and jump to the specified target */
4074 static void handlePCReconstruction(CompilationUnit *cUnit,
4075 ArmLIR *targetLabel)
4078 (ArmLIR **) cUnit->pcReconstructionList.elemList;
4079 int numElems = cUnit->pcReconstructionList.numUsed;
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);
4089 static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
4091 "kMirOpNullNRangeUpCheck",
4092 "kMirOpNullNRangeDownCheck",
4100 * vC = endConditionReg;
4103 * arg[2] = loopBranchConditionCode
4105 static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
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
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];
4118 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
4119 RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
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);
4127 /* regLength <- len(arrayRef) */
4128 regLength = allocTemp(cUnit);
4129 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
4133 * If the loop end condition is ">=" instead of ">", then the largest value
4134 * of the index is "endCondition - 1".
4136 if (dInsn->arg[2] == OP_IF_GE) {
4141 int tReg = allocTemp(cUnit);
4142 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
4143 rlIdxEnd.lowReg = tReg;
4144 freeTemp(cUnit, tReg);
4146 /* Punt if "regIdxEnd < len(Array)" is false */
4147 genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
4148 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4154 * vC = endConditionReg;
4157 * arg[2] = loopBranchConditionCode
4159 static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
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];
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);
4175 /* regLength <- len(arrayRef) */
4176 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
4179 int tReg = allocTemp(cUnit);
4180 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
4181 rlIdxInit.lowReg = tReg;
4182 freeTemp(cUnit, tReg);
4185 /* Punt if "regIdxInit < len(Array)" is false */
4186 genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
4187 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4194 static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
4196 DecodedInstruction *dInsn = &mir->dalvikInsn;
4197 const int minC = dInsn->vB;
4198 RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
4200 /* regIdx <- initial index value */
4201 rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
4203 /* Punt if "regIdxInit + minC >= 0" is false */
4204 genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
4205 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4208 /* Extended MIR instructions like PHI */
4209 static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
4211 int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
4212 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
4214 strcpy(msg, extendedMIROpNames[opOffset]);
4215 newLIR1(cUnit, kArmPseudoExtended, (int) msg);
4217 switch (mir->dalvikInsn.opCode) {
4219 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
4220 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
4223 case kMirOpNullNRangeUpCheck: {
4224 genHoistedChecksForCountUpLoop(cUnit, mir);
4227 case kMirOpNullNRangeDownCheck: {
4228 genHoistedChecksForCountDownLoop(cUnit, mir);
4231 case kMirOpLowerBound: {
4232 genHoistedLowerBoundCheck(cUnit, mir);
4236 genUnconditionalBranch(cUnit,
4237 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
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.
4252 static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
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);
4265 * Next, create two branches - one branch over to the loop body and the
4266 * other branch to the PCR cell to punt.
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;
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;
4281 void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
4283 /* Used to hold the labels of each block */
4285 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
4286 GrowableList chainingListByType[kChainingCellLast];
4290 * Initialize various types chaining lists.
4292 for (i = 0; i < kChainingCellLast; i++) {
4293 dvmInitGrowableList(&chainingListByType[i], 2);
4296 BasicBlock **blockList = cUnit->blockList;
4298 if (cUnit->executionCount) {
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
4308 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
4309 * sub r0, #10 @ back up to addr of executionCount
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);
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;
4332 /* Handle the content in each basic block */
4333 for (i = 0; i < cUnit->numBlocks; i++) {
4334 blockList[i]->visited = true;
4337 labelList[i].operands[0] = blockList[i]->startOffset;
4339 if (blockList[i]->blockType >= kChainingCellLast) {
4341 * Append the label pseudo LIR first. Chaining cells will be handled
4342 * separately afterwards.
4344 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
4347 if (blockList[i]->blockType == kEntryBlock) {
4348 labelList[i].opCode = ARM_PSEUDO_kEntryBlock;
4349 if (blockList[i]->firstMIRInsn == NULL) {
4352 setupLoopEntryBlock(cUnit, blockList[i],
4353 &labelList[blockList[i]->fallThrough->id]);
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);
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);
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],
4382 case kChainingCellInvokePredicted:
4383 labelList[i].opCode =
4384 ARM_PSEUDO_kChainingCellInvokePredicted;
4385 /* handle the codegen later */
4386 dvmInsertGrowableList(
4387 &chainingListByType[kChainingCellInvokePredicted],
4390 case kChainingCellHot:
4391 labelList[i].opCode =
4392 ARM_PSEUDO_kChainingCellHot;
4393 /* handle the codegen later */
4394 dvmInsertGrowableList(
4395 &chainingListByType[kChainingCellHot],
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]);
4405 case kExceptionHandling:
4406 labelList[i].opCode = kArmPseudoEHBlockLabel;
4407 if (cUnit->pcReconstructionList.numUsed) {
4408 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4409 jitToInterpEntries.dvmJitToInterpPunt),
4411 opReg(cUnit, kOpBlx, r1);
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],
4430 ArmLIR *headLIR = NULL;
4432 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
4434 resetRegPool(cUnit);
4435 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
4436 clobberAllRegs(cUnit);
4439 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
4440 resetDefTracking(cUnit);
4443 if (mir->dalvikInsn.opCode >= kMirOpFirst) {
4444 handleExtendedMIR(cUnit, mir);
4449 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
4450 InstructionFormat dalvikFormat =
4451 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
4452 ArmLIR *boundaryLIR =
4453 newLIR2(cUnit, ARM_PSEUDO_kDalvikByteCode_BOUNDARY,
4455 (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
4458 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
4459 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
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;
4471 * Debugging: screen the opcode first to see if it is in the
4472 * do[-not]-compile list
4475 gDvmJit.includeSelectedOp !=
4476 ((gDvmJit.opList[dalvikOpCode >> 3] &
4477 (1 << (dalvikOpCode & 0x7))) !=
4479 #if defined(WITH_SELF_VERIFICATION)
4480 /* Punt on opcodes we can't replay */
4481 if (selfVerificationPuntOps(dalvikOpCode))
4482 singleStepMe = true;
4484 if (singleStepMe || cUnit->allSingleStep) {
4486 genInterpSingleStep(cUnit, mir);
4488 opcodeCoverage[dalvikOpCode]++;
4489 switch (dalvikFormat) {
4493 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
4494 mir, blockList[i], labelList);
4497 notHandled = handleFmt10x(cUnit, mir);
4501 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
4504 notHandled = handleFmt11x(cUnit, mir);
4507 notHandled = handleFmt12x(cUnit, mir);
4510 notHandled = handleFmt20bc(cUnit, mir);
4514 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
4517 notHandled = handleFmt21h(cUnit, mir);
4520 notHandled = handleFmt21s(cUnit, mir);
4523 notHandled = handleFmt21t(cUnit, mir, blockList[i],
4528 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
4531 notHandled = handleFmt22c(cUnit, mir);
4534 notHandled = handleFmt22cs(cUnit, mir);
4537 notHandled = handleFmt22t(cUnit, mir, blockList[i],
4542 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
4545 notHandled = handleFmt23x(cUnit, mir);
4548 notHandled = handleFmt31t(cUnit, mir);
4552 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
4557 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
4561 notHandled = handleFmt3inline(cUnit, mir);
4564 notHandled = handleFmt51l(cUnit, mir);
4572 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
4574 dalvikOpCode, getOpcodeName(dalvikOpCode),
4581 if (blockList[i]->blockType == kEntryBlock) {
4582 dvmCompilerAppendLIR(cUnit,
4583 (LIR *) cUnit->loopAnalysis->branchToBody);
4584 dvmCompilerAppendLIR(cUnit,
4585 (LIR *) cUnit->loopAnalysis->branchToPCR);
4590 * Eliminate redundant loads/stores and delay stores into later
4593 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4594 cUnit->lastLIRInsn);
4599 * Check if the block is terminated due to trace length constraint -
4600 * insert an unconditional branch to the chaining cell.
4602 if (blockList[i]->needFallThroughBranch) {
4603 genUnconditionalBranch(cUnit,
4604 &labelList[blockList[i]->fallThrough->id]);
4609 /* Handle the chaining cells in predefined order */
4610 for (i = 0; i < kChainingCellLast; i++) {
4612 int *blockIdList = (int *) chainingListByType[i].elemList;
4614 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4616 /* No chaining cells of this type */
4617 if (cUnit->numChainingCells[i] == 0)
4620 /* Record the first LIR for a new type of chaining cell */
4621 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4623 for (j = 0; j < chainingListByType[i].numUsed; j++) {
4624 int blockId = blockIdList[j];
4626 /* Align this chaining cell first */
4627 newLIR0(cUnit, kArmPseudoPseudoAlign4);
4629 /* Insert the pseudo chaining instruction */
4630 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4633 switch (blockList[blockId]->blockType) {
4634 case kChainingCellNormal:
4635 handleNormalChainingCell(cUnit,
4636 blockList[blockId]->startOffset);
4638 case kChainingCellInvokeSingleton:
4639 handleInvokeSingletonChainingCell(cUnit,
4640 blockList[blockId]->containingMethod);
4642 case kChainingCellInvokePredicted:
4643 handleInvokePredictedChainingCell(cUnit);
4645 case kChainingCellHot:
4646 handleHotChainingCell(cUnit,
4647 blockList[blockId]->startOffset);
4649 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
4650 case kChainingCellBackwardBranch:
4651 handleBackwardBranchChainingCell(cUnit,
4652 blockList[blockId]->startOffset);
4656 LOGE("Bad blocktype %d", blockList[blockId]->blockType);
4664 * Generate the branch to the dvmJitToInterpNoChain entry point at the end
4665 * of all chaining cells for the overflow cases.
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);
4676 opReg(cUnit, kOpBlx, r2);
4679 dvmCompilerApplyGlobalOptimizations(cUnit);
4682 /* Accept the work and start compiling */
4683 bool dvmCompilerDoWork(CompilerWorkOrder *work)
4687 if (gDvmJit.codeCacheFull) {
4691 switch (work->kind) {
4692 case kWorkOrderMethod:
4693 res = dvmCompileMethod(work->info, &work->result);
4695 case kWorkOrderTrace:
4696 /* Start compilation with maximally allowed trace length */
4697 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
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;;
4714 /* Architectural-specific debugging helpers go here */
4715 void dvmCompilerArchDump(void)
4717 /* Print compiled opcode in this VM instance */
4718 int i, start, streak;
4723 while (opcodeCoverage[i] == 0 && i < 256) {
4729 for (start = i++, streak = 1; i < 256; i++) {
4730 if (opcodeCoverage[i]) {
4734 sprintf(buf+strlen(buf), "%x,", start);
4736 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4739 while (opcodeCoverage[i] == 0 && i < 256) {
4750 sprintf(buf+strlen(buf), "%x", start);
4752 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4756 LOGD("dalvik.vm.jit.op = %s", buf);
4760 /* Common initialization routine for an architecture family */
4761 bool dvmCompilerArchInit()
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);
4773 return compilerArchVariantInit();