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.
28 /* Array holding the entry offset of each template relative to the first one */
29 static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
31 /* Track exercised opcodes */
32 static int opcodeCoverage[256];
34 #if defined(WITH_SELF_VERIFICATION)
35 /* Prevent certain opcodes from being jitted */
36 static inline bool selfVerificationPuntOps(OpCode op)
38 return (op == OP_MONITOR_ENTER || op == OP_MONITOR_EXIT ||
39 op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY);
43 * The following are used to keep compiled loads and stores from modifying
44 * memory during self verification mode.
46 * Stores do not modify memory. Instead, the address and value pair are stored
47 * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
48 * than a word, the word containing the address is loaded first before being
51 * Loads check heapSpace first and return data from there if an entry exists.
52 * Otherwise, data is loaded from memory as usual.
55 /* Decode contents of heapArgSpace to determine addr to load from */
56 static void selfVerificationLoadDecode(HeapArgSpace* heapArgSpace, int* addr)
58 int reg = heapArgSpace->regMap & 0xF;
62 *addr = heapArgSpace->r0;
65 *addr = heapArgSpace->r1;
68 *addr = heapArgSpace->r2;
71 *addr = heapArgSpace->r3;
74 LOGE("ERROR: bad reg used in selfVerificationLoadDecode: %d", reg);
79 /* Decode contents of heapArgSpace to determine reg to load into */
80 static void selfVerificationLoadDecodeData(HeapArgSpace* heapArgSpace,
85 heapArgSpace->r0 = data;
88 heapArgSpace->r1 = data;
91 heapArgSpace->r2 = data;
94 heapArgSpace->r3 = data;
97 LOGE("ERROR: bad reg passed to selfVerificationLoadDecodeData: %d",
103 static void selfVerificationLoad(InterpState* interpState)
105 Thread *self = dvmThreadSelf();
106 ShadowHeap *heapSpacePtr;
107 ShadowSpace *shadowSpace = self->shadowSpace;
108 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
111 selfVerificationLoadDecode(heapArgSpace, &addr);
113 for (heapSpacePtr = shadowSpace->heapSpace;
114 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
115 if (heapSpacePtr->addr == addr) {
116 data = heapSpacePtr->data;
121 if (heapSpacePtr == shadowSpace->heapSpaceTail)
122 data = *((unsigned int*) addr);
124 //LOGD("*** HEAP LOAD: Addr: 0x%x Data: 0x%x", addr, data);
126 int reg = (heapArgSpace->regMap >> 4) & 0xF;
127 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
130 static void selfVerificationLoadByte(InterpState* interpState)
132 Thread *self = dvmThreadSelf();
133 ShadowHeap *heapSpacePtr;
134 ShadowSpace *shadowSpace = self->shadowSpace;
135 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
138 selfVerificationLoadDecode(heapArgSpace, &addr);
140 int maskedAddr = addr & 0xFFFFFFFC;
141 int alignment = addr & 0x3;
143 for (heapSpacePtr = shadowSpace->heapSpace;
144 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
145 if (heapSpacePtr->addr == maskedAddr) {
146 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
147 data = *((unsigned char*) addr);
152 if (heapSpacePtr == shadowSpace->heapSpaceTail)
153 data = *((unsigned char*) addr);
155 //LOGD("*** HEAP LOAD BYTE: Addr: 0x%x Data: 0x%x", addr, data);
157 int reg = (heapArgSpace->regMap >> 4) & 0xF;
158 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
161 static void selfVerificationLoadHalfword(InterpState* interpState)
163 Thread *self = dvmThreadSelf();
164 ShadowHeap *heapSpacePtr;
165 ShadowSpace *shadowSpace = self->shadowSpace;
166 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
169 selfVerificationLoadDecode(heapArgSpace, &addr);
171 int maskedAddr = addr & 0xFFFFFFFC;
172 int alignment = addr & 0x2;
174 for (heapSpacePtr = shadowSpace->heapSpace;
175 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
176 if (heapSpacePtr->addr == maskedAddr) {
177 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
178 data = *((unsigned short*) addr);
183 if (heapSpacePtr == shadowSpace->heapSpaceTail)
184 data = *((unsigned short*) addr);
186 //LOGD("*** HEAP LOAD HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
188 int reg = (heapArgSpace->regMap >> 4) & 0xF;
189 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
192 static void selfVerificationLoadSignedByte(InterpState* interpState)
194 Thread *self = dvmThreadSelf();
195 ShadowHeap* heapSpacePtr;
196 ShadowSpace* shadowSpace = self->shadowSpace;
197 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
200 selfVerificationLoadDecode(heapArgSpace, &addr);
202 int maskedAddr = addr & 0xFFFFFFFC;
203 int alignment = addr & 0x3;
205 for (heapSpacePtr = shadowSpace->heapSpace;
206 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
207 if (heapSpacePtr->addr == maskedAddr) {
208 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
209 data = *((signed char*) addr);
214 if (heapSpacePtr == shadowSpace->heapSpaceTail)
215 data = *((signed char*) addr);
217 //LOGD("*** HEAP LOAD SIGNED BYTE: Addr: 0x%x Data: 0x%x", addr, data);
219 int reg = (heapArgSpace->regMap >> 4) & 0xF;
220 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
223 static void selfVerificationLoadSignedHalfword(InterpState* interpState)
225 Thread *self = dvmThreadSelf();
226 ShadowHeap* heapSpacePtr;
227 ShadowSpace* shadowSpace = self->shadowSpace;
228 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
231 selfVerificationLoadDecode(heapArgSpace, &addr);
233 int maskedAddr = addr & 0xFFFFFFFC;
234 int alignment = addr & 0x2;
236 for (heapSpacePtr = shadowSpace->heapSpace;
237 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
238 if (heapSpacePtr->addr == maskedAddr) {
239 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
240 data = *((signed short*) addr);
245 if (heapSpacePtr == shadowSpace->heapSpaceTail)
246 data = *((signed short*) addr);
248 //LOGD("*** HEAP LOAD SIGNED HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
250 int reg = (heapArgSpace->regMap >> 4) & 0xF;
251 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
254 static void selfVerificationLoadDoubleword(InterpState* interpState)
256 Thread *self = dvmThreadSelf();
257 ShadowHeap* heapSpacePtr;
258 ShadowSpace* shadowSpace = self->shadowSpace;
259 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
262 selfVerificationLoadDecode(heapArgSpace, &addr);
265 unsigned int data = *((unsigned int*) addr);
266 unsigned int data2 = *((unsigned int*) addr2);
268 for (heapSpacePtr = shadowSpace->heapSpace;
269 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
270 if (heapSpacePtr->addr == addr) {
271 data = heapSpacePtr->data;
272 } else if (heapSpacePtr->addr == addr2) {
273 data2 = heapSpacePtr->data;
277 //LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
278 // addr, data, data2);
280 int reg = (heapArgSpace->regMap >> 4) & 0xF;
281 int reg2 = (heapArgSpace->regMap >> 8) & 0xF;
282 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
283 selfVerificationLoadDecodeData(heapArgSpace, data2, reg2);
286 /* Decode contents of heapArgSpace to determine arguments to store. */
287 static void selfVerificationStoreDecode(HeapArgSpace* heapArgSpace,
292 *value = heapArgSpace->r0;
295 *value = heapArgSpace->r1;
298 *value = heapArgSpace->r2;
301 *value = heapArgSpace->r3;
304 LOGE("ERROR: bad reg passed to selfVerificationStoreDecode: %d",
310 static void selfVerificationStore(InterpState* interpState)
312 Thread *self = dvmThreadSelf();
313 ShadowHeap *heapSpacePtr;
314 ShadowSpace *shadowSpace = self->shadowSpace;
315 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
318 int reg0 = heapArgSpace->regMap & 0xF;
319 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
320 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
321 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
323 //LOGD("*** HEAP STORE: Addr: 0x%x Data: 0x%x", addr, data);
325 for (heapSpacePtr = shadowSpace->heapSpace;
326 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
327 if (heapSpacePtr->addr == addr) break;
330 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
331 heapSpacePtr->addr = addr;
332 shadowSpace->heapSpaceTail++;
335 heapSpacePtr->data = data;
338 static void selfVerificationStoreByte(InterpState* interpState)
340 Thread *self = dvmThreadSelf();
341 ShadowHeap *heapSpacePtr;
342 ShadowSpace *shadowSpace = self->shadowSpace;
343 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
346 int reg0 = heapArgSpace->regMap & 0xF;
347 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
348 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
349 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
351 int maskedAddr = addr & 0xFFFFFFFC;
352 int alignment = addr & 0x3;
354 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Data: 0x%x", addr, data);
356 for (heapSpacePtr = shadowSpace->heapSpace;
357 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
358 if (heapSpacePtr->addr == maskedAddr) break;
361 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
362 heapSpacePtr->addr = maskedAddr;
363 heapSpacePtr->data = *((unsigned int*) maskedAddr);
364 shadowSpace->heapSpaceTail++;
367 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
368 *((unsigned char*) addr) = (char) data;
370 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Final Data: 0x%x",
371 // addr, heapSpacePtr->data);
374 static void selfVerificationStoreHalfword(InterpState* interpState)
376 Thread *self = dvmThreadSelf();
377 ShadowHeap *heapSpacePtr;
378 ShadowSpace *shadowSpace = self->shadowSpace;
379 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
382 int reg0 = heapArgSpace->regMap & 0xF;
383 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
384 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
385 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
387 int maskedAddr = addr & 0xFFFFFFFC;
388 int alignment = addr & 0x2;
390 //LOGD("*** HEAP STORE HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
392 for (heapSpacePtr = shadowSpace->heapSpace;
393 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
394 if (heapSpacePtr->addr == maskedAddr) break;
397 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
398 heapSpacePtr->addr = maskedAddr;
399 heapSpacePtr->data = *((unsigned int*) maskedAddr);
400 shadowSpace->heapSpaceTail++;
403 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
404 *((unsigned short*) addr) = (short) data;
406 //LOGD("*** HEAP STORE HALFWORD: Addr: 0x%x Final Data: 0x%x",
407 // addr, heapSpacePtr->data);
410 static void selfVerificationStoreDoubleword(InterpState* interpState)
412 Thread *self = dvmThreadSelf();
413 ShadowHeap *heapSpacePtr;
414 ShadowSpace *shadowSpace = self->shadowSpace;
415 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
417 int addr, data, data2;
418 int reg0 = heapArgSpace->regMap & 0xF;
419 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
420 int reg2 = (heapArgSpace->regMap >> 8) & 0xF;
421 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
422 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
423 selfVerificationStoreDecode(heapArgSpace, &data2, reg2);
426 bool store1 = false, store2 = false;
428 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: 0x%x Data: 0x%x, Data2: 0x%x",
429 // addr, data, data2);
431 for (heapSpacePtr = shadowSpace->heapSpace;
432 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
433 if (heapSpacePtr->addr == addr) {
434 heapSpacePtr->data = data;
436 } else if (heapSpacePtr->addr == addr2) {
437 heapSpacePtr->data = data2;
443 shadowSpace->heapSpaceTail->addr = addr;
444 shadowSpace->heapSpaceTail->data = data;
445 shadowSpace->heapSpaceTail++;
448 shadowSpace->heapSpaceTail->addr = addr2;
449 shadowSpace->heapSpaceTail->data = data2;
450 shadowSpace->heapSpaceTail++;
454 /* Common wrapper function for all memory operations */
455 static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
458 int regMask = (1 << r4PC) | (1 << r3) | (1 << r2) | (1 << r1) | (1 << r0);
460 /* r7 <- InterpState->heapArgSpace */
461 loadConstant(cUnit, r4PC, offsetof(InterpState, heapArgSpace));
462 newLIR3(cUnit, THUMB_ADD_RRR, r7, rGLUE, r4PC);
464 /* Save out values to heapArgSpace */
465 loadConstant(cUnit, r4PC, regMap);
466 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
468 /* Pass interpState pointer to function */
469 newLIR2(cUnit, THUMB_MOV_RR, r0, rGLUE);
471 /* Set function pointer and branch */
472 loadConstant(cUnit, r1, (int) funct);
473 newLIR1(cUnit, THUMB_BLX_R, r1);
475 /* r7 <- InterpState->heapArgSpace */
476 loadConstant(cUnit, r4PC, offsetof(InterpState, heapArgSpace));
477 newLIR3(cUnit, THUMB_ADD_RRR, r7, rGLUE, r4PC);
479 /* Restore register state */
480 newLIR2(cUnit, THUMB_LDMIA, r7, regMask);
485 * The following are building blocks to construct low-level IRs with 0 - 4
488 static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
490 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
491 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
492 insn->opCode = opCode;
493 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
497 static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
500 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
501 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
502 insn->opCode = opCode;
503 insn->operands[0] = dest;
504 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
508 static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
511 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
512 assert(isPseudoOpCode(opCode) ||
513 (EncodingMap[opCode].flags & IS_BINARY_OP));
514 insn->opCode = opCode;
515 insn->operands[0] = dest;
516 insn->operands[1] = src1;
517 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
521 static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
522 int dest, int src1, int src2)
524 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
525 assert(isPseudoOpCode(opCode) ||
526 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
527 insn->opCode = opCode;
528 insn->operands[0] = dest;
529 insn->operands[1] = src1;
530 insn->operands[2] = src2;
531 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
535 static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
536 int dest, int src1, int src2, int info)
538 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
539 assert(isPseudoOpCode(opCode) ||
540 (EncodingMap[opCode].flags & IS_QUAD_OP));
541 insn->opCode = opCode;
542 insn->operands[0] = dest;
543 insn->operands[1] = src1;
544 insn->operands[2] = src2;
545 insn->operands[3] = info;
546 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
551 * If the next instruction is a move-result or move-result-long,
552 * return the target Dalvik instruction and convert the next to a
553 * nop. Otherwise, return -1. Used to optimize method inlining.
555 static int inlinedTarget(MIR *mir)
558 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
559 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT) ||
560 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE))) {
561 mir->next->dalvikInsn.opCode = OP_NOP;
562 return mir->next->dalvikInsn.vA;
571 * The following are building blocks to insert constants into the pool or
572 * instruction streams.
575 /* Add a 32-bit constant either in the constant pool or mixed with code */
576 static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
578 /* Add the constant to the literal pool */
580 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
581 newValue->operands[0] = value;
582 newValue->generic.next = cUnit->wordList;
583 cUnit->wordList = (LIR *) newValue;
586 /* Add the constant in the middle of code stream */
587 newLIR1(cUnit, ARM_16BIT_DATA, (value & 0xffff));
588 newLIR1(cUnit, ARM_16BIT_DATA, (value >> 16));
594 * Search the existing constants in the literal pool for an exact or close match
595 * within specified delta (greater or equal to 0).
597 static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
600 LIR *dataTarget = cUnit->wordList;
602 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
604 return (ArmLIR *) dataTarget;
605 dataTarget = dataTarget->next;
610 /* Perform the actual operation for OP_RETURN_* */
611 static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
613 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
614 #if defined(INVOKE_STATS)
617 int dPC = (int) (cUnit->method->insns + mir->offset);
618 /* Insert branch, but defer setting of target */
619 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
620 /* Set up the place holder to reconstruct this Dalvik PC */
621 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
622 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
623 pcrLabel->operands[0] = dPC;
624 pcrLabel->operands[1] = mir->offset;
625 /* Insert the place holder to the growable list */
626 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
627 /* Branch to the PC reconstruction code */
628 branch->generic.target = (LIR *) pcrLabel;
631 /* Create the PC reconstruction slot if not already done */
632 static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
636 /* Set up the place holder to reconstruct this Dalvik PC */
637 if (pcrLabel == NULL) {
638 int dPC = (int) (cUnit->method->insns + dOffset);
639 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
640 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
641 pcrLabel->operands[0] = dPC;
642 pcrLabel->operands[1] = dOffset;
643 /* Insert the place holder to the growable list */
644 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
646 /* Branch to the PC reconstruction code */
647 branch->generic.target = (LIR *) pcrLabel;
653 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
656 static inline ArmLIR *insertRegRegCheck(CompilationUnit *cUnit,
657 ArmConditionCode cond,
658 int reg1, int reg2, int dOffset,
662 res = opRegReg(cUnit, OP_CMP, reg1, reg2);
663 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
664 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
669 * Perform null-check on a register. vReg is the Dalvik register being checked,
670 * and mReg is the machine register holding the actual value. If internal state
671 * indicates that vReg has been checked before the check request is ignored.
673 static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
674 int dOffset, ArmLIR *pcrLabel)
676 /* This particular Dalvik register has been null-checked */
677 if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
680 dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
681 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
685 * Perform zero-check on a register. Similar to genNullCheck but the value being
686 * checked does not have a corresponding Dalvik register.
688 static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
689 int dOffset, ArmLIR *pcrLabel)
691 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
694 /* Perform bound check on two registers */
695 static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
696 int rBound, int dOffset, ArmLIR *pcrLabel)
698 return insertRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
702 /* Generate a unconditional branch to go to the interpreter */
703 static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
706 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
707 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
710 /* Load a wide field from an object instance */
711 static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
713 DecodedInstruction *dInsn = &mir->dalvikInsn;
714 int reg0, reg1, reg2, reg3;
716 /* Allocate reg0..reg3 into physical registers r0..r3 */
718 /* See if vB is in a native register. If so, reuse it. */
719 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
720 /* Ping reg3 to the other register of the same pair containing reg2 */
723 * Ping reg0 to the first register of the alternate register pair
725 reg0 = (reg2 + 2) & 0xa;
726 reg1 = NEXT_REG(reg0);
728 loadValue(cUnit, dInsn->vB, reg2);
729 loadConstant(cUnit, reg3, fieldOffset);
730 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
731 opRegReg(cUnit, OP_ADD, reg2, reg3);
732 #if !defined(WITH_SELF_VERIFICATION)
733 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
735 int regMap = reg1 << 8 | reg0 << 4 | reg2;
736 selfVerificationMemOpWrapper(cUnit, regMap,
737 &selfVerificationLoadDoubleword);
739 storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
742 /* Store a wide field to an object instance */
743 static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
745 DecodedInstruction *dInsn = &mir->dalvikInsn;
746 int reg0, reg1, reg2, reg3;
748 /* Allocate reg0..reg3 into physical registers r0..r3 */
750 /* See if vB is in a native register. If so, reuse it. */
751 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
752 /* Ping reg3 to the other register of the same pair containing reg2 */
755 * Ping reg0 to the first register of the alternate register pair
757 reg0 = (reg2 + 2) & 0xa;
758 reg1 = NEXT_REG(reg0);
761 loadValue(cUnit, dInsn->vB, reg2);
762 loadValuePair(cUnit, dInsn->vA, reg0, reg1);
763 updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
764 loadConstant(cUnit, reg3, fieldOffset);
765 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
766 opRegReg(cUnit, OP_ADD, reg2, reg3);
767 #if !defined(WITH_SELF_VERIFICATION)
768 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
770 int regMap = reg1 << 8 | reg0 << 4 | reg2;
771 selfVerificationMemOpWrapper(cUnit, regMap,
772 &selfVerificationStoreDoubleword);
777 * Load a field from an object instance
780 static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
783 DecodedInstruction *dInsn = &mir->dalvikInsn;
786 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
787 reg1 = NEXT_REG(reg0);
788 loadValue(cUnit, dInsn->vB, reg0);
789 #if !defined(WITH_SELF_VERIFICATION)
790 loadBaseDisp(cUnit, mir, reg0, fieldOffset, reg1, size, true, dInsn->vB);
792 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
793 /* Combine address and offset */
794 loadConstant(cUnit, reg1, fieldOffset);
795 opRegReg(cUnit, OP_ADD, reg0, reg1);
797 int regMap = reg1 << 4 | reg0;
798 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
800 storeValue(cUnit, reg1, dInsn->vA, reg0);
804 * Store a field to an object instance
807 static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
810 DecodedInstruction *dInsn = &mir->dalvikInsn;
811 int reg0, reg1, reg2;
813 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
814 reg1 = NEXT_REG(reg0);
815 reg2 = NEXT_REG(reg1);
817 loadValue(cUnit, dInsn->vB, reg0);
818 loadValue(cUnit, dInsn->vA, reg2);
819 updateLiveRegister(cUnit, dInsn->vA, reg2);
820 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
821 #if !defined(WITH_SELF_VERIFICATION)
822 storeBaseDisp(cUnit, reg0, fieldOffset, reg2, size, reg1);
824 /* Combine address and offset */
825 loadConstant(cUnit, reg1, fieldOffset);
826 opRegReg(cUnit, OP_ADD, reg0, reg1);
828 int regMap = reg2 << 4 | reg0;
829 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
831 opRegReg(cUnit, OP_SUB, reg0, reg1);
837 * Generate array load
840 static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
841 int vArray, int vIndex, int vDest, int scale)
843 int lenOffset = offsetof(ArrayObject, length);
844 int dataOffset = offsetof(ArrayObject, contents);
845 int reg0, reg1, reg2, reg3;
847 reg0 = selectFirstRegister(cUnit, vArray, false);
848 reg1 = NEXT_REG(reg0);
849 reg2 = NEXT_REG(reg1);
850 reg3 = NEXT_REG(reg2);
852 loadValue(cUnit, vArray, reg2);
853 loadValue(cUnit, vIndex, reg3);
856 ArmLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
857 loadWordDisp(cUnit, reg2, lenOffset, reg0); /* Get len */
858 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone); /* reg2 -> array data */
859 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
860 #if !defined(WITH_SELF_VERIFICATION)
861 if ((size == LONG) || (size == DOUBLE)) {
862 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
863 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
864 loadBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
865 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
866 loadBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
867 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
869 loadBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
870 storeValue(cUnit, reg0, vDest, reg3);
873 //TODO: probably want to move this into loadBaseIndexed
878 funct = (void*) &selfVerificationLoadDoubleword;
881 funct = (void*) &selfVerificationLoad;
884 funct = (void*) &selfVerificationLoadHalfword;
887 funct = (void*) &selfVerificationLoadSignedHalfword;
890 funct = (void*) &selfVerificationLoadByte;
893 funct = (void*) &selfVerificationLoadSignedByte;
899 /* Combine address and index */
901 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
902 opRegReg(cUnit, OP_ADD, reg2, reg3);
904 int regMap = reg1 << 8 | reg0 << 4 | reg2;
905 selfVerificationMemOpWrapper(cUnit, regMap, funct);
907 opRegReg(cUnit, OP_SUB, reg2, reg3);
909 if ((size == LONG) || (size == DOUBLE))
910 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
912 storeValue(cUnit, reg0, vDest, reg3);
917 * Generate array store
920 static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
921 int vArray, int vIndex, int vSrc, int scale)
923 int lenOffset = offsetof(ArrayObject, length);
924 int dataOffset = offsetof(ArrayObject, contents);
925 int reg0, reg1, reg2, reg3;
927 reg0 = selectFirstRegister(cUnit, vArray, false);
928 reg1 = NEXT_REG(reg0);
929 reg2 = NEXT_REG(reg1);
930 reg3 = NEXT_REG(reg2);
932 loadValue(cUnit, vArray, reg2);
933 loadValue(cUnit, vIndex, reg3);
936 ArmLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
938 loadWordDisp(cUnit, reg2, lenOffset, reg0); /* Get len */
939 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone); /* reg2 -> array data */
940 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
941 /* at this point, reg2 points to array, reg3 is unscaled index */
942 #if !defined(WITH_SELF_VERIFICATION)
943 if ((size == LONG) || (size == DOUBLE)) {
944 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
945 loadValuePair(cUnit, vSrc, reg0, reg1);
946 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
948 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
949 storeBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
950 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
951 storeBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
953 loadValue(cUnit, vSrc, reg0);
954 updateLiveRegister(cUnit, vSrc, reg0);
955 storeBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
958 //TODO: probably want to move this into storeBaseIndexed
963 funct = (void*) &selfVerificationStoreDoubleword;
966 funct = (void*) &selfVerificationStore;
970 funct = (void*) &selfVerificationStoreHalfword;
974 funct = (void*) &selfVerificationStoreByte;
981 /* Combine address and index */
982 if ((size == LONG) || (size == DOUBLE)) {
983 loadValuePair(cUnit, vSrc, reg0, reg1);
984 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
986 loadValue(cUnit, vSrc, reg0);
987 updateLiveRegister(cUnit, vSrc, reg0);
990 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
991 opRegReg(cUnit, OP_ADD, reg2, reg3);
993 int regMap = reg1 << 8 | reg0 << 4 | reg2;
994 selfVerificationMemOpWrapper(cUnit, regMap, funct);
996 opRegReg(cUnit, OP_SUB, reg2, reg3);
1000 static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1001 int vSrc1, int vShift)
1004 * Don't mess with the regsiters here as there is a particular calling
1005 * convention to the out-of-line handler.
1007 loadValue(cUnit, vShift, r2);
1008 loadValuePair(cUnit, vSrc1, r0, r1);
1009 switch( mir->dalvikInsn.opCode) {
1011 case OP_SHL_LONG_2ADDR:
1012 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
1015 case OP_SHR_LONG_2ADDR:
1016 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
1019 case OP_USHR_LONG_2ADDR:
1020 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1025 storeValuePair(cUnit, r0, r1, vDest, r2);
1028 bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1029 int vDest, int vSrc1, int vSrc2)
1032 * Don't optimize the regsiter usage here as they are governed by the EABI
1033 * calling convention.
1038 /* TODO: use a proper include file to define these */
1039 float __aeabi_fadd(float a, float b);
1040 float __aeabi_fsub(float a, float b);
1041 float __aeabi_fdiv(float a, float b);
1042 float __aeabi_fmul(float a, float b);
1043 float fmodf(float a, float b);
1045 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1046 reg1 = NEXT_REG(reg0);
1048 switch (mir->dalvikInsn.opCode) {
1049 case OP_ADD_FLOAT_2ADDR:
1051 funct = (void*) __aeabi_fadd;
1053 case OP_SUB_FLOAT_2ADDR:
1055 funct = (void*) __aeabi_fsub;
1057 case OP_DIV_FLOAT_2ADDR:
1059 funct = (void*) __aeabi_fdiv;
1061 case OP_MUL_FLOAT_2ADDR:
1063 funct = (void*) __aeabi_fmul;
1065 case OP_REM_FLOAT_2ADDR:
1067 funct = (void*) fmodf;
1069 case OP_NEG_FLOAT: {
1070 loadValue(cUnit, vSrc2, reg0);
1071 opRegImm(cUnit, OP_ADD, reg0, 0x80000000, reg1);
1072 storeValue(cUnit, reg0, vDest, reg1);
1078 loadConstant(cUnit, r2, (int)funct);
1079 loadValue(cUnit, vSrc1, r0);
1080 loadValue(cUnit, vSrc2, r1);
1081 opReg(cUnit, OP_BLX, r2);
1082 storeValue(cUnit, r0, vDest, r1);
1086 bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1087 int vDest, int vSrc1, int vSrc2)
1090 int reg0, reg1, reg2;
1092 /* TODO: use a proper include file to define these */
1093 double __aeabi_dadd(double a, double b);
1094 double __aeabi_dsub(double a, double b);
1095 double __aeabi_ddiv(double a, double b);
1096 double __aeabi_dmul(double a, double b);
1097 double fmod(double a, double b);
1099 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1100 reg1 = NEXT_REG(reg0);
1101 reg2 = NEXT_REG(reg1);
1103 switch (mir->dalvikInsn.opCode) {
1104 case OP_ADD_DOUBLE_2ADDR:
1106 funct = (void*) __aeabi_dadd;
1108 case OP_SUB_DOUBLE_2ADDR:
1110 funct = (void*) __aeabi_dsub;
1112 case OP_DIV_DOUBLE_2ADDR:
1114 funct = (void*) __aeabi_ddiv;
1116 case OP_MUL_DOUBLE_2ADDR:
1118 funct = (void*) __aeabi_dmul;
1120 case OP_REM_DOUBLE_2ADDR:
1122 funct = (void*) fmod;
1124 case OP_NEG_DOUBLE: {
1125 loadValuePair(cUnit, vSrc2, reg0, reg1);
1126 opRegImm(cUnit, OP_ADD, reg1, 0x80000000, reg2);
1127 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
1134 * Don't optimize the regsiter usage here as they are governed by the EABI
1135 * calling convention.
1137 loadConstant(cUnit, r4PC, (int)funct);
1138 loadValuePair(cUnit, vSrc1, r0, r1);
1139 loadValuePair(cUnit, vSrc2, r2, r3);
1140 opReg(cUnit, OP_BLX, r4PC);
1141 storeValuePair(cUnit, r0, r1, vDest, r2);
1145 static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1146 int vSrc1, int vSrc2)
1148 OpKind firstOp = OP_BKPT;
1149 OpKind secondOp = OP_BKPT;
1150 bool callOut = false;
1153 int reg0, reg1, reg2, reg3;
1154 /* TODO - find proper .h file to declare these */
1155 long long __aeabi_ldivmod(long long op1, long long op2);
1157 switch (mir->dalvikInsn.opCode) {
1163 case OP_ADD_LONG_2ADDR:
1168 case OP_SUB_LONG_2ADDR:
1173 case OP_MUL_LONG_2ADDR:
1174 loadValuePair(cUnit, vSrc1, r0, r1);
1175 loadValuePair(cUnit, vSrc2, r2, r3);
1176 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
1177 storeValuePair(cUnit, r0, r1, vDest, r2);
1181 case OP_DIV_LONG_2ADDR:
1184 callTgt = (void*)__aeabi_ldivmod;
1186 /* NOTE - result is in r2/r3 instead of r0/r1 */
1188 case OP_REM_LONG_2ADDR:
1190 callTgt = (void*)__aeabi_ldivmod;
1194 case OP_AND_LONG_2ADDR:
1199 case OP_OR_LONG_2ADDR:
1204 case OP_XOR_LONG_2ADDR:
1209 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1210 reg1 = NEXT_REG(reg0);
1211 reg2 = NEXT_REG(reg1);
1212 reg3 = NEXT_REG(reg2);
1214 loadValuePair(cUnit, vSrc2, reg0, reg1);
1215 loadConstant(cUnit, reg3, 0);
1216 opRegRegReg(cUnit, OP_SUB, reg2, reg3, reg0);
1217 opRegReg(cUnit, OP_SBC, reg3, reg1);
1218 storeValuePair(cUnit, reg2, reg3, vDest, reg0);
1222 LOGE("Invalid long arith op");
1226 reg0 = selectFirstRegister(cUnit, vSrc1, true);
1227 reg1 = NEXT_REG(reg0);
1228 reg2 = NEXT_REG(reg1);
1229 reg3 = NEXT_REG(reg2);
1231 loadValuePair(cUnit, vSrc1, reg0, reg1);
1232 loadValuePair(cUnit, vSrc2, reg2, reg3);
1233 opRegReg(cUnit, firstOp, reg0, reg2);
1234 opRegReg(cUnit, secondOp, reg1, reg3);
1235 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
1237 * Don't optimize the register usage here as they are governed by the EABI
1238 * calling convention.
1241 loadValuePair(cUnit, vSrc2, r2, r3);
1242 loadConstant(cUnit, r4PC, (int) callTgt);
1243 loadValuePair(cUnit, vSrc1, r0, r1);
1244 opReg(cUnit, OP_BLX, r4PC);
1245 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
1250 static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
1251 int vSrc1, int vSrc2)
1253 OpKind op = OP_BKPT;
1254 bool callOut = false;
1255 bool checkZero = false;
1256 bool threeOperand = false;
1259 int reg0, reg1, regDest;
1261 /* TODO - find proper .h file to declare these */
1262 int __aeabi_idivmod(int op1, int op2);
1263 int __aeabi_idiv(int op1, int op2);
1265 switch (mir->dalvikInsn.opCode) {
1273 case OP_ADD_INT_2ADDR:
1275 threeOperand = true;
1278 case OP_SUB_INT_2ADDR:
1280 threeOperand = true;
1283 case OP_MUL_INT_2ADDR:
1287 case OP_DIV_INT_2ADDR:
1290 callTgt = __aeabi_idiv;
1293 /* NOTE: returns in r1 */
1295 case OP_REM_INT_2ADDR:
1298 callTgt = __aeabi_idivmod;
1302 case OP_AND_INT_2ADDR:
1306 case OP_OR_INT_2ADDR:
1310 case OP_XOR_INT_2ADDR:
1314 case OP_SHL_INT_2ADDR:
1318 case OP_SHR_INT_2ADDR:
1322 case OP_USHR_INT_2ADDR:
1326 LOGE("Invalid word arith op: 0x%x(%d)",
1327 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1331 /* Try to allocate reg0 to the currently cached source operand */
1332 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
1333 reg0 = selectFirstRegister(cUnit, vSrc1, false);
1334 reg1 = NEXT_REG(reg0);
1335 regDest = NEXT_REG(reg1);
1337 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
1338 loadValue(cUnit, vSrc2, reg1);
1340 opRegRegReg(cUnit, op, regDest, reg0, reg1);
1341 storeValue(cUnit, regDest, vDest, reg1);
1343 opRegReg(cUnit, op, reg0, reg1);
1344 storeValue(cUnit, reg0, vDest, reg1);
1347 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1348 reg1 = NEXT_REG(reg0);
1349 regDest = NEXT_REG(reg1);
1351 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
1352 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
1354 opRegRegReg(cUnit, op, regDest, reg1, reg0);
1355 storeValue(cUnit, regDest, vDest, reg1);
1357 opRegReg(cUnit, op, reg1, reg0);
1358 storeValue(cUnit, reg1, vDest, reg0);
1363 * Load the callout target first since it will never be eliminated
1364 * and its value will be used first.
1366 loadConstant(cUnit, r2, (int) callTgt);
1368 * Load vSrc2 first if it is not cached in a native register or it
1369 * is in r0 which will be clobbered if vSrc1 is loaded first.
1371 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
1372 cUnit->registerScoreboard.nativeReg == r0) {
1373 /* Cannot be optimized and won't clobber r0 */
1374 loadValue(cUnit, vSrc2, r1);
1375 /* May be optimized if vSrc1 is cached */
1376 loadValue(cUnit, vSrc1, r0);
1378 loadValue(cUnit, vSrc1, r0);
1379 loadValue(cUnit, vSrc2, r1);
1382 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
1384 opReg(cUnit, OP_BLX, r2);
1385 storeValue(cUnit, retReg, vDest, r2);
1390 static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
1392 OpCode opCode = mir->dalvikInsn.opCode;
1393 int vA = mir->dalvikInsn.vA;
1394 int vB = mir->dalvikInsn.vB;
1395 int vC = mir->dalvikInsn.vC;
1397 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
1398 return genArithOpLong(cUnit,mir, vA, vA, vB);
1400 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
1401 return genArithOpLong(cUnit,mir, vA, vB, vC);
1403 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
1404 return genShiftOpLong(cUnit,mir, vA, vA, vB);
1406 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
1407 return genShiftOpLong(cUnit,mir, vA, vB, vC);
1409 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
1410 return genArithOpInt(cUnit,mir, vA, vA, vB);
1412 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
1413 return genArithOpInt(cUnit,mir, vA, vB, vC);
1415 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
1416 return genArithOpFloat(cUnit,mir, vA, vA, vB);
1418 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
1419 return genArithOpFloat(cUnit, mir, vA, vB, vC);
1421 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1422 return genArithOpDouble(cUnit,mir, vA, vA, vB);
1424 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
1425 return genArithOpDouble(cUnit,mir, vA, vB, vC);
1430 static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1431 int srcSize, int tgtSize)
1434 * Don't optimize the register usage since it calls out to template
1437 loadConstant(cUnit, r2, (int)funct);
1439 loadValue(cUnit, mir->dalvikInsn.vB, r0);
1441 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
1443 opReg(cUnit, OP_BLX, r2);
1445 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1447 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1452 static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1453 DecodedInstruction *dInsn,
1457 unsigned int regMask = 0;
1459 /* Load arguments to r0..r4 */
1460 for (i = 0; i < dInsn->vA; i++) {
1462 loadValue(cUnit, dInsn->arg[i], i);
1465 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
1466 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1467 sizeof(StackSaveArea) + (dInsn->vA << 2), rNone);
1468 /* generate null check */
1470 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1473 storeMultiple(cUnit, r7, regMask);
1477 static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1478 DecodedInstruction *dInsn,
1481 int srcOffset = dInsn->vC << 2;
1482 int numArgs = dInsn->vA;
1488 opRegRegImm(cUnit, OP_ADD, r4PC, rFP, srcOffset, rNone);
1489 /* load [r0 .. min(numArgs,4)] */
1490 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
1491 loadMultiple(cUnit, r4PC, regMask);
1493 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1494 sizeof(StackSaveArea) + (numArgs << 2), rNone);
1495 /* generate null check */
1497 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
1501 * Handle remaining 4n arguments:
1502 * store previously loaded 4 values and load the next 4 values
1505 ArmLIR *loopLabel = NULL;
1507 * r0 contains "this" and it will be used later, so push it to the stack
1508 * first. Pushing r5 (rFP) is just for stack alignment purposes.
1510 opImm(cUnit, OP_PUSH, (1 << r0 | 1 << rFP));
1511 /* No need to generate the loop structure if numArgs <= 11 */
1513 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
1514 loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
1516 storeMultiple(cUnit, r7, regMask);
1517 loadMultiple(cUnit, r4PC, regMask);
1518 /* No need to generate the loop structure if numArgs <= 11 */
1520 opRegImm(cUnit, OP_SUB, rFP, 4, rNone);
1521 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1525 /* Save the last batch of loaded values */
1526 storeMultiple(cUnit, r7, regMask);
1528 /* Generate the loop epilogue - don't use r0 */
1529 if ((numArgs > 4) && (numArgs % 4)) {
1530 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
1531 loadMultiple(cUnit, r4PC, regMask);
1534 opImm(cUnit, OP_POP, (1 << r0 | 1 << rFP));
1536 /* Save the modulo 4 arguments */
1537 if ((numArgs > 4) && (numArgs % 4)) {
1538 storeMultiple(cUnit, r7, regMask);
1543 * Generate code to setup the call stack then jump to the chaining cell if it
1544 * is not a native method.
1546 static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
1547 BasicBlock *bb, ArmLIR *labelList,
1549 const Method *calleeMethod)
1551 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
1553 /* r1 = &retChainingCell */
1554 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
1555 /* r4PC = dalvikCallsite */
1556 loadConstant(cUnit, r4PC,
1557 (int) (cUnit->method->insns + mir->offset));
1558 addrRetChain->generic.target = (LIR *) retChainingCell;
1560 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
1561 * r1 = &ChainingCell
1562 * r4PC = callsiteDPC
1564 if (dvmIsNativeMethod(calleeMethod)) {
1565 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
1566 #if defined(INVOKE_STATS)
1567 gDvmJit.invokeNative++;
1570 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1571 #if defined(INVOKE_STATS)
1572 gDvmJit.invokeChain++;
1574 /* Branch to the chaining cell */
1575 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1577 /* Handle exceptions using the interpreter */
1578 genTrap(cUnit, mir->offset, pcrLabel);
1582 * Generate code to check the validity of a predicted chain and take actions
1583 * based on the result.
1585 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1586 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1587 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1588 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1589 * 0x426a99b2 : blx_2 see above --+
1590 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1591 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1592 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1593 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1594 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1595 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1596 * 0x426a99c0 : blx r7 --+
1597 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1598 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1599 * 0x426a99c6 : blx_2 see above --+
1601 static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1603 ArmLIR *retChainingCell,
1604 ArmLIR *predChainingCell,
1607 /* "this" is already left in r0 by genProcessArgs* */
1609 /* r4PC = dalvikCallsite */
1610 loadConstant(cUnit, r4PC,
1611 (int) (cUnit->method->insns + mir->offset));
1613 /* r1 = &retChainingCell */
1614 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
1615 addrRetChain->generic.target = (LIR *) retChainingCell;
1617 /* r2 = &predictedChainingCell */
1618 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, OP_ADD, r2, rpc, 0,
1620 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1622 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1624 /* return through lr - jump to the chaining cell */
1625 genUnconditionalBranch(cUnit, predChainingCell);
1628 * null-check on "this" may have been eliminated, but we still need a PC-
1629 * reconstruction label for stack overflow bailout.
1631 if (pcrLabel == NULL) {
1632 int dPC = (int) (cUnit->method->insns + mir->offset);
1633 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1634 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
1635 pcrLabel->operands[0] = dPC;
1636 pcrLabel->operands[1] = mir->offset;
1637 /* Insert the place holder to the growable list */
1638 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1641 /* return through lr+2 - punt to the interpreter */
1642 genUnconditionalBranch(cUnit, pcrLabel);
1645 * return through lr+4 - fully resolve the callee method.
1647 * r2 <- &predictedChainCell
1650 * r7 <- this->class->vtable
1653 /* r0 <- calleeMethod */
1654 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
1656 /* Check if rechain limit is reached */
1657 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
1659 ArmLIR *bypassRechaining =
1660 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
1662 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1663 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
1667 * r2 = &predictedChainingCell
1670 * &returnChainingCell has been loaded into r1 but is not needed
1671 * when patching the chaining cell and will be clobbered upon
1672 * returning so it will be reconstructed again.
1674 opReg(cUnit, OP_BLX, r7);
1676 /* r1 = &retChainingCell */
1677 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
1678 addrRetChain->generic.target = (LIR *) retChainingCell;
1680 bypassRechaining->generic.target = (LIR *) addrRetChain;
1682 * r0 = calleeMethod,
1683 * r1 = &ChainingCell,
1684 * r4PC = callsiteDPC,
1686 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1687 #if defined(INVOKE_STATS)
1688 gDvmJit.invokePredictedChain++;
1690 /* Handle exceptions using the interpreter */
1691 genTrap(cUnit, mir->offset, pcrLabel);
1695 * Up calling this function, "this" is stored in r0. The actual class will be
1696 * chased down off r0 and the predicted one will be retrieved through
1697 * predictedChainingCell then a comparison is performed to see whether the
1698 * previously established chaining is still valid.
1700 * The return LIR is a branch based on the comparison result. The actual branch
1701 * target will be setup in the caller.
1703 static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1704 ArmLIR *predChainingCell,
1705 ArmLIR *retChainingCell,
1708 /* r3 now contains this->clazz */
1709 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1712 * r2 now contains predicted class. The starting offset of the
1713 * cached value is 4 bytes into the chaining cell.
1715 ArmLIR *getPredictedClass =
1716 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
1717 getPredictedClass->generic.target = (LIR *) predChainingCell;
1720 * r0 now contains predicted method. The starting offset of the
1721 * cached value is 8 bytes into the chaining cell.
1723 ArmLIR *getPredictedMethod =
1724 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
1725 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1727 /* Load the stats counter to see if it is time to unchain and refresh */
1728 ArmLIR *getRechainingRequestCount =
1729 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
1730 getRechainingRequestCount->generic.target =
1731 (LIR *) predChainingCell;
1733 /* r4PC = dalvikCallsite */
1734 loadConstant(cUnit, r4PC,
1735 (int) (cUnit->method->insns + mir->offset));
1737 /* r1 = &retChainingCell */
1738 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
1739 addrRetChain->generic.target = (LIR *) retChainingCell;
1741 /* Check if r2 (predicted class) == r3 (actual class) */
1742 opRegReg(cUnit, OP_CMP, r2, r3);
1744 return opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
1747 /* Geneate a branch to go back to the interpreter */
1748 static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1750 /* r0 = dalvik pc */
1751 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
1752 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1753 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1754 jitToInterpEntries.dvmJitToInterpPunt), r1);
1755 opReg(cUnit, OP_BLX, r1);
1759 * Attempt to single step one instruction using the interpreter and return
1760 * to the compiled code for the next Dalvik instruction
1762 static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1764 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1765 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1767 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1768 genPuntToInterp(cUnit, mir->offset);
1771 int entryAddr = offsetof(InterpState,
1772 jitToInterpEntries.dvmJitToInterpSingleStep);
1773 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
1774 /* r0 = dalvik pc */
1775 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1776 /* r1 = dalvik pc of following instruction */
1777 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
1778 opReg(cUnit, OP_BLX, r2);
1781 /* Generate conditional branch instructions */
1782 static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1783 ArmConditionCode cond,
1786 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
1787 branch->generic.target = (LIR *) target;
1791 /* Generate unconditional branch instructions */
1792 static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1794 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
1795 branch->generic.target = (LIR *) target;
1799 /* Load the address of a Dalvik register on the frame */
1800 static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
1802 return opRegRegImm(cUnit, OP_ADD, rDest, rFP, vSrc*4, rNone);
1805 /* Load a single value from rFP[src] and store them into rDest */
1806 static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
1808 return loadBaseDisp(cUnit, NULL, rFP, vSrc * 4, rDest, WORD, false, -1);
1811 /* Load a word at base + displacement. Displacement must be word multiple */
1812 static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
1815 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, WORD, false,
1819 static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
1820 int displacement, int rSrc, int rScratch)
1822 return storeBaseDisp(cUnit, rBase, displacement, rSrc, WORD, rScratch);
1825 /* Store a value from rSrc to vDest */
1826 static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
1829 killNullCheckedRegister(cUnit, vDest);
1830 updateLiveRegister(cUnit, vDest, rSrc);
1831 return storeBaseDisp(cUnit, rFP, vDest * 4, rSrc, WORD, rScratch);
1834 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
1837 static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
1841 /* Use reg + imm5*4 to load the values if possible */
1843 res = loadWordDisp(cUnit, rFP, vSrc*4, rDestLo);
1844 loadWordDisp(cUnit, rFP, (vSrc+1)*4, rDestHi);
1846 assert(rDestLo < rDestHi);
1847 res = loadValueAddress(cUnit, vSrc, rDestLo);
1848 loadMultiple(cUnit, rDestLo, (1<<rDestLo) | (1<<rDestHi));
1854 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
1857 static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
1858 int vDest, int rScratch)
1861 killNullCheckedRegister(cUnit, vDest);
1862 killNullCheckedRegister(cUnit, vDest+1);
1863 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
1865 /* Use reg + imm5*4 to store the values if possible */
1867 res = storeWordDisp(cUnit, rFP, vDest*4, rSrcLo, rScratch);
1868 storeWordDisp(cUnit, rFP, (vDest+1)*4, rSrcHi, rScratch);
1870 assert(rSrcLo < rSrcHi);
1871 res = loadValueAddress(cUnit, vDest, rScratch);
1872 storeMultiple(cUnit, rScratch, (1<<rSrcLo) | (1 << rSrcHi));
1877 static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1879 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
1880 dvmCompilerAppendLIR(cUnit, (LIR*)res);
1885 * The following are the first-level codegen routines that analyze the format
1886 * of each bytecode then either dispatch special purpose codegen routines
1887 * or produce corresponding Thumb instructions directly.
1890 static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
1891 BasicBlock *bb, ArmLIR *labelList)
1893 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1894 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1898 static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1900 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1901 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1902 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
1903 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1906 switch (dalvikOpCode) {
1907 case OP_RETURN_VOID:
1908 genReturnCommon(cUnit,mir);
1913 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1923 static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1925 int reg0, reg1, reg2;
1927 switch (mir->dalvikInsn.opCode) {
1930 /* Avoid using the previously used register */
1931 reg0 = selectFirstRegister(cUnit, vNone, false);
1932 reg1 = NEXT_REG(reg0);
1933 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1934 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
1937 case OP_CONST_WIDE_32: {
1938 /* Avoid using the previously used register */
1939 reg0 = selectFirstRegister(cUnit, vNone, true);
1940 reg1 = NEXT_REG(reg0);
1941 reg2 = NEXT_REG(reg1);
1942 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1943 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
1944 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
1953 static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1955 int reg0, reg1, reg2;
1957 /* Avoid using the previously used register */
1958 switch (mir->dalvikInsn.opCode) {
1959 case OP_CONST_HIGH16: {
1960 reg0 = selectFirstRegister(cUnit, vNone, false);
1961 reg1 = NEXT_REG(reg0);
1962 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
1963 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
1966 case OP_CONST_WIDE_HIGH16: {
1967 reg0 = selectFirstRegister(cUnit, vNone, true);
1968 reg1 = NEXT_REG(reg0);
1969 reg2 = NEXT_REG(reg1);
1970 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
1971 loadConstant(cUnit, reg0, 0);
1972 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
1981 static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1983 /* For OP_THROW_VERIFICATION_ERROR */
1984 genInterpSingleStep(cUnit, mir);
1988 static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1990 /* Native register to use if the interested value is vA */
1991 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
1992 /* Native register to use if source is not from Dalvik registers */
1993 int regvNone = selectFirstRegister(cUnit, vNone, false);
1994 /* Similar to regvA but for 64-bit values */
1995 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
1996 /* Similar to regvNone but for 64-bit values */
1997 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
1999 switch (mir->dalvikInsn.opCode) {
2000 case OP_CONST_STRING_JUMBO:
2001 case OP_CONST_STRING: {
2002 void *strPtr = (void*)
2003 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2004 assert(strPtr != NULL);
2005 loadConstant(cUnit, regvNone, (int) strPtr );
2006 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
2009 case OP_CONST_CLASS: {
2010 void *classPtr = (void*)
2011 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2012 assert(classPtr != NULL);
2013 loadConstant(cUnit, regvNone, (int) classPtr );
2014 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
2017 case OP_SGET_OBJECT:
2018 case OP_SGET_BOOLEAN:
2023 int valOffset = offsetof(StaticField, value);
2024 void *fieldPtr = (void*)
2025 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2026 assert(fieldPtr != NULL);
2027 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
2028 #if !defined(WITH_SELF_VERIFICATION)
2029 loadWordDisp(cUnit, regvNone, 0, regvNone);
2031 int regMap = regvNone << 4 | regvNone;
2032 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2035 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
2038 case OP_SGET_WIDE: {
2039 int valOffset = offsetof(StaticField, value);
2040 void *fieldPtr = (void*)
2041 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2042 int reg0, reg1, reg2;
2044 assert(fieldPtr != NULL);
2045 reg0 = regvNoneWide;
2046 reg1 = NEXT_REG(reg0);
2047 reg2 = NEXT_REG(reg1);
2048 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
2049 #if !defined(WITH_SELF_VERIFICATION)
2050 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
2052 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2053 selfVerificationMemOpWrapper(cUnit, regMap,
2054 &selfVerificationLoadDoubleword);
2057 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
2060 case OP_SPUT_OBJECT:
2061 case OP_SPUT_BOOLEAN:
2066 int valOffset = offsetof(StaticField, value);
2067 void *fieldPtr = (void*)
2068 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2070 assert(fieldPtr != NULL);
2071 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
2072 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
2073 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
2074 #if !defined(WITH_SELF_VERIFICATION)
2075 storeWordDisp(cUnit, NEXT_REG(regvA), 0 , regvA, -1);
2077 int regMap = regvA << 4 | NEXT_REG(regvA);
2078 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2082 case OP_SPUT_WIDE: {
2083 int reg0, reg1, reg2;
2084 int valOffset = offsetof(StaticField, value);
2085 void *fieldPtr = (void*)
2086 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2088 assert(fieldPtr != NULL);
2090 reg1 = NEXT_REG(reg0);
2091 reg2 = NEXT_REG(reg1);
2092 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2093 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2094 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
2095 #if !defined(WITH_SELF_VERIFICATION)
2096 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
2098 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2099 selfVerificationMemOpWrapper(cUnit, regMap,
2100 &selfVerificationStoreDoubleword);
2104 case OP_NEW_INSTANCE: {
2106 * Obey the calling convention and don't mess with the register
2109 ClassObject *classPtr = (void*)
2110 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2111 assert(classPtr != NULL);
2112 assert(classPtr->status & CLASS_INITIALIZED);
2113 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
2114 /* It's going to throw, just let the interp. deal with it. */
2115 genInterpSingleStep(cUnit, mir);
2118 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
2119 loadConstant(cUnit, r0, (int) classPtr);
2120 genExportPC(cUnit, mir, r2, r3 );
2121 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
2122 opReg(cUnit, OP_BLX, r4PC);
2123 genZeroCheck(cUnit, r0, mir->offset, NULL);
2124 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2127 case OP_CHECK_CAST: {
2129 * Obey the calling convention and don't mess with the register
2132 ClassObject *classPtr =
2133 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2134 loadConstant(cUnit, r1, (int) classPtr );
2135 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
2136 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* Null? */
2138 opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
2139 /* r0 now contains object->clazz */
2140 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
2141 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
2142 opRegReg(cUnit, OP_CMP, r0, r1);
2144 opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2145 opReg(cUnit, OP_BLX, r4PC);
2146 /* check cast failed - punt to the interpreter */
2147 genZeroCheck(cUnit, r0, mir->offset, NULL);
2148 /* check cast passed - branch target here */
2149 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
2150 branch1->generic.target = (LIR *)target;
2151 branch2->generic.target = (LIR *)target;
2160 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2162 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2163 switch (dalvikOpCode) {
2164 case OP_MOVE_EXCEPTION: {
2165 int offset = offsetof(InterpState, self);
2166 int exOffset = offsetof(Thread, exception);
2167 loadWordDisp(cUnit, rGLUE, offset, r1);
2168 loadWordDisp(cUnit, r1, exOffset, r0);
2169 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2172 case OP_MOVE_RESULT:
2173 case OP_MOVE_RESULT_OBJECT: {
2174 int offset = offsetof(InterpState, retval);
2175 loadWordDisp(cUnit, rGLUE, offset, r0);
2176 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2179 case OP_MOVE_RESULT_WIDE: {
2180 int offset = offsetof(InterpState, retval);
2181 loadWordDisp(cUnit, rGLUE, offset, r0);
2182 loadWordDisp(cUnit, rGLUE, offset+4, r1);
2183 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2186 case OP_RETURN_WIDE: {
2187 int vSrc = mir->dalvikInsn.vA;
2188 int reg0 = selectFirstRegister(cUnit, vSrc, true);
2189 int reg1 = NEXT_REG(reg0);
2190 int rScratch = NEXT_REG(reg1);
2191 int offset = offsetof(InterpState, retval);
2192 loadValuePair(cUnit, vSrc, reg0, reg1);
2193 storeWordDisp(cUnit, rGLUE, offset, reg0, rScratch);
2194 storeWordDisp(cUnit, rGLUE, offset + 4, reg1, rScratch);
2195 genReturnCommon(cUnit,mir);
2199 case OP_RETURN_OBJECT: {
2200 int vSrc = mir->dalvikInsn.vA;
2201 int reg0 = selectFirstRegister(cUnit, vSrc, false);
2202 int rScratch = NEXT_REG(reg0);
2203 loadValue(cUnit, vSrc, reg0);
2204 storeWordDisp(cUnit, rGLUE, offsetof(InterpState, retval),
2206 genReturnCommon(cUnit,mir);
2209 case OP_MONITOR_ENTER:
2210 case OP_MONITOR_EXIT: {
2211 int offset = offsetof(InterpState, self);
2212 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2213 loadWordDisp(cUnit, rGLUE, offset, r0);
2214 if (dalvikOpCode == OP_MONITOR_ENTER) {
2215 loadConstant(cUnit, r2, (int)dvmLockObject);
2217 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2219 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
2221 opReg(cUnit, OP_BLX, r2);
2225 genInterpSingleStep(cUnit, mir);
2234 static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
2236 OpCode opCode = mir->dalvikInsn.opCode;
2238 float __aeabi_i2f( int op1 );
2239 int __aeabi_f2iz( float op1 );
2240 float __aeabi_d2f( double op1 );
2241 double __aeabi_f2d( float op1 );
2242 double __aeabi_i2d( int op1 );
2243 int __aeabi_d2iz( double op1 );
2244 float __aeabi_l2f( long op1 );
2245 double __aeabi_l2d( long op1 );
2246 s8 dvmJitf2l( float op1 );
2247 s8 dvmJitd2l( double op1 );
2250 case OP_INT_TO_FLOAT:
2251 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2252 case OP_FLOAT_TO_INT:
2253 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2254 case OP_DOUBLE_TO_FLOAT:
2255 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2256 case OP_FLOAT_TO_DOUBLE:
2257 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2258 case OP_INT_TO_DOUBLE:
2259 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2260 case OP_DOUBLE_TO_INT:
2261 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2262 case OP_FLOAT_TO_LONG:
2263 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
2264 case OP_LONG_TO_FLOAT:
2265 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2266 case OP_DOUBLE_TO_LONG:
2267 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
2268 case OP_LONG_TO_DOUBLE:
2269 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2276 static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2278 OpCode opCode = mir->dalvikInsn.opCode;
2279 int vSrc1Dest = mir->dalvikInsn.vA;
2280 int vSrc2 = mir->dalvikInsn.vB;
2281 int reg0, reg1, reg2;
2283 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
2284 return genArithOp( cUnit, mir );
2288 * If data type is 64-bit, re-calculate the register numbers in the
2289 * corresponding cases.
2291 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2292 reg1 = NEXT_REG(reg0);
2293 reg2 = NEXT_REG(reg1);
2296 case OP_INT_TO_FLOAT:
2297 case OP_FLOAT_TO_INT:
2298 case OP_DOUBLE_TO_FLOAT:
2299 case OP_FLOAT_TO_DOUBLE:
2300 case OP_INT_TO_DOUBLE:
2301 case OP_DOUBLE_TO_INT:
2302 case OP_FLOAT_TO_LONG:
2303 case OP_LONG_TO_FLOAT:
2304 case OP_DOUBLE_TO_LONG:
2305 case OP_LONG_TO_DOUBLE:
2306 return genConversion(cUnit, mir);
2309 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2312 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
2314 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2316 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2317 case OP_MOVE_WIDE: {
2318 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2319 reg1 = NEXT_REG(reg0);
2320 reg2 = NEXT_REG(reg1);
2322 loadValuePair(cUnit, vSrc2, reg0, reg1);
2323 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
2326 case OP_INT_TO_LONG: {
2327 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2328 reg1 = NEXT_REG(reg0);
2329 reg2 = NEXT_REG(reg1);
2331 loadValue(cUnit, vSrc2, reg0);
2332 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
2333 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
2337 case OP_MOVE_OBJECT:
2338 case OP_LONG_TO_INT:
2339 loadValue(cUnit, vSrc2, reg0);
2340 storeValue(cUnit, reg0, vSrc1Dest, reg1);
2342 case OP_INT_TO_BYTE:
2343 loadValue(cUnit, vSrc2, reg0);
2344 opRegReg(cUnit, OP_2BYTE, reg1, reg0);
2345 storeValue(cUnit, reg1, vSrc1Dest, reg2);
2347 case OP_INT_TO_SHORT:
2348 loadValue(cUnit, vSrc2, reg0);
2349 opRegReg(cUnit, OP_2SHORT, reg1, reg0);
2350 storeValue(cUnit, reg1, vSrc1Dest, reg2);
2352 case OP_INT_TO_CHAR:
2353 loadValue(cUnit, vSrc2, reg0);
2354 opRegReg(cUnit, OP_2CHAR, reg1, reg0);
2355 storeValue(cUnit, reg1, vSrc1Dest, reg2);
2357 case OP_ARRAY_LENGTH: {
2358 int lenOffset = offsetof(ArrayObject, length);
2359 loadValue(cUnit, vSrc2, reg1);
2360 genNullCheck(cUnit, vSrc2, reg1, mir->offset, NULL);
2361 loadWordDisp(cUnit, reg1, lenOffset, reg0);
2362 storeValue(cUnit, reg0, vSrc1Dest, reg1);
2371 static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2373 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2374 int reg0, reg1, reg2;
2376 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
2377 if (dalvikOpCode == OP_CONST_WIDE_16) {
2378 int vDest = mir->dalvikInsn.vA;
2379 int BBBB = mir->dalvikInsn.vB;
2381 reg0 = selectFirstRegister(cUnit, vNone, true);
2382 reg1 = NEXT_REG(reg0);
2383 reg2 = NEXT_REG(reg1);
2385 loadConstant(cUnit, reg0, BBBB);
2386 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
2388 /* Save the long values to the specified Dalvik register pair */
2389 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
2390 } else if (dalvikOpCode == OP_CONST_16) {
2391 int vDest = mir->dalvikInsn.vA;
2392 int BBBB = mir->dalvikInsn.vB;
2394 reg0 = selectFirstRegister(cUnit, vNone, false);
2395 reg1 = NEXT_REG(reg0);
2397 loadConstant(cUnit, reg0, BBBB);
2398 storeValue(cUnit, reg0, vDest, reg1);
2405 /* Compare agaist zero */
2406 static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2409 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2410 ArmConditionCode cond;
2411 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2413 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2414 opRegImm(cUnit, OP_CMP, reg0, 0, rNone);
2416 //TUNING: break this out to allow use of Thumb2 CB[N]Z
2417 switch (dalvikOpCode) {
2438 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2441 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2442 /* This mostly likely will be optimized away in a later phase */
2443 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2447 static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2449 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2450 int vSrc = mir->dalvikInsn.vB;
2451 int vDest = mir->dalvikInsn.vA;
2452 int lit = mir->dalvikInsn.vC;
2454 int reg0, reg1, regDest;
2456 reg0 = selectFirstRegister(cUnit, vSrc, false);
2457 reg1 = NEXT_REG(reg0);
2458 regDest = NEXT_REG(reg1);
2460 int __aeabi_idivmod(int op1, int op2);
2461 int __aeabi_idiv(int op1, int op2);
2463 switch (dalvikOpCode) {
2464 case OP_ADD_INT_LIT8:
2465 case OP_ADD_INT_LIT16:
2466 loadValue(cUnit, vSrc, reg0);
2467 opRegImm(cUnit, OP_ADD, reg0, lit, reg1);
2468 storeValue(cUnit, reg0, vDest, reg1);
2471 case OP_RSUB_INT_LIT8:
2473 loadValue(cUnit, vSrc, reg1);
2474 loadConstant(cUnit, reg0, lit);
2475 opRegRegReg(cUnit, OP_SUB, regDest, reg0, reg1);
2476 storeValue(cUnit, regDest, vDest, reg1);
2479 case OP_MUL_INT_LIT8:
2480 case OP_MUL_INT_LIT16:
2481 case OP_AND_INT_LIT8:
2482 case OP_AND_INT_LIT16:
2483 case OP_OR_INT_LIT8:
2484 case OP_OR_INT_LIT16:
2485 case OP_XOR_INT_LIT8:
2486 case OP_XOR_INT_LIT16:
2487 loadValue(cUnit, vSrc, reg0);
2488 switch (dalvikOpCode) {
2489 case OP_MUL_INT_LIT8:
2490 case OP_MUL_INT_LIT16:
2493 case OP_AND_INT_LIT8:
2494 case OP_AND_INT_LIT16:
2497 case OP_OR_INT_LIT8:
2498 case OP_OR_INT_LIT16:
2501 case OP_XOR_INT_LIT8:
2502 case OP_XOR_INT_LIT16:
2508 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2509 storeValue(cUnit, regDest, vDest, reg1);
2512 case OP_SHL_INT_LIT8:
2513 case OP_SHR_INT_LIT8:
2514 case OP_USHR_INT_LIT8:
2515 loadValue(cUnit, vSrc, reg0);
2516 switch (dalvikOpCode) {
2517 case OP_SHL_INT_LIT8:
2520 case OP_SHR_INT_LIT8:
2523 case OP_USHR_INT_LIT8:
2526 default: dvmAbort();
2528 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2529 storeValue(cUnit, regDest, vDest, reg1);
2532 case OP_DIV_INT_LIT8:
2533 case OP_DIV_INT_LIT16:
2534 /* Register usage based on the calling convention */
2536 /* Let the interpreter deal with div by 0 */
2537 genInterpSingleStep(cUnit, mir);
2540 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2541 loadConstant(cUnit, r1, lit);
2542 loadValue(cUnit, vSrc, r0);
2543 opReg(cUnit, OP_BLX, r2);
2544 storeValue(cUnit, r0, vDest, r2);
2547 case OP_REM_INT_LIT8:
2548 case OP_REM_INT_LIT16:
2549 /* Register usage based on the calling convention */
2551 /* Let the interpreter deal with div by 0 */
2552 genInterpSingleStep(cUnit, mir);
2555 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2556 loadConstant(cUnit, r1, lit);
2557 loadValue(cUnit, vSrc, r0);
2558 opReg(cUnit, OP_BLX, r2);
2559 storeValue(cUnit, r1, vDest, r2);
2567 static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2569 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2572 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2573 InstField *pInstField = (InstField *)
2574 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2577 assert(pInstField != NULL);
2578 fieldOffset = pInstField->byteOffset;
2580 /* To make the compiler happy */
2583 switch (dalvikOpCode) {
2584 case OP_NEW_ARRAY: {
2585 void *classPtr = (void*)
2586 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2587 assert(classPtr != NULL);
2588 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2589 loadConstant(cUnit, r0, (int) classPtr );
2590 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
2592 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2593 genExportPC(cUnit, mir, r2, r3 );
2594 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2595 opReg(cUnit, OP_BLX, r4PC);
2596 /* Note: on failure, we'll bail and reinterpret */
2597 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
2598 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2601 case OP_INSTANCE_OF: {
2602 ClassObject *classPtr =
2603 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2604 assert(classPtr != NULL);
2605 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
2606 loadConstant(cUnit, r2, (int) classPtr );
2607 //TUNING: compare to 0 primative to allow use of CB[N]Z
2608 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
2609 /* When taken r0 has NULL which can be used for store directly */
2610 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
2611 /* r1 now contains object->clazz */
2612 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
2613 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
2614 loadConstant(cUnit, r0, 1); /* Assume true */
2615 opRegReg(cUnit, OP_CMP, r1, r2);
2616 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2617 opRegReg(cUnit, OP_MOV, r0, r1);
2618 opRegReg(cUnit, OP_MOV, r1, r2);
2619 opReg(cUnit, OP_BLX, r4PC);
2620 /* branch target here */
2621 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
2622 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2623 branch1->generic.target = (LIR *)target;
2624 branch2->generic.target = (LIR *)target;
2628 genIGetWide(cUnit, mir, fieldOffset);
2631 case OP_IGET_OBJECT:
2632 genIGet(cUnit, mir, WORD, fieldOffset);
2634 case OP_IGET_BOOLEAN:
2635 genIGet(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
2638 genIGet(cUnit, mir, SIGNED_BYTE, fieldOffset);
2641 genIGet(cUnit, mir, UNSIGNED_HALF, fieldOffset);
2644 genIGet(cUnit, mir, SIGNED_HALF, fieldOffset);
2647 genIPutWide(cUnit, mir, fieldOffset);
2650 case OP_IPUT_OBJECT:
2651 genIPut(cUnit, mir, WORD, fieldOffset);
2655 genIPut(cUnit, mir, UNSIGNED_HALF, fieldOffset);
2658 case OP_IPUT_BOOLEAN:
2659 genIPut(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
2667 static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2669 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2670 int fieldOffset = mir->dalvikInsn.vC;
2671 switch (dalvikOpCode) {
2673 case OP_IGET_OBJECT_QUICK:
2674 genIGet(cUnit, mir, WORD, fieldOffset);
2677 case OP_IPUT_OBJECT_QUICK:
2678 genIPut(cUnit, mir, WORD, fieldOffset);
2680 case OP_IGET_WIDE_QUICK:
2681 genIGetWide(cUnit, mir, fieldOffset);
2683 case OP_IPUT_WIDE_QUICK:
2684 genIPutWide(cUnit, mir, fieldOffset);
2693 /* Compare agaist zero */
2694 static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2697 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2698 ArmConditionCode cond;
2701 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2702 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2703 reg1 = NEXT_REG(reg0);
2704 /* Load vB first since vA can be fetched via a move */
2705 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2706 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2708 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2709 reg1 = NEXT_REG(reg0);
2710 /* Load vA first since vB can be fetched via a move */
2711 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2712 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2714 opRegReg(cUnit, OP_CMP, reg0, reg1);
2716 switch (dalvikOpCode) {
2737 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2740 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2741 /* This mostly likely will be optimized away in a later phase */
2742 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2746 static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2748 OpCode opCode = mir->dalvikInsn.opCode;
2749 int vSrc1Dest = mir->dalvikInsn.vA;
2750 int vSrc2 = mir->dalvikInsn.vB;
2751 int reg0, reg1, reg2;
2755 case OP_MOVE_OBJECT_16:
2756 case OP_MOVE_FROM16:
2757 case OP_MOVE_OBJECT_FROM16: {
2758 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2759 reg1 = NEXT_REG(reg0);
2760 loadValue(cUnit, vSrc2, reg0);
2761 storeValue(cUnit, reg0, vSrc1Dest, reg1);
2764 case OP_MOVE_WIDE_16:
2765 case OP_MOVE_WIDE_FROM16: {
2766 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2767 reg1 = NEXT_REG(reg0);
2768 reg2 = NEXT_REG(reg1);
2769 loadValuePair(cUnit, vSrc2, reg0, reg1);
2770 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
2779 static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2781 OpCode opCode = mir->dalvikInsn.opCode;
2782 int vA = mir->dalvikInsn.vA;
2783 int vB = mir->dalvikInsn.vB;
2784 int vC = mir->dalvikInsn.vC;
2786 /* Don't optimize for register usage since out-of-line handlers are used */
2787 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2788 return genArithOp( cUnit, mir );
2794 case OP_CMPL_DOUBLE:
2795 case OP_CMPG_DOUBLE:
2796 return genCmpX(cUnit, mir, vA, vB, vC);
2798 genCmpLong(cUnit, mir, vA, vB, vC);
2801 genArrayGet(cUnit, mir, LONG, vB, vC, vA, 3);
2804 case OP_AGET_OBJECT:
2805 genArrayGet(cUnit, mir, WORD, vB, vC, vA, 2);
2807 case OP_AGET_BOOLEAN:
2808 genArrayGet(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
2811 genArrayGet(cUnit, mir, SIGNED_BYTE, vB, vC, vA, 0);
2814 genArrayGet(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
2817 genArrayGet(cUnit, mir, SIGNED_HALF, vB, vC, vA, 1);
2820 genArrayPut(cUnit, mir, LONG, vB, vC, vA, 3);
2823 case OP_APUT_OBJECT:
2824 genArrayPut(cUnit, mir, WORD, vB, vC, vA, 2);
2828 genArrayPut(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
2831 case OP_APUT_BOOLEAN:
2832 genArrayPut(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
2840 static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2842 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2843 switch (dalvikOpCode) {
2844 case OP_FILL_ARRAY_DATA: {
2845 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2846 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2847 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2848 (int) (cUnit->method->insns + mir->offset));
2849 genExportPC(cUnit, mir, r2, r3 );
2850 opReg(cUnit, OP_BLX, r4PC);
2851 genZeroCheck(cUnit, r0, mir->offset, NULL);
2856 * - Add a 1 to 3-entry per-location cache here to completely
2857 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2858 * - Use out-of-line handlers for both of these
2860 case OP_PACKED_SWITCH:
2861 case OP_SPARSE_SWITCH: {
2862 if (dalvikOpCode == OP_PACKED_SWITCH) {
2863 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2865 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2867 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2868 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2869 (int) (cUnit->method->insns + mir->offset));
2870 opReg(cUnit, OP_BLX, r4PC);
2871 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
2872 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2873 jitToInterpEntries.dvmJitToInterpNoChain), r2);
2874 opRegReg(cUnit, OP_ADD, r0, r0);
2875 opRegRegReg(cUnit, OP_ADD, r4PC, r0, r1);
2876 opReg(cUnit, OP_BLX, r2);
2885 static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2888 ArmLIR *retChainingCell = NULL;
2889 ArmLIR *pcrLabel = NULL;
2891 if (bb->fallThrough != NULL)
2892 retChainingCell = &labelList[bb->fallThrough->id];
2894 DecodedInstruction *dInsn = &mir->dalvikInsn;
2895 switch (mir->dalvikInsn.opCode) {
2897 * calleeMethod = this->clazz->vtable[
2898 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2901 case OP_INVOKE_VIRTUAL:
2902 case OP_INVOKE_VIRTUAL_RANGE: {
2903 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2905 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2908 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2909 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2911 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2913 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2920 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2921 * ->pResMethods[BBBB]->methodIndex]
2923 /* TODO - not excersized in RunPerf.jar */
2924 case OP_INVOKE_SUPER:
2925 case OP_INVOKE_SUPER_RANGE: {
2926 int mIndex = cUnit->method->clazz->pDvmDex->
2927 pResMethods[dInsn->vB]->methodIndex;
2928 const Method *calleeMethod =
2929 cUnit->method->clazz->super->vtable[mIndex];
2931 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2932 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2934 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2936 /* r0 = calleeMethod */
2937 loadConstant(cUnit, r0, (int) calleeMethod);
2939 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2943 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2944 case OP_INVOKE_DIRECT:
2945 case OP_INVOKE_DIRECT_RANGE: {
2946 const Method *calleeMethod =
2947 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2949 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2950 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2952 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2954 /* r0 = calleeMethod */
2955 loadConstant(cUnit, r0, (int) calleeMethod);
2957 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2961 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2962 case OP_INVOKE_STATIC:
2963 case OP_INVOKE_STATIC_RANGE: {
2964 const Method *calleeMethod =
2965 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2967 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2968 genProcessArgsNoRange(cUnit, mir, dInsn,
2969 NULL /* no null check */);
2971 genProcessArgsRange(cUnit, mir, dInsn,
2972 NULL /* no null check */);
2974 /* r0 = calleeMethod */
2975 loadConstant(cUnit, r0, (int) calleeMethod);
2977 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2982 * TODO: When we move to using upper registers in Thumb2, make sure
2983 * the register allocater is told that r9, r10, & r12 are killed
2987 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2988 * BBBB, method, method->clazz->pDvmDex)
2990 * Given "invoke-interface {v0}", the following is the generated code:
2992 * 0x426a9abe : ldr r0, [r5, #0] --+
2993 * 0x426a9ac0 : mov r7, r5 |
2994 * 0x426a9ac2 : sub r7, #24 |
2995 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
2996 * 0x426a9ac6 : beq 0x426a9afe |
2997 * 0x426a9ac8 : stmia r7, <r0> --+
2998 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2999 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3000 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3001 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3002 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3003 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3004 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
3005 * 0x426a9ad8 : mov r9, r1 --+
3006 * 0x426a9ada : mov r10, r2 |
3007 * 0x426a9adc : mov r12, r3 |
3008 * 0x426a9ade : mov r0, r3 |
3009 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3010 * 0x426a9ae2 : ldr r2, [pc, #76] |
3011 * 0x426a9ae4 : ldr r3, [pc, #68] |
3012 * 0x426a9ae6 : ldr r7, [pc, #64] |
3013 * 0x426a9ae8 : blx r7 --+
3014 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
3015 * 0x426a9aec : cmp r1, #0 --> compare against 0
3016 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3017 * 0x426a9af0 : ldr r7, [r6, #96] --+
3018 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
3019 * 0x426a9af4 : mov r3, r12 |
3020 * 0x426a9af6 : blx r7 --+
3021 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3022 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3023 * 0x426a9afc : blx_2 see above --+
3024 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3025 * 0x426a9afe (0042): ldr r0, [pc, #52]
3026 * Exception_Handling:
3027 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3028 * 0x426a9b02 (0046): blx r1
3029 * 0x426a9b04 (0048): .align4
3030 * -------- chaining cell (hot): 0x0021
3031 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3032 * 0x426a9b06 (004a): blx r0
3033 * 0x426a9b08 (004c): data 0x7872(30834)
3034 * 0x426a9b0a (004e): data 0x428b(17035)
3035 * 0x426a9b0c (0050): .align4
3036 * -------- chaining cell (predicted)
3037 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3038 * 0x426a9b0e (0052): data 0x0000(0)
3039 * 0x426a9b10 (0054): data 0x0000(0) --> class
3040 * 0x426a9b12 (0056): data 0x0000(0)
3041 * 0x426a9b14 (0058): data 0x0000(0) --> method
3042 * 0x426a9b16 (005a): data 0x0000(0)
3043 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3044 * 0x426a9b1a (005e): data 0x0000(0)
3045 * 0x426a9b28 (006c): .word (0xad0392a5)
3046 * 0x426a9b2c (0070): .word (0x6e750)
3047 * 0x426a9b30 (0074): .word (0x4109a618)
3048 * 0x426a9b34 (0078): .word (0x428b786c)
3050 case OP_INVOKE_INTERFACE:
3051 case OP_INVOKE_INTERFACE_RANGE: {
3052 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3053 int methodIndex = dInsn->vB;
3055 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3056 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3058 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3060 /* "this" is already left in r0 by genProcessArgs* */
3062 /* r4PC = dalvikCallsite */
3063 loadConstant(cUnit, r4PC,
3064 (int) (cUnit->method->insns + mir->offset));
3066 /* r1 = &retChainingCell */
3067 ArmLIR *addrRetChain =
3068 opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
3069 addrRetChain->generic.target = (LIR *) retChainingCell;
3071 /* r2 = &predictedChainingCell */
3072 ArmLIR *predictedChainingCell =
3073 opRegRegImm(cUnit, OP_ADD, r2, rpc, 0, rNone);
3074 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3076 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3078 /* return through lr - jump to the chaining cell */
3079 genUnconditionalBranch(cUnit, predChainingCell);
3082 * null-check on "this" may have been eliminated, but we still need
3083 * a PC-reconstruction label for stack overflow bailout.
3085 if (pcrLabel == NULL) {
3086 int dPC = (int) (cUnit->method->insns + mir->offset);
3087 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3088 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
3089 pcrLabel->operands[0] = dPC;
3090 pcrLabel->operands[1] = mir->offset;
3091 /* Insert the place holder to the growable list */
3092 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3095 /* return through lr+2 - punt to the interpreter */
3096 genUnconditionalBranch(cUnit, pcrLabel);
3099 * return through lr+4 - fully resolve the callee method.
3101 * r2 <- &predictedChainCell
3104 * r7 <- this->class->vtable
3107 /* Save count, &predictedChainCell, and class to high regs first */
3108 opRegReg(cUnit, OP_MOV, r9, r1);
3109 opRegReg(cUnit, OP_MOV, r10, r2);
3110 opRegReg(cUnit, OP_MOV, r12, r3);
3112 /* r0 now contains this->clazz */
3113 opRegReg(cUnit, OP_MOV, r0, r3);
3116 loadConstant(cUnit, r1, dInsn->vB);
3118 /* r2 = method (caller) */
3119 loadConstant(cUnit, r2, (int) cUnit->method);
3122 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3124 loadConstant(cUnit, r7,
3125 (intptr_t) dvmFindInterfaceMethodInCache);
3126 opReg(cUnit, OP_BLX, r7);
3128 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3130 opRegReg(cUnit, OP_MOV, r1, r9);
3132 /* Check if rechain limit is reached */
3133 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
3135 ArmLIR *bypassRechaining =
3136 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
3138 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3139 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
3141 opRegReg(cUnit, OP_MOV, r2, r10);
3142 opRegReg(cUnit, OP_MOV, r3, r12);
3146 * r2 = &predictedChainingCell
3149 * &returnChainingCell has been loaded into r1 but is not needed
3150 * when patching the chaining cell and will be clobbered upon
3151 * returning so it will be reconstructed again.
3153 opReg(cUnit, OP_BLX, r7);
3155 /* r1 = &retChainingCell */
3156 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
3157 addrRetChain->generic.target = (LIR *) retChainingCell;
3159 bypassRechaining->generic.target = (LIR *) addrRetChain;
3162 * r0 = this, r1 = calleeMethod,
3163 * r1 = &ChainingCell,
3164 * r4PC = callsiteDPC,
3166 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3167 #if defined(INVOKE_STATS)
3168 gDvmJit.invokePredictedChain++;
3170 /* Handle exceptions using the interpreter */
3171 genTrap(cUnit, mir->offset, pcrLabel);
3175 case OP_INVOKE_DIRECT_EMPTY: {
3178 case OP_FILLED_NEW_ARRAY:
3179 case OP_FILLED_NEW_ARRAY_RANGE: {
3180 /* Just let the interpreter deal with these */
3181 genInterpSingleStep(cUnit, mir);
3190 static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
3191 BasicBlock *bb, ArmLIR *labelList)
3193 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3194 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3195 ArmLIR *pcrLabel = NULL;
3197 DecodedInstruction *dInsn = &mir->dalvikInsn;
3198 switch (mir->dalvikInsn.opCode) {
3199 /* calleeMethod = this->clazz->vtable[BBBB] */
3200 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3201 case OP_INVOKE_VIRTUAL_QUICK: {
3202 int methodIndex = dInsn->vB;
3203 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3204 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3206 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3208 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3214 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3215 case OP_INVOKE_SUPER_QUICK:
3216 case OP_INVOKE_SUPER_QUICK_RANGE: {
3217 const Method *calleeMethod =
3218 cUnit->method->clazz->super->vtable[dInsn->vB];
3220 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3221 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3223 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3225 /* r0 = calleeMethod */
3226 loadConstant(cUnit, r0, (int) calleeMethod);
3228 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3230 /* Handle exceptions using the interpreter */
3231 genTrap(cUnit, mir->offset, pcrLabel);
3241 * NOTE: We assume here that the special native inline routines
3242 * are side-effect free. By making this assumption, we can safely
3243 * re-execute the routine from the interpreter if it decides it
3244 * wants to throw an exception. We still need to EXPORT_PC(), though.
3246 static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3248 DecodedInstruction *dInsn = &mir->dalvikInsn;
3249 switch( mir->dalvikInsn.opCode) {
3250 case OP_EXECUTE_INLINE: {
3252 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
3253 int offset = offsetof(InterpState, retval);
3254 int operation = dInsn->vB;
3256 switch (operation) {
3257 case INLINE_EMPTYINLINEMETHOD:
3258 return false; /* Nop */
3259 case INLINE_STRING_LENGTH:
3260 return genInlinedStringLength(cUnit, mir);
3261 case INLINE_MATH_ABS_INT:
3262 return genInlinedAbsInt(cUnit, mir);
3263 case INLINE_MATH_ABS_LONG:
3264 return genInlinedAbsLong(cUnit, mir);
3265 case INLINE_MATH_MIN_INT:
3266 return genInlinedMinMaxInt(cUnit, mir, true);
3267 case INLINE_MATH_MAX_INT:
3268 return genInlinedMinMaxInt(cUnit, mir, false);
3269 case INLINE_STRING_CHARAT:
3270 return genInlinedStringCharAt(cUnit, mir);
3271 case INLINE_MATH_SQRT:
3272 if (genInlineSqrt(cUnit, mir))
3275 break; /* Handle with C routine */
3276 case INLINE_MATH_COS:
3277 case INLINE_MATH_SIN:
3278 break; /* Handle with C routine */
3279 case INLINE_MATH_ABS_FLOAT:
3280 return genInlinedAbsFloat(cUnit, mir);
3281 case INLINE_MATH_ABS_DOUBLE:
3282 return genInlinedAbsDouble(cUnit, mir);
3283 case INLINE_STRING_COMPARETO:
3284 case INLINE_STRING_EQUALS:
3290 /* Materialize pointer to retval & push */
3291 opRegReg(cUnit, OP_MOV, r4PC, rGLUE);
3292 opRegImm(cUnit, OP_ADD, r4PC, offset, rNone);
3294 /* Push r4 and (just to take up space) r5) */
3295 opImm(cUnit, OP_PUSH, (1 << r4PC | 1 << rFP));
3297 /* Get code pointer to inline routine */
3298 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3301 genExportPC(cUnit, mir, r0, r1 );
3303 /* Load arguments to r0 through r3 as applicable */
3304 for (i=0; i < dInsn->vA; i++) {
3305 loadValue(cUnit, dInsn->arg[i], i);
3307 /* Call inline routine */
3308 opReg(cUnit, OP_BLX, r4PC);
3311 opRegImm(cUnit, OP_ADD, r13, 8, rNone);
3313 /* Did we throw? If so, redo under interpreter*/
3314 genZeroCheck(cUnit, r0, mir->offset, NULL);
3316 resetRegisterScoreboard(cUnit);
3325 static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3327 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3328 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3329 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
3334 * The following are special processing routines that handle transfer of
3335 * controls between compiled code and the interpreter. Certain VM states like
3336 * Dalvik PC and special-purpose registers are reconstructed here.
3339 /* Chaining cell for code that may need warmup. */
3340 static void handleNormalChainingCell(CompilationUnit *cUnit,
3341 unsigned int offset)
3343 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3344 jitToInterpEntries.dvmJitToInterpNormal), r0);
3345 opReg(cUnit, OP_BLX, r0);
3346 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3350 * Chaining cell for instructions that immediately following already translated
3353 static void handleHotChainingCell(CompilationUnit *cUnit,
3354 unsigned int offset)
3356 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3357 jitToInterpEntries.dvmJitToTraceSelect), r0);
3358 opReg(cUnit, OP_BLX, r0);
3359 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3362 #if defined(WITH_SELF_VERIFICATION)
3363 /* Chaining cell for branches that branch back into the same basic block */
3364 static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3365 unsigned int offset)
3367 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3368 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
3369 newLIR1(cUnit, THUMB_BLX_R, r0);
3370 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3374 /* Chaining cell for monomorphic method invocations. */
3375 static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3376 const Method *callee)
3378 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3379 jitToInterpEntries.dvmJitToTraceSelect), r0);
3380 opReg(cUnit, OP_BLX, r0);
3381 addWordData(cUnit, (int) (callee->insns), true);
3384 /* Chaining cell for monomorphic method invocations. */
3385 static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3388 /* Should not be executed in the initial state */
3389 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3390 /* To be filled: class */
3391 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3392 /* To be filled: method */
3393 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3395 * Rechain count. The initial value of 0 here will trigger chaining upon
3396 * the first invocation of this callsite.
3398 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3401 /* Load the Dalvik PC into r0 and jump to the specified target */
3402 static void handlePCReconstruction(CompilationUnit *cUnit,
3403 ArmLIR *targetLabel)
3406 (ArmLIR **) cUnit->pcReconstructionList.elemList;
3407 int numElems = cUnit->pcReconstructionList.numUsed;
3409 for (i = 0; i < numElems; i++) {
3410 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3411 /* r0 = dalvik PC */
3412 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3413 genUnconditionalBranch(cUnit, targetLabel);
3417 /* Entry function to invoke the backend of the JIT compiler */
3418 void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3420 /* Used to hold the labels of each block */
3422 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
3423 GrowableList chainingListByType[CHAINING_CELL_LAST];
3427 * Initialize various types chaining lists.
3429 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3430 dvmInitGrowableList(&chainingListByType[i], 2);
3433 BasicBlock **blockList = cUnit->blockList;
3435 if (cUnit->executionCount) {
3437 * Reserve 6 bytes at the beginning of the trace
3438 * +----------------------------+
3439 * | execution count (4 bytes) |
3440 * +----------------------------+
3441 * | chain cell offset (2 bytes)|
3442 * +----------------------------+
3443 * ...and then code to increment the execution
3445 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3446 * sub r0, #10 @ back up to addr of executionCount
3451 newLIR1(cUnit, ARM_16BIT_DATA, 0);
3452 newLIR1(cUnit, ARM_16BIT_DATA, 0);
3453 cUnit->chainCellOffsetLIR =
3454 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
3455 cUnit->headerSize = 6;
3456 /* Thumb instruction used directly here to ensure correct size */
3457 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc & THUMB_REG_MASK);
3458 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3459 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3460 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3461 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
3463 /* Just reserve 2 bytes for the chain cell offset */
3464 cUnit->chainCellOffsetLIR =
3465 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
3466 cUnit->headerSize = 2;
3469 /* Handle the content in each basic block */
3470 for (i = 0; i < cUnit->numBlocks; i++) {
3471 blockList[i]->visited = true;
3474 labelList[i].operands[0] = blockList[i]->startOffset;
3476 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3478 * Append the label pseudo LIR first. Chaining cells will be handled
3479 * separately afterwards.
3481 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3484 if (blockList[i]->blockType == DALVIK_BYTECODE) {
3485 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
3486 /* Reset the register state */
3487 resetRegisterScoreboard(cUnit);
3489 switch (blockList[i]->blockType) {
3490 case CHAINING_CELL_NORMAL:
3491 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
3492 /* handle the codegen later */
3493 dvmInsertGrowableList(
3494 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
3496 case CHAINING_CELL_INVOKE_SINGLETON:
3497 labelList[i].opCode =
3498 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
3499 labelList[i].operands[0] =
3500 (int) blockList[i]->containingMethod;
3501 /* handle the codegen later */
3502 dvmInsertGrowableList(
3503 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3506 case CHAINING_CELL_INVOKE_PREDICTED:
3507 labelList[i].opCode =
3508 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
3509 /* handle the codegen later */
3510 dvmInsertGrowableList(
3511 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3514 case CHAINING_CELL_HOT:
3515 labelList[i].opCode =
3516 ARM_PSEUDO_CHAINING_CELL_HOT;
3517 /* handle the codegen later */
3518 dvmInsertGrowableList(
3519 &chainingListByType[CHAINING_CELL_HOT],
3522 case PC_RECONSTRUCTION:
3523 /* Make sure exception handling block is next */
3524 labelList[i].opCode =
3525 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
3526 assert (i == cUnit->numBlocks - 2);
3527 handlePCReconstruction(cUnit, &labelList[i+1]);
3529 case EXCEPTION_HANDLING:
3530 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
3531 if (cUnit->pcReconstructionList.numUsed) {
3532 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3533 jitToInterpEntries.dvmJitToInterpPunt),
3535 opReg(cUnit, OP_BLX, r1);
3538 #if defined(WITH_SELF_VERIFICATION)
3539 case CHAINING_CELL_BACKWARD_BRANCH:
3540 labelList[i].opCode =
3541 ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
3542 /* handle the codegen later */
3543 dvmInsertGrowableList(
3544 &chainingListByType[CHAINING_CELL_BACKWARD_BRANCH],
3554 ArmLIR *headLIR = NULL;
3556 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
3557 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3558 InstructionFormat dalvikFormat =
3559 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
3560 ArmLIR *boundaryLIR =
3561 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
3562 mir->offset,dalvikOpCode);
3563 /* Remember the first LIR for this block */
3564 if (headLIR == NULL) {
3565 headLIR = boundaryLIR;
3569 * Debugging: screen the opcode first to see if it is in the
3570 * do[-not]-compile list
3573 gDvmJit.includeSelectedOp !=
3574 ((gDvmJit.opList[dalvikOpCode >> 3] &
3575 (1 << (dalvikOpCode & 0x7))) !=
3577 #if defined(WITH_SELF_VERIFICATION)
3578 /* Punt on opcodes we can't replay */
3579 if (selfVerificationPuntOps(dalvikOpCode))
3580 singleStepMe = true;
3582 if (singleStepMe || cUnit->allSingleStep) {
3584 genInterpSingleStep(cUnit, mir);
3586 opcodeCoverage[dalvikOpCode]++;
3587 switch (dalvikFormat) {
3591 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3592 mir, blockList[i], labelList);
3595 notHandled = handleFmt10x(cUnit, mir);
3599 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3602 notHandled = handleFmt11x(cUnit, mir);
3605 notHandled = handleFmt12x(cUnit, mir);
3608 notHandled = handleFmt20bc(cUnit, mir);
3612 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3615 notHandled = handleFmt21h(cUnit, mir);
3618 notHandled = handleFmt21s(cUnit, mir);
3621 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3626 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3629 notHandled = handleFmt22c(cUnit, mir);
3632 notHandled = handleFmt22cs(cUnit, mir);
3635 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3640 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3643 notHandled = handleFmt23x(cUnit, mir);
3646 notHandled = handleFmt31t(cUnit, mir);
3650 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3655 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3659 notHandled = handleFmt3inline(cUnit, mir);
3662 notHandled = handleFmt51l(cUnit, mir);
3670 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3672 dalvikOpCode, getOpcodeName(dalvikOpCode),
3678 /* Eliminate redundant loads/stores and delay stores into later slots */
3679 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3680 cUnit->lastLIRInsn);
3682 * Check if the block is terminated due to trace length constraint -
3683 * insert an unconditional branch to the chaining cell.
3685 if (blockList[i]->needFallThroughBranch) {
3686 genUnconditionalBranch(cUnit,
3687 &labelList[blockList[i]->fallThrough->id]);
3692 /* Handle the chaining cells in predefined order */
3693 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3695 int *blockIdList = (int *) chainingListByType[i].elemList;
3697 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3699 /* No chaining cells of this type */
3700 if (cUnit->numChainingCells[i] == 0)
3703 /* Record the first LIR for a new type of chaining cell */
3704 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3706 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3707 int blockId = blockIdList[j];
3709 /* Align this chaining cell first */
3710 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
3712 /* Insert the pseudo chaining instruction */
3713 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3716 switch (blockList[blockId]->blockType) {
3717 case CHAINING_CELL_NORMAL:
3718 handleNormalChainingCell(cUnit,
3719 blockList[blockId]->startOffset);
3721 case CHAINING_CELL_INVOKE_SINGLETON:
3722 handleInvokeSingletonChainingCell(cUnit,
3723 blockList[blockId]->containingMethod);
3725 case CHAINING_CELL_INVOKE_PREDICTED:
3726 handleInvokePredictedChainingCell(cUnit);
3728 case CHAINING_CELL_HOT:
3729 handleHotChainingCell(cUnit,
3730 blockList[blockId]->startOffset);
3732 #if defined(WITH_SELF_VERIFICATION)
3733 case CHAINING_CELL_BACKWARD_BRANCH:
3734 handleBackwardBranchChainingCell(cUnit,
3735 blockList[blockId]->startOffset);
3745 dvmCompilerApplyGlobalOptimizations(cUnit);
3748 /* Accept the work and start compiling */
3749 bool dvmCompilerDoWork(CompilerWorkOrder *work)
3753 if (gDvmJit.codeCacheFull) {
3757 switch (work->kind) {
3758 case kWorkOrderMethod:
3759 res = dvmCompileMethod(work->info, &work->result);
3761 case kWorkOrderTrace:
3762 /* Start compilation with maximally allowed trace length */
3763 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
3772 /* Architectural-specific debugging helpers go here */
3773 void dvmCompilerArchDump(void)
3775 /* Print compiled opcode in this VM instance */
3776 int i, start, streak;
3781 while (opcodeCoverage[i] == 0 && i < 256) {
3787 for (start = i++, streak = 1; i < 256; i++) {
3788 if (opcodeCoverage[i]) {
3792 sprintf(buf+strlen(buf), "%x,", start);
3794 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3797 while (opcodeCoverage[i] == 0 && i < 256) {
3808 sprintf(buf+strlen(buf), "%x", start);
3810 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3814 LOGD("dalvik.vm.jit.op = %s", buf);