blob: b6c266dc7473cd4f123eae26564e346253295754 [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00:29 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Bill Buzbee50a6bf22009-07-08 13:08:04 -070017/*
18 * This file contains codegen and support common to all supported
19 * ARM variants. It is included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
25 */
26
Ben Chengba4fc8b2009-06-01 13:00:29 -070027
Ben Chengba4fc8b2009-06-01 13:00:29 -070028/* Array holding the entry offset of each template relative to the first one */
29static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
30
31/* Track exercised opcodes */
32static int opcodeCoverage[256];
33
34/*****************************************************************************/
35
36/*
37 * The following are building blocks to construct low-level IRs with 0 - 3
38 * operands.
39 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -070040static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
Ben Chengba4fc8b2009-06-01 13:00:29 -070041{
Bill Buzbee89efc3d2009-07-28 11:22:22 -070042 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070043 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
Ben Chengba4fc8b2009-06-01 13:00:29 -070044 insn->opCode = opCode;
45 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
46 return insn;
47}
48
Bill Buzbee89efc3d2009-07-28 11:22:22 -070049static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -070050 int dest)
51{
Bill Buzbee89efc3d2009-07-28 11:22:22 -070052 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070053 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -070054 insn->opCode = opCode;
55 insn->operands[0] = dest;
56 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
57 return insn;
58}
59
Bill Buzbee89efc3d2009-07-28 11:22:22 -070060static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -070061 int dest, int src1)
62{
Bill Buzbee89efc3d2009-07-28 11:22:22 -070063 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070064 assert(isPseudoOpCode(opCode) ||
65 (EncodingMap[opCode].flags & IS_BINARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -070066 insn->opCode = opCode;
67 insn->operands[0] = dest;
68 insn->operands[1] = src1;
69 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
70 return insn;
71}
72
Bill Buzbee89efc3d2009-07-28 11:22:22 -070073static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -070074 int dest, int src1, int src2)
75{
Bill Buzbee89efc3d2009-07-28 11:22:22 -070076 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070077 assert(isPseudoOpCode(opCode) ||
78 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -070079 insn->opCode = opCode;
80 insn->operands[0] = dest;
81 insn->operands[1] = src1;
82 insn->operands[2] = src2;
83 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
84 return insn;
85}
86
Bill Buzbee89efc3d2009-07-28 11:22:22 -070087static ArmLIR *newLIR23(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -070088 int srcdest, int src2)
89{
90 assert(!isPseudoOpCode(opCode));
Ben Chenge9695e52009-06-16 16:11:47 -070091 if (EncodingMap[opCode].flags & IS_BINARY_OP)
Ben Chengba4fc8b2009-06-01 13:00:29 -070092 return newLIR2(cUnit, opCode, srcdest, src2);
93 else
94 return newLIR3(cUnit, opCode, srcdest, srcdest, src2);
95}
96
97/*****************************************************************************/
98
99/*
100 * The following are building blocks to insert constants into the pool or
101 * instruction streams.
102 */
103
104/* Add a 32-bit constant either in the constant pool or mixed with code */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700105static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700106{
107 /* Add the constant to the literal pool */
108 if (!inPlace) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700109 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700110 newValue->operands[0] = value;
111 newValue->generic.next = cUnit->wordList;
112 cUnit->wordList = (LIR *) newValue;
113 return newValue;
114 } else {
115 /* Add the constant in the middle of code stream */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700116 newLIR1(cUnit, ARM_16BIT_DATA, (value & 0xffff));
117 newLIR1(cUnit, ARM_16BIT_DATA, (value >> 16));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700118 }
119 return NULL;
120}
121
122/*
123 * Search the existing constants in the literal pool for an exact or close match
124 * within specified delta (greater or equal to 0).
125 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700126static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700127 unsigned int delta)
128{
129 LIR *dataTarget = cUnit->wordList;
130 while (dataTarget) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700131 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
Ben Chengba4fc8b2009-06-01 13:00:29 -0700132 delta)
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700133 return (ArmLIR *) dataTarget;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700134 dataTarget = dataTarget->next;
135 }
136 return NULL;
137}
138
Ben Chengba4fc8b2009-06-01 13:00:29 -0700139/* Perform the actual operation for OP_RETURN_* */
140static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
141{
142 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
143#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -0700144 gDvmJit.returnOp++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700145#endif
146 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700147 /* Insert branch, but defer setting of target */
148 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700149 /* Set up the place holder to reconstruct this Dalvik PC */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700150 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
151 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700152 pcrLabel->operands[0] = dPC;
153 pcrLabel->operands[1] = mir->offset;
154 /* Insert the place holder to the growable list */
155 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
156 /* Branch to the PC reconstruction code */
157 branch->generic.target = (LIR *) pcrLabel;
158}
159
160/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700161 * Perform a binary operation on 64-bit operands and leave the results in the
162 * r0/r1 pair.
163 */
164static void genBinaryOpWide(CompilationUnit *cUnit, int vDest,
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700165 ArmOpCode preinst, ArmOpCode inst,
Ben Chenge9695e52009-06-16 16:11:47 -0700166 int reg0, int reg2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700167{
Ben Chenge9695e52009-06-16 16:11:47 -0700168 int reg1 = NEXT_REG(reg0);
169 int reg3 = NEXT_REG(reg2);
170 newLIR23(cUnit, preinst, reg0, reg2);
171 newLIR23(cUnit, inst, reg1, reg3);
172 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700173}
174
175/* Perform a binary operation on 32-bit operands and leave the results in r0. */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700176static void genBinaryOp(CompilationUnit *cUnit, int vDest, ArmOpCode inst,
Ben Chenge9695e52009-06-16 16:11:47 -0700177 int reg0, int reg1, int regDest)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700178{
Ben Chenge9695e52009-06-16 16:11:47 -0700179 if (EncodingMap[inst].flags & IS_BINARY_OP) {
180 newLIR2(cUnit, inst, reg0, reg1);
181 storeValue(cUnit, reg0, vDest, reg1);
182 } else {
183 newLIR3(cUnit, inst, regDest, reg0, reg1);
184 storeValue(cUnit, regDest, vDest, reg1);
185 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700186}
187
188/* Create the PC reconstruction slot if not already done */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700189static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
190 ArmLIR *branch,
191 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700192{
193 /* Set up the place holder to reconstruct this Dalvik PC */
194 if (pcrLabel == NULL) {
195 int dPC = (int) (cUnit->method->insns + dOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700196 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
197 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700198 pcrLabel->operands[0] = dPC;
199 pcrLabel->operands[1] = dOffset;
200 /* Insert the place holder to the growable list */
201 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
202 }
203 /* Branch to the PC reconstruction code */
204 branch->generic.target = (LIR *) pcrLabel;
205 return pcrLabel;
206}
207
Ben Chengba4fc8b2009-06-01 13:00:29 -0700208
209/*
210 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
211 * satisfies.
212 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700213static inline ArmLIR *inertRegRegCheck(CompilationUnit *cUnit,
214 ArmConditionCode cond,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700215 int reg1, int reg2, int dOffset,
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700216 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700217{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700218 newLIR2(cUnit, THUMB_CMP_RR, reg1, reg2);
219 ArmLIR *branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700220 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
221}
222
Ben Chenge9695e52009-06-16 16:11:47 -0700223/*
224 * Perform null-check on a register. vReg is the Dalvik register being checked,
225 * and mReg is the machine register holding the actual value. If internal state
226 * indicates that vReg has been checked before the check request is ignored.
227 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700228static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
229 int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700230{
Ben Chenge9695e52009-06-16 16:11:47 -0700231 /* This particular Dalvik register has been null-checked */
232 if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
233 return pcrLabel;
234 }
235 dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
236 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
237}
238
239/*
240 * Perform zero-check on a register. Similar to genNullCheck but the value being
241 * checked does not have a corresponding Dalvik register.
242 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700243static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
244 int dOffset, ArmLIR *pcrLabel)
Ben Chenge9695e52009-06-16 16:11:47 -0700245{
246 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700247}
248
249/* Perform bound check on two registers */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700250static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
251 int rBound, int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700252{
253 return inertRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
254 pcrLabel);
255}
256
257/* Generate a unconditional branch to go to the interpreter */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700258static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
259 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700260{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700261 ArmLIR *branch = newLIR0(cUnit, THUMB_B_UNCOND);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700262 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
263}
264
265/* Load a wide field from an object instance */
266static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
267{
268 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700269 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700270
Ben Chenge9695e52009-06-16 16:11:47 -0700271 /* Allocate reg0..reg3 into physical registers r0..r3 */
272
273 /* See if vB is in a native register. If so, reuse it. */
274 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
275 /* Ping reg3 to the other register of the same pair containing reg2 */
276 reg3 = reg2 ^ 0x1;
277 /*
278 * Ping reg0 to the first register of the alternate register pair
279 */
280 reg0 = (reg2 + 2) & 0x2;
281 reg1 = NEXT_REG(reg0);
282
283 loadValue(cUnit, dInsn->vB, reg2);
284 loadConstant(cUnit, reg3, fieldOffset);
285 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700286 newLIR3(cUnit, THUMB_ADD_RRR, reg2, reg2, reg3);
287 newLIR2(cUnit, THUMB_LDMIA, reg2, (1<<reg0 | 1<<reg1));
Ben Chenge9695e52009-06-16 16:11:47 -0700288 storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700289}
290
291/* Store a wide field to an object instance */
292static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
293{
294 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700295 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700296
Ben Chenge9695e52009-06-16 16:11:47 -0700297 /* Allocate reg0..reg3 into physical registers r0..r3 */
298
299 /* See if vB is in a native register. If so, reuse it. */
300 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
301 /* Ping reg3 to the other register of the same pair containing reg2 */
302 reg3 = reg2 ^ 0x1;
303 /*
304 * Ping reg0 to the first register of the alternate register pair
305 */
306 reg0 = (reg2 + 2) & 0x2;
307 reg1 = NEXT_REG(reg0);
308
309
310 loadValue(cUnit, dInsn->vB, reg2);
311 loadValuePair(cUnit, dInsn->vA, reg0, reg1);
312 updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
313 loadConstant(cUnit, reg3, fieldOffset);
314 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700315 newLIR3(cUnit, THUMB_ADD_RRR, reg2, reg2, reg3);
316 newLIR2(cUnit, THUMB_STMIA, reg2, (1<<reg0 | 1<<reg1));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700317}
318
319/*
320 * Load a field from an object instance
321 *
322 * Inst should be one of:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700323 * THUMB_LDR_RRR
324 * THUMB_LDRB_RRR
325 * THUMB_LDRH_RRR
326 * THUMB_LDRSB_RRR
327 * THUMB_LDRSH_RRR
Ben Chengba4fc8b2009-06-01 13:00:29 -0700328 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700329static void genIGet(CompilationUnit *cUnit, MIR *mir, ArmOpCode inst,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700330 int fieldOffset)
331{
332 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700333 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700334
Ben Chenge9695e52009-06-16 16:11:47 -0700335 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
336 reg1 = NEXT_REG(reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700337 /* TUNING: write a utility routine to load via base + constant offset */
Ben Chenge9695e52009-06-16 16:11:47 -0700338 loadValue(cUnit, dInsn->vB, reg0);
339 loadConstant(cUnit, reg1, fieldOffset);
340 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
341 newLIR3(cUnit, inst, reg0, reg0, reg1);
342 storeValue(cUnit, reg0, dInsn->vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700343}
344
345/*
346 * Store a field to an object instance
347 *
348 * Inst should be one of:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700349 * THUMB_STR_RRR
350 * THUMB_STRB_RRR
351 * THUMB_STRH_RRR
Ben Chengba4fc8b2009-06-01 13:00:29 -0700352 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700353static void genIPut(CompilationUnit *cUnit, MIR *mir, ArmOpCode inst,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700354 int fieldOffset)
355{
356 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700357 int reg0, reg1, reg2;
358
359 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
360 reg1 = NEXT_REG(reg0);
361 reg2 = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700362
363 /* TUNING: write a utility routine to load via base + constant offset */
Ben Chenge9695e52009-06-16 16:11:47 -0700364 loadValue(cUnit, dInsn->vB, reg0);
365 loadConstant(cUnit, reg1, fieldOffset);
366 loadValue(cUnit, dInsn->vA, reg2);
367 updateLiveRegister(cUnit, dInsn->vA, reg2);
368 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
369 newLIR3(cUnit, inst, reg2, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700370}
371
372
373/* TODO: This should probably be done as an out-of-line instruction handler. */
374
375/*
376 * Generate array load
377 *
378 * Inst should be one of:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700379 * THUMB_LDR_RRR
380 * THUMB_LDRB_RRR
381 * THUMB_LDRH_RRR
382 * THUMB_LDRSB_RRR
383 * THUMB_LDRSH_RRR
Ben Chengba4fc8b2009-06-01 13:00:29 -0700384 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700385static void genArrayGet(CompilationUnit *cUnit, MIR *mir, ArmOpCode inst,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700386 int vArray, int vIndex, int vDest, int scale)
387{
388 int lenOffset = offsetof(ArrayObject, length);
389 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700390 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700391
Ben Chenge9695e52009-06-16 16:11:47 -0700392 reg0 = selectFirstRegister(cUnit, vArray, false);
393 reg1 = NEXT_REG(reg0);
394 reg2 = NEXT_REG(reg1);
395 reg3 = NEXT_REG(reg2);
396
397 loadValue(cUnit, vArray, reg2);
398 loadValue(cUnit, vIndex, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700399
400 /* null object? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700401 ArmLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
Ben Chenge9695e52009-06-16 16:11:47 -0700402 NULL);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700403 newLIR3(cUnit, THUMB_LDR_RRI5, reg0, reg2, lenOffset >> 2); /* Get len */
404 newLIR2(cUnit, THUMB_ADD_RI8, reg2, dataOffset); /* reg2 -> array data */
Ben Chenge9695e52009-06-16 16:11:47 -0700405 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700406 if (scale) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700407 newLIR3(cUnit, THUMB_LSL, reg3, reg3, scale);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700408 }
409 if (scale==3) {
Ben Chenge9695e52009-06-16 16:11:47 -0700410 newLIR3(cUnit, inst, reg0, reg2, reg3);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700411 newLIR2(cUnit, THUMB_ADD_RI8, reg2, 4);
Ben Chenge9695e52009-06-16 16:11:47 -0700412 newLIR3(cUnit, inst, reg1, reg2, reg3);
413 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700414 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700415 newLIR3(cUnit, inst, reg0, reg2, reg3);
416 storeValue(cUnit, reg0, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700417 }
418}
419
420/* TODO: This should probably be done as an out-of-line instruction handler. */
421
422/*
423 * Generate array store
424 *
425 * Inst should be one of:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700426 * THUMB_STR_RRR
427 * THUMB_STRB_RRR
428 * THUMB_STRH_RRR
Ben Chengba4fc8b2009-06-01 13:00:29 -0700429 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700430static void genArrayPut(CompilationUnit *cUnit, MIR *mir, ArmOpCode inst,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700431 int vArray, int vIndex, int vSrc, int scale)
432{
433 int lenOffset = offsetof(ArrayObject, length);
434 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700435 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700436
Ben Chenge9695e52009-06-16 16:11:47 -0700437 reg0 = selectFirstRegister(cUnit, vArray, false);
438 reg1 = NEXT_REG(reg0);
439 reg2 = NEXT_REG(reg1);
440 reg3 = NEXT_REG(reg2);
441
442 loadValue(cUnit, vArray, reg2);
443 loadValue(cUnit, vIndex, reg3);
444
Ben Cheng1efc9c52009-06-08 18:25:27 -0700445 /* null object? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700446 ArmLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
Ben Chenge9695e52009-06-16 16:11:47 -0700447 NULL);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700448 newLIR3(cUnit, THUMB_LDR_RRI5, reg0, reg2, lenOffset >> 2); /* Get len */
449 newLIR2(cUnit, THUMB_ADD_RI8, reg2, dataOffset); /* reg2 -> array data */
Ben Chenge9695e52009-06-16 16:11:47 -0700450 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
451 /* at this point, reg2 points to array, reg3 is unscaled index */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700452 if (scale==3) {
Ben Chenge9695e52009-06-16 16:11:47 -0700453 loadValuePair(cUnit, vSrc, reg0, reg1);
454 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700455 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700456 loadValue(cUnit, vSrc, reg0);
457 updateLiveRegister(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700458 }
459 if (scale) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700460 newLIR3(cUnit, THUMB_LSL, reg3, reg3, scale);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700461 }
462 /*
Ben Chenge9695e52009-06-16 16:11:47 -0700463 * at this point, reg2 points to array, reg3 is scaled index, and
464 * reg0[reg1] is data
Ben Chengba4fc8b2009-06-01 13:00:29 -0700465 */
466 if (scale==3) {
Ben Chenge9695e52009-06-16 16:11:47 -0700467 newLIR3(cUnit, inst, reg0, reg2, reg3);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700468 newLIR2(cUnit, THUMB_ADD_RI8, reg2, 4);
Ben Chenge9695e52009-06-16 16:11:47 -0700469 newLIR3(cUnit, inst, reg1, reg2, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700470 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700471 newLIR3(cUnit, inst, reg0, reg2, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700472 }
473}
474
475static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
476 int vSrc1, int vShift)
477{
Ben Chenge9695e52009-06-16 16:11:47 -0700478 /*
479 * Don't mess with the regsiters here as there is a particular calling
480 * convention to the out-of-line handler.
481 */
482 loadValue(cUnit, vShift, r2);
483 loadValuePair(cUnit, vSrc1, r0, r1);
484 switch( mir->dalvikInsn.opCode) {
485 case OP_SHL_LONG:
486 case OP_SHL_LONG_2ADDR:
487 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
488 break;
489 case OP_SHR_LONG:
490 case OP_SHR_LONG_2ADDR:
491 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
492 break;
493 case OP_USHR_LONG:
494 case OP_USHR_LONG_2ADDR:
495 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
496 break;
497 default:
498 return true;
499 }
500 storeValuePair(cUnit, r0, r1, vDest, r2);
501 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700502}
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700503bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
504 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700505{
Ben Chenge9695e52009-06-16 16:11:47 -0700506 /*
507 * Don't optimize the regsiter usage here as they are governed by the EABI
508 * calling convention.
509 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700510 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -0700511 int reg0, reg1;
512
Ben Chengba4fc8b2009-06-01 13:00:29 -0700513 /* TODO: use a proper include file to define these */
514 float __aeabi_fadd(float a, float b);
515 float __aeabi_fsub(float a, float b);
516 float __aeabi_fdiv(float a, float b);
517 float __aeabi_fmul(float a, float b);
518 float fmodf(float a, float b);
519
Ben Chenge9695e52009-06-16 16:11:47 -0700520 reg0 = selectFirstRegister(cUnit, vSrc2, false);
521 reg1 = NEXT_REG(reg0);
522
Ben Chengba4fc8b2009-06-01 13:00:29 -0700523 switch (mir->dalvikInsn.opCode) {
524 case OP_ADD_FLOAT_2ADDR:
525 case OP_ADD_FLOAT:
526 funct = (void*) __aeabi_fadd;
527 break;
528 case OP_SUB_FLOAT_2ADDR:
529 case OP_SUB_FLOAT:
530 funct = (void*) __aeabi_fsub;
531 break;
532 case OP_DIV_FLOAT_2ADDR:
533 case OP_DIV_FLOAT:
534 funct = (void*) __aeabi_fdiv;
535 break;
536 case OP_MUL_FLOAT_2ADDR:
537 case OP_MUL_FLOAT:
538 funct = (void*) __aeabi_fmul;
539 break;
540 case OP_REM_FLOAT_2ADDR:
541 case OP_REM_FLOAT:
542 funct = (void*) fmodf;
543 break;
544 case OP_NEG_FLOAT: {
Ben Chenge9695e52009-06-16 16:11:47 -0700545 loadValue(cUnit, vSrc2, reg0);
546 loadConstant(cUnit, reg1, 0x80000000);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700547 newLIR3(cUnit, THUMB_ADD_RRR, reg0, reg0, reg1);
Ben Chenge9695e52009-06-16 16:11:47 -0700548 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700549 return false;
550 }
551 default:
552 return true;
553 }
554 loadConstant(cUnit, r2, (int)funct);
555 loadValue(cUnit, vSrc1, r0);
556 loadValue(cUnit, vSrc2, r1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700557 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700558 storeValue(cUnit, r0, vDest, r1);
559 return false;
560}
561
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700562bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
563 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700564{
565 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -0700566 int reg0, reg1, reg2;
567
Ben Chengba4fc8b2009-06-01 13:00:29 -0700568 /* TODO: use a proper include file to define these */
569 double __aeabi_dadd(double a, double b);
570 double __aeabi_dsub(double a, double b);
571 double __aeabi_ddiv(double a, double b);
572 double __aeabi_dmul(double a, double b);
573 double fmod(double a, double b);
574
Ben Chenge9695e52009-06-16 16:11:47 -0700575 reg0 = selectFirstRegister(cUnit, vSrc2, true);
576 reg1 = NEXT_REG(reg0);
577 reg2 = NEXT_REG(reg1);
578
Ben Chengba4fc8b2009-06-01 13:00:29 -0700579 switch (mir->dalvikInsn.opCode) {
580 case OP_ADD_DOUBLE_2ADDR:
581 case OP_ADD_DOUBLE:
582 funct = (void*) __aeabi_dadd;
583 break;
584 case OP_SUB_DOUBLE_2ADDR:
585 case OP_SUB_DOUBLE:
586 funct = (void*) __aeabi_dsub;
587 break;
588 case OP_DIV_DOUBLE_2ADDR:
589 case OP_DIV_DOUBLE:
590 funct = (void*) __aeabi_ddiv;
591 break;
592 case OP_MUL_DOUBLE_2ADDR:
593 case OP_MUL_DOUBLE:
594 funct = (void*) __aeabi_dmul;
595 break;
596 case OP_REM_DOUBLE_2ADDR:
597 case OP_REM_DOUBLE:
598 funct = (void*) fmod;
599 break;
600 case OP_NEG_DOUBLE: {
Ben Chenge9695e52009-06-16 16:11:47 -0700601 loadValuePair(cUnit, vSrc2, reg0, reg1);
602 loadConstant(cUnit, reg2, 0x80000000);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700603 newLIR3(cUnit, THUMB_ADD_RRR, reg1, reg1, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -0700604 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700605 return false;
606 }
607 default:
608 return true;
609 }
Ben Chenge9695e52009-06-16 16:11:47 -0700610 /*
611 * Don't optimize the regsiter usage here as they are governed by the EABI
612 * calling convention.
613 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700614 loadConstant(cUnit, r4PC, (int)funct);
615 loadValuePair(cUnit, vSrc1, r0, r1);
616 loadValuePair(cUnit, vSrc2, r2, r3);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700617 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700618 storeValuePair(cUnit, r0, r1, vDest, r2);
619 return false;
620}
621
622static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
623 int vSrc1, int vSrc2)
624{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700625 int firstOp = THUMB_BKPT;
626 int secondOp = THUMB_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700627 bool callOut = false;
628 void *callTgt;
629 int retReg = r0;
Ben Chenge9695e52009-06-16 16:11:47 -0700630 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700631 /* TODO - find proper .h file to declare these */
632 long long __aeabi_ldivmod(long long op1, long long op2);
633
634 switch (mir->dalvikInsn.opCode) {
635 case OP_NOT_LONG:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700636 firstOp = THUMB_MVN;
637 secondOp = THUMB_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700638 break;
639 case OP_ADD_LONG:
640 case OP_ADD_LONG_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700641 firstOp = THUMB_ADD_RRR;
642 secondOp = THUMB_ADC;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700643 break;
644 case OP_SUB_LONG:
645 case OP_SUB_LONG_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700646 firstOp = THUMB_SUB_RRR;
647 secondOp = THUMB_SBC;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700648 break;
649 case OP_MUL_LONG:
650 case OP_MUL_LONG_2ADDR:
651 loadValuePair(cUnit, vSrc1, r0, r1);
652 loadValuePair(cUnit, vSrc2, r2, r3);
653 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
654 storeValuePair(cUnit, r0, r1, vDest, r2);
655 return false;
656 break;
657 case OP_DIV_LONG:
658 case OP_DIV_LONG_2ADDR:
659 callOut = true;
660 retReg = r0;
661 callTgt = (void*)__aeabi_ldivmod;
662 break;
663 /* NOTE - result is in r2/r3 instead of r0/r1 */
664 case OP_REM_LONG:
665 case OP_REM_LONG_2ADDR:
666 callOut = true;
667 callTgt = (void*)__aeabi_ldivmod;
668 retReg = r2;
669 break;
670 case OP_AND_LONG:
671 case OP_AND_LONG_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700672 firstOp = THUMB_AND_RR;
673 secondOp = THUMB_AND_RR;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700674 break;
675 case OP_OR_LONG:
676 case OP_OR_LONG_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700677 firstOp = THUMB_ORR;
678 secondOp = THUMB_ORR;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700679 break;
680 case OP_XOR_LONG:
681 case OP_XOR_LONG_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700682 firstOp = THUMB_EOR;
683 secondOp = THUMB_EOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700684 break;
Ben Chenge9695e52009-06-16 16:11:47 -0700685 case OP_NEG_LONG: {
686 reg0 = selectFirstRegister(cUnit, vSrc2, true);
687 reg1 = NEXT_REG(reg0);
688 reg2 = NEXT_REG(reg1);
689 reg3 = NEXT_REG(reg2);
690
691 loadValuePair(cUnit, vSrc2, reg0, reg1);
692 loadConstant(cUnit, reg3, 0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700693 newLIR3(cUnit, THUMB_SUB_RRR, reg2, reg3, reg0);
694 newLIR2(cUnit, THUMB_SBC, reg3, reg1);
Ben Cheng38329f52009-07-07 14:19:20 -0700695 storeValuePair(cUnit, reg2, reg3, vDest, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700696 return false;
Ben Chenge9695e52009-06-16 16:11:47 -0700697 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700698 default:
699 LOGE("Invalid long arith op");
700 dvmAbort();
701 }
702 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -0700703 reg0 = selectFirstRegister(cUnit, vSrc1, true);
704 reg1 = NEXT_REG(reg0);
705 reg2 = NEXT_REG(reg1);
706 reg3 = NEXT_REG(reg2);
707
708 loadValuePair(cUnit, vSrc1, reg0, reg1);
709 loadValuePair(cUnit, vSrc2, reg2, reg3);
710 genBinaryOpWide(cUnit, vDest, firstOp, secondOp, reg0, reg2);
711 /*
712 * Don't optimize the regsiter usage here as they are governed by the EABI
713 * calling convention.
714 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700715 } else {
716 loadValuePair(cUnit, vSrc2, r2, r3);
717 loadConstant(cUnit, r4PC, (int) callTgt);
718 loadValuePair(cUnit, vSrc1, r0, r1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700719 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700720 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
721 }
722 return false;
723}
724
725static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
726 int vSrc1, int vSrc2)
727{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700728 int armOp = THUMB_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700729 bool callOut = false;
730 bool checkZero = false;
731 int retReg = r0;
732 void *callTgt;
Ben Chenge9695e52009-06-16 16:11:47 -0700733 int reg0, reg1, regDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700734
735 /* TODO - find proper .h file to declare these */
736 int __aeabi_idivmod(int op1, int op2);
737 int __aeabi_idiv(int op1, int op2);
738
739 switch (mir->dalvikInsn.opCode) {
740 case OP_NEG_INT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700741 armOp = THUMB_NEG;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700742 break;
743 case OP_NOT_INT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700744 armOp = THUMB_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700745 break;
746 case OP_ADD_INT:
747 case OP_ADD_INT_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700748 armOp = THUMB_ADD_RRR;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700749 break;
750 case OP_SUB_INT:
751 case OP_SUB_INT_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700752 armOp = THUMB_SUB_RRR;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700753 break;
754 case OP_MUL_INT:
755 case OP_MUL_INT_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700756 armOp = THUMB_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700757 break;
758 case OP_DIV_INT:
759 case OP_DIV_INT_2ADDR:
760 callOut = true;
761 checkZero = true;
762 callTgt = __aeabi_idiv;
763 retReg = r0;
764 break;
765 /* NOTE: returns in r1 */
766 case OP_REM_INT:
767 case OP_REM_INT_2ADDR:
768 callOut = true;
769 checkZero = true;
770 callTgt = __aeabi_idivmod;
771 retReg = r1;
772 break;
773 case OP_AND_INT:
774 case OP_AND_INT_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700775 armOp = THUMB_AND_RR;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700776 break;
777 case OP_OR_INT:
778 case OP_OR_INT_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700779 armOp = THUMB_ORR;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700780 break;
781 case OP_XOR_INT:
782 case OP_XOR_INT_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700783 armOp = THUMB_EOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700784 break;
785 case OP_SHL_INT:
786 case OP_SHL_INT_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700787 armOp = THUMB_LSLV;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700788 break;
789 case OP_SHR_INT:
790 case OP_SHR_INT_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700791 armOp = THUMB_ASRV;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700792 break;
793 case OP_USHR_INT:
794 case OP_USHR_INT_2ADDR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700795 armOp = THUMB_LSRV;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700796 break;
797 default:
798 LOGE("Invalid word arith op: 0x%x(%d)",
799 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
800 dvmAbort();
801 }
802 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -0700803 /* Try to allocate reg0 to the currently cached source operand */
804 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
805 reg0 = selectFirstRegister(cUnit, vSrc1, false);
806 reg1 = NEXT_REG(reg0);
807 regDest = NEXT_REG(reg1);
808
809 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
810 loadValue(cUnit, vSrc2, reg1);
811 genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
812 } else {
813 reg0 = selectFirstRegister(cUnit, vSrc2, false);
814 reg1 = NEXT_REG(reg0);
815 regDest = NEXT_REG(reg1);
816
817 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
818 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
819 genBinaryOp(cUnit, vDest, armOp, reg1, reg0, regDest);
820 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700821 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700822 /*
823 * Load the callout target first since it will never be eliminated
824 * and its value will be used first.
825 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700826 loadConstant(cUnit, r2, (int) callTgt);
Ben Chenge9695e52009-06-16 16:11:47 -0700827 /*
828 * Load vSrc2 first if it is not cached in a native register or it
829 * is in r0 which will be clobbered if vSrc1 is loaded first.
830 */
831 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
832 cUnit->registerScoreboard.nativeReg == r0) {
833 /* Cannot be optimized and won't clobber r0 */
834 loadValue(cUnit, vSrc2, r1);
835 /* May be optimized if vSrc1 is cached */
836 loadValue(cUnit, vSrc1, r0);
837 } else {
838 loadValue(cUnit, vSrc1, r0);
839 loadValue(cUnit, vSrc2, r1);
840 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700841 if (checkZero) {
Ben Chenge9695e52009-06-16 16:11:47 -0700842 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700843 }
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700844 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700845 storeValue(cUnit, retReg, vDest, r2);
846 }
847 return false;
848}
849
850static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
851{
852 OpCode opCode = mir->dalvikInsn.opCode;
853 int vA = mir->dalvikInsn.vA;
854 int vB = mir->dalvikInsn.vB;
855 int vC = mir->dalvikInsn.vC;
856
857 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
858 return genArithOpLong(cUnit,mir, vA, vA, vB);
859 }
860 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
861 return genArithOpLong(cUnit,mir, vA, vB, vC);
862 }
863 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
864 return genShiftOpLong(cUnit,mir, vA, vA, vB);
865 }
866 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
867 return genShiftOpLong(cUnit,mir, vA, vB, vC);
868 }
869 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
870 return genArithOpInt(cUnit,mir, vA, vA, vB);
871 }
872 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
873 return genArithOpInt(cUnit,mir, vA, vB, vC);
874 }
875 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700876 return genArithOpFloat(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700877 }
878 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700879 return genArithOpFloat(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700880 }
881 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700882 return genArithOpDouble(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700883 }
884 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700885 return genArithOpDouble(cUnit,mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700886 }
887 return true;
888}
889
Bill Buzbeed45ba372009-06-15 17:00:57 -0700890static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
891 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700892{
Ben Chenge9695e52009-06-16 16:11:47 -0700893 /*
894 * Don't optimize the register usage since it calls out to template
895 * functions
896 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700897 loadConstant(cUnit, r2, (int)funct);
898 if (srcSize == 1) {
899 loadValue(cUnit, mir->dalvikInsn.vB, r0);
900 } else {
901 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
902 }
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700903 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700904 if (tgtSize == 1) {
905 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
906 } else {
907 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
908 }
909 return false;
910}
911
Ben Chengba4fc8b2009-06-01 13:00:29 -0700912static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
913{
Ben Chengba4fc8b2009-06-01 13:00:29 -0700914 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700915 int offset = offsetof(InterpState, retval);
916 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
917 int reg1 = NEXT_REG(regObj);
918 loadValue(cUnit, dInsn->arg[0], regObj);
919 genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
920 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700921 newLIR3(cUnit, THUMB_STR_RRI5, reg1, rGLUE, offset >> 2);
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700922 return false;
923}
924
925/*
926 * NOTE: The amount of code for this body suggests it ought to
927 * be handled in a template (and could also be coded quite a bit
928 * more efficiently in ARM). However, the code is dependent on the
929 * internal structure layout of string objects which are most safely
930 * known at run time.
931 * TUNING: One possibility (which could also be used for StringCompareTo
932 * and StringEquals) is to generate string access helper subroutines on
933 * Jit startup, and then call them from the translated inline-executes.
934 */
935static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
936{
937 DecodedInstruction *dInsn = &mir->dalvikInsn;
938 int offset = offsetof(InterpState, retval);
939 int contents = offsetof(ArrayObject, contents);
940 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
941 int regIdx = NEXT_REG(regObj);
942 int regMax = NEXT_REG(regIdx);
943 int regOff = NEXT_REG(regMax);
944 loadValue(cUnit, dInsn->arg[0], regObj);
945 loadValue(cUnit, dInsn->arg[1], regIdx);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700946 ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700947 mir->offset, NULL);
948 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
949 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
950 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
951 genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
952
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700953 newLIR2(cUnit, THUMB_ADD_RI8, regObj, contents);
954 newLIR3(cUnit, THUMB_ADD_RRR, regIdx, regIdx, regOff);
955 newLIR3(cUnit, THUMB_ADD_RRR, regIdx, regIdx, regIdx);
956 newLIR3(cUnit, THUMB_LDRH_RRR, regMax, regObj, regIdx);
957 newLIR3(cUnit, THUMB_STR_RRI5, regMax, rGLUE, offset >> 2);
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700958 return false;
959}
960
961static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
962{
963 int offset = offsetof(InterpState, retval);
964 DecodedInstruction *dInsn = &mir->dalvikInsn;
965 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
966 int sign = NEXT_REG(reg0);
967 /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
968 loadValue(cUnit, dInsn->arg[0], reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700969 newLIR3(cUnit, THUMB_ASR, sign, reg0, 31);
970 newLIR3(cUnit, THUMB_ADD_RRR, reg0, reg0, sign);
971 newLIR2(cUnit, THUMB_EOR, reg0, sign);
972 newLIR3(cUnit, THUMB_STR_RRI5, reg0, rGLUE, offset >> 2);
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700973 return false;
974}
975
976static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
977{
978 int offset = offsetof(InterpState, retval);
979 DecodedInstruction *dInsn = &mir->dalvikInsn;
980 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
981 int signMask = NEXT_REG(reg0);
982 loadValue(cUnit, dInsn->arg[0], reg0);
983 loadConstant(cUnit, signMask, 0x7fffffff);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700984 newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
985 newLIR3(cUnit, THUMB_STR_RRI5, reg0, rGLUE, offset >> 2);
Bill Buzbee50a6bf22009-07-08 13:08:04 -0700986 return false;
987}
988
989static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
990{
991 int offset = offsetof(InterpState, retval);
992 DecodedInstruction *dInsn = &mir->dalvikInsn;
993 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
994 int ophi = NEXT_REG(oplo);
995 int signMask = NEXT_REG(ophi);
996 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
997 loadConstant(cUnit, signMask, 0x7fffffff);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700998 newLIR3(cUnit, THUMB_STR_RRI5, oplo, rGLUE, offset >> 2);
999 newLIR2(cUnit, THUMB_AND_RR, ophi, signMask);
1000 newLIR3(cUnit, THUMB_STR_RRI5, ophi, rGLUE, (offset >> 2)+1);
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001001 return false;
1002}
1003
1004 /* No select in thumb, so we need to branch. Thumb2 will do better */
1005static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
1006{
1007 int offset = offsetof(InterpState, retval);
1008 DecodedInstruction *dInsn = &mir->dalvikInsn;
1009 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1010 int reg1 = NEXT_REG(reg0);
1011 loadValue(cUnit, dInsn->arg[0], reg0);
1012 loadValue(cUnit, dInsn->arg[1], reg1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001013 newLIR2(cUnit, THUMB_CMP_RR, reg0, reg1);
1014 ArmLIR *branch1 = newLIR2(cUnit, THUMB_B_COND, 2,
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001015 isMin ? ARM_COND_LT : ARM_COND_GT);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001016 newLIR2(cUnit, THUMB_MOV_RR, reg0, reg1);
1017 ArmLIR *target =
1018 newLIR3(cUnit, THUMB_STR_RRI5, reg0, rGLUE, offset >> 2);
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001019 branch1->generic.target = (LIR *)target;
1020 return false;
1021}
1022
1023static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
1024{
1025 int offset = offsetof(InterpState, retval);
1026 DecodedInstruction *dInsn = &mir->dalvikInsn;
1027 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1028 int ophi = NEXT_REG(oplo);
1029 int sign = NEXT_REG(ophi);
1030 /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
1031 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001032 newLIR3(cUnit, THUMB_ASR, sign, ophi, 31);
1033 newLIR3(cUnit, THUMB_ADD_RRR, oplo, oplo, sign);
1034 newLIR2(cUnit, THUMB_ADC, ophi, sign);
1035 newLIR2(cUnit, THUMB_EOR, oplo, sign);
1036 newLIR2(cUnit, THUMB_EOR, ophi, sign);
1037 newLIR3(cUnit, THUMB_STR_RRI5, oplo, rGLUE, offset >> 2);
1038 newLIR3(cUnit, THUMB_STR_RRI5, ophi, rGLUE, (offset >> 2)+1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001039 return false;
1040}
1041
1042static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1043 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001044 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001045{
1046 unsigned int i;
1047 unsigned int regMask = 0;
1048
1049 /* Load arguments to r0..r4 */
1050 for (i = 0; i < dInsn->vA; i++) {
1051 regMask |= 1 << i;
1052 loadValue(cUnit, dInsn->arg[i], i);
1053 }
1054 if (regMask) {
1055 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001056 newLIR2(cUnit, THUMB_MOV_RR, r7, rFP);
1057 newLIR2(cUnit, THUMB_SUB_RI8, r7,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001058 sizeof(StackSaveArea) + (dInsn->vA << 2));
1059 /* generate null check */
1060 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001061 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1062 NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001063 }
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001064 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001065 }
1066}
1067
1068static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1069 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001070 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001071{
1072 int srcOffset = dInsn->vC << 2;
1073 int numArgs = dInsn->vA;
1074 int regMask;
1075 /*
1076 * r4PC : &rFP[vC]
1077 * r7: &newFP[0]
1078 */
1079 if (srcOffset < 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001080 newLIR3(cUnit, THUMB_ADD_RRI3, r4PC, rFP, srcOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001081 } else {
1082 loadConstant(cUnit, r4PC, srcOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001083 newLIR3(cUnit, THUMB_ADD_RRR, r4PC, rFP, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001084 }
1085 /* load [r0 .. min(numArgs,4)] */
1086 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001087 newLIR2(cUnit, THUMB_LDMIA, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001088
1089 if (sizeof(StackSaveArea) + (numArgs << 2) < 256) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001090 newLIR2(cUnit, THUMB_MOV_RR, r7, rFP);
1091 newLIR2(cUnit, THUMB_SUB_RI8, r7,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001092 sizeof(StackSaveArea) + (numArgs << 2));
1093 } else {
1094 loadConstant(cUnit, r7, sizeof(StackSaveArea) + (numArgs << 2));
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001095 newLIR3(cUnit, THUMB_SUB_RRR, r7, rFP, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001096 }
1097
1098 /* generate null check */
1099 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001100 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001101 }
1102
1103 /*
1104 * Handle remaining 4n arguments:
1105 * store previously loaded 4 values and load the next 4 values
1106 */
1107 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001108 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001109 /*
1110 * r0 contains "this" and it will be used later, so push it to the stack
1111 * first. Pushing r5 is just for stack alignment purposes.
1112 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001113 newLIR1(cUnit, THUMB_PUSH, 1 << r0 | 1 << 5);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001114 /* No need to generate the loop structure if numArgs <= 11 */
1115 if (numArgs > 11) {
1116 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001117 loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001118 }
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001119 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
1120 newLIR2(cUnit, THUMB_LDMIA, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001121 /* No need to generate the loop structure if numArgs <= 11 */
1122 if (numArgs > 11) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001123 newLIR2(cUnit, THUMB_SUB_RI8, 5, 4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001124 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1125 }
1126 }
1127
1128 /* Save the last batch of loaded values */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001129 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001130
1131 /* Generate the loop epilogue - don't use r0 */
1132 if ((numArgs > 4) && (numArgs % 4)) {
1133 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001134 newLIR2(cUnit, THUMB_LDMIA, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001135 }
1136 if (numArgs >= 8)
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001137 newLIR1(cUnit, THUMB_POP, 1 << r0 | 1 << 5);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001138
1139 /* Save the modulo 4 arguments */
1140 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001141 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001142 }
1143}
1144
Ben Cheng38329f52009-07-07 14:19:20 -07001145/*
1146 * Generate code to setup the call stack then jump to the chaining cell if it
1147 * is not a native method.
1148 */
1149static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001150 BasicBlock *bb, ArmLIR *labelList,
1151 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001152 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001153{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001154 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001155
1156 /* r1 = &retChainingCell */
Ben Cheng3f02aa42009-08-14 13:52:09 -07001157 ArmLIR *addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL, r1, 0, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001158 /* r4PC = dalvikCallsite */
1159 loadConstant(cUnit, r4PC,
1160 (int) (cUnit->method->insns + mir->offset));
1161 addrRetChain->generic.target = (LIR *) retChainingCell;
1162 /*
Ben Cheng38329f52009-07-07 14:19:20 -07001163 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001164 * r1 = &ChainingCell
1165 * r4PC = callsiteDPC
1166 */
1167 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07001168 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001169#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07001170 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001171#endif
1172 } else {
1173 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1174#if defined(INVOKE_STATS)
1175 gDvmJit.invokeChain++;
1176#endif
Ben Cheng38329f52009-07-07 14:19:20 -07001177 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001178 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1179 }
1180 /* Handle exceptions using the interpreter */
1181 genTrap(cUnit, mir->offset, pcrLabel);
1182}
1183
Ben Cheng38329f52009-07-07 14:19:20 -07001184/*
1185 * Generate code to check the validity of a predicted chain and take actions
1186 * based on the result.
1187 *
1188 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1189 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1190 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1191 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1192 * 0x426a99b2 : blx_2 see above --+
1193 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1194 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1195 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1196 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1197 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1198 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1199 * 0x426a99c0 : blx r7 --+
1200 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1201 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1202 * 0x426a99c6 : blx_2 see above --+
1203 */
1204static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1205 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001206 ArmLIR *retChainingCell,
1207 ArmLIR *predChainingCell,
1208 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07001209{
1210 /* "this" is already left in r0 by genProcessArgs* */
1211
1212 /* r4PC = dalvikCallsite */
1213 loadConstant(cUnit, r4PC,
1214 (int) (cUnit->method->insns + mir->offset));
1215
1216 /* r1 = &retChainingCell */
Ben Cheng3f02aa42009-08-14 13:52:09 -07001217 ArmLIR *addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL, r1, 0, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001218 addrRetChain->generic.target = (LIR *) retChainingCell;
1219
1220 /* r2 = &predictedChainingCell */
Ben Cheng3f02aa42009-08-14 13:52:09 -07001221 ArmLIR *predictedChainingCell = newLIR3(cUnit, THUMB_ADD_PC_REL, r2, 0, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001222 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1223
1224 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1225
1226 /* return through lr - jump to the chaining cell */
1227 genUnconditionalBranch(cUnit, predChainingCell);
1228
1229 /*
1230 * null-check on "this" may have been eliminated, but we still need a PC-
1231 * reconstruction label for stack overflow bailout.
1232 */
1233 if (pcrLabel == NULL) {
1234 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001235 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1236 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07001237 pcrLabel->operands[0] = dPC;
1238 pcrLabel->operands[1] = mir->offset;
1239 /* Insert the place holder to the growable list */
1240 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1241 }
1242
1243 /* return through lr+2 - punt to the interpreter */
1244 genUnconditionalBranch(cUnit, pcrLabel);
1245
1246 /*
1247 * return through lr+4 - fully resolve the callee method.
1248 * r1 <- count
1249 * r2 <- &predictedChainCell
1250 * r3 <- this->class
1251 * r4 <- dPC
1252 * r7 <- this->class->vtable
1253 */
1254
1255 /* r0 <- calleeMethod */
1256 if (methodIndex < 32) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001257 newLIR3(cUnit, THUMB_LDR_RRI5, r0, r7, methodIndex);
Ben Cheng38329f52009-07-07 14:19:20 -07001258 } else {
1259 loadConstant(cUnit, r0, methodIndex<<2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001260 newLIR3(cUnit, THUMB_LDR_RRR, r0, r7, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001261 }
1262
1263 /* Check if rechain limit is reached */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001264 newLIR2(cUnit, THUMB_CMP_RI8, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001265
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001266 ArmLIR *bypassRechaining =
1267 newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07001268
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001269 newLIR3(cUnit, THUMB_LDR_RRI5, r7, rGLUE,
Ben Cheng38329f52009-07-07 14:19:20 -07001270 offsetof(InterpState,
1271 jitToInterpEntries.dvmJitToPatchPredictedChain)
1272 >> 2);
1273
1274 /*
1275 * r0 = calleeMethod
1276 * r2 = &predictedChainingCell
1277 * r3 = class
1278 *
1279 * &returnChainingCell has been loaded into r1 but is not needed
1280 * when patching the chaining cell and will be clobbered upon
1281 * returning so it will be reconstructed again.
1282 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001283 newLIR1(cUnit, THUMB_BLX_R, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001284
1285 /* r1 = &retChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001286 addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL, r1, 0, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001287 addrRetChain->generic.target = (LIR *) retChainingCell;
1288
1289 bypassRechaining->generic.target = (LIR *) addrRetChain;
1290 /*
1291 * r0 = calleeMethod,
1292 * r1 = &ChainingCell,
1293 * r4PC = callsiteDPC,
1294 */
1295 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1296#if defined(INVOKE_STATS)
1297 gDvmJit.invokePredictedChain++;
1298#endif
1299 /* Handle exceptions using the interpreter */
1300 genTrap(cUnit, mir->offset, pcrLabel);
1301}
1302
1303/*
1304 * Up calling this function, "this" is stored in r0. The actual class will be
1305 * chased down off r0 and the predicted one will be retrieved through
1306 * predictedChainingCell then a comparison is performed to see whether the
1307 * previously established chaining is still valid.
1308 *
1309 * The return LIR is a branch based on the comparison result. The actual branch
1310 * target will be setup in the caller.
1311 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001312static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1313 ArmLIR *predChainingCell,
1314 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07001315 MIR *mir)
1316{
1317 /* r3 now contains this->clazz */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001318 newLIR3(cUnit, THUMB_LDR_RRI5, r3, r0,
Ben Cheng38329f52009-07-07 14:19:20 -07001319 offsetof(Object, clazz) >> 2);
1320
1321 /*
1322 * r2 now contains predicted class. The starting offset of the
1323 * cached value is 4 bytes into the chaining cell.
1324 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001325 ArmLIR *getPredictedClass =
1326 newLIR3(cUnit, THUMB_LDR_PC_REL, r2, 0,
Ben Cheng38329f52009-07-07 14:19:20 -07001327 offsetof(PredictedChainingCell, clazz));
1328 getPredictedClass->generic.target = (LIR *) predChainingCell;
1329
1330 /*
1331 * r0 now contains predicted method. The starting offset of the
1332 * cached value is 8 bytes into the chaining cell.
1333 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001334 ArmLIR *getPredictedMethod =
1335 newLIR3(cUnit, THUMB_LDR_PC_REL, r0, 0,
Ben Cheng38329f52009-07-07 14:19:20 -07001336 offsetof(PredictedChainingCell, method));
1337 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1338
1339 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001340 ArmLIR *getRechainingRequestCount =
1341 newLIR3(cUnit, THUMB_LDR_PC_REL, r7, 0,
Ben Cheng38329f52009-07-07 14:19:20 -07001342 offsetof(PredictedChainingCell, counter));
1343 getRechainingRequestCount->generic.target =
1344 (LIR *) predChainingCell;
1345
1346 /* r4PC = dalvikCallsite */
1347 loadConstant(cUnit, r4PC,
1348 (int) (cUnit->method->insns + mir->offset));
1349
1350 /* r1 = &retChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001351 ArmLIR *addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL,
Ben Cheng38329f52009-07-07 14:19:20 -07001352 r1, 0, 0);
1353 addrRetChain->generic.target = (LIR *) retChainingCell;
1354
1355 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001356 newLIR2(cUnit, THUMB_CMP_RR, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001357
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001358 return newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_EQ);
Ben Cheng38329f52009-07-07 14:19:20 -07001359}
1360
Ben Chengba4fc8b2009-06-01 13:00:29 -07001361/* Geneate a branch to go back to the interpreter */
1362static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1363{
1364 /* r0 = dalvik pc */
1365 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001366 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001367 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpPunt) >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001368 newLIR1(cUnit, THUMB_BLX_R, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001369}
1370
1371/*
1372 * Attempt to single step one instruction using the interpreter and return
1373 * to the compiled code for the next Dalvik instruction
1374 */
1375static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1376{
1377 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1378 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1379 kInstrCanThrow;
1380 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1381 genPuntToInterp(cUnit, mir->offset);
1382 return;
1383 }
1384 int entryAddr = offsetof(InterpState,
1385 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001386 newLIR3(cUnit, THUMB_LDR_RRI5, r2, rGLUE, entryAddr >> 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001387 /* r0 = dalvik pc */
1388 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1389 /* r1 = dalvik pc of following instruction */
1390 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001391 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001392}
1393
1394
1395/*****************************************************************************/
1396/*
1397 * The following are the first-level codegen routines that analyze the format
1398 * of each bytecode then either dispatch special purpose codegen routines
1399 * or produce corresponding Thumb instructions directly.
1400 */
1401
1402static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001403 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001404{
1405 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1406 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1407 return false;
1408}
1409
1410static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1411{
1412 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1413 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1414 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
1415 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1416 return true;
1417 }
1418 switch (dalvikOpCode) {
1419 case OP_RETURN_VOID:
1420 genReturnCommon(cUnit,mir);
1421 break;
1422 case OP_UNUSED_73:
1423 case OP_UNUSED_79:
1424 case OP_UNUSED_7A:
1425 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1426 return true;
1427 case OP_NOP:
1428 break;
1429 default:
1430 return true;
1431 }
1432 return false;
1433}
1434
1435static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1436{
Ben Chenge9695e52009-06-16 16:11:47 -07001437 int reg0, reg1, reg2;
1438
Ben Chengba4fc8b2009-06-01 13:00:29 -07001439 switch (mir->dalvikInsn.opCode) {
1440 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07001441 case OP_CONST_4: {
1442 /* Avoid using the previously used register */
1443 reg0 = selectFirstRegister(cUnit, vNone, false);
1444 reg1 = NEXT_REG(reg0);
1445 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1446 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001447 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001448 }
1449 case OP_CONST_WIDE_32: {
1450 /* Avoid using the previously used register */
1451 reg0 = selectFirstRegister(cUnit, vNone, true);
1452 reg1 = NEXT_REG(reg0);
1453 reg2 = NEXT_REG(reg1);
1454 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001455 newLIR3(cUnit, THUMB_ASR, reg1, reg0, 31);
Ben Chenge9695e52009-06-16 16:11:47 -07001456 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001457 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001458 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001459 default:
1460 return true;
1461 }
1462 return false;
1463}
1464
1465static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1466{
Ben Chenge9695e52009-06-16 16:11:47 -07001467 int reg0, reg1, reg2;
1468
1469 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001470 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07001471 case OP_CONST_HIGH16: {
1472 reg0 = selectFirstRegister(cUnit, vNone, false);
1473 reg1 = NEXT_REG(reg0);
1474 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
1475 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001476 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001477 }
1478 case OP_CONST_WIDE_HIGH16: {
1479 reg0 = selectFirstRegister(cUnit, vNone, true);
1480 reg1 = NEXT_REG(reg0);
1481 reg2 = NEXT_REG(reg1);
1482 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
1483 loadConstant(cUnit, reg0, 0);
1484 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001485 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001486 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001487 default:
1488 return true;
1489 }
1490 return false;
1491}
1492
1493static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1494{
1495 /* For OP_THROW_VERIFICATION_ERROR */
1496 genInterpSingleStep(cUnit, mir);
1497 return false;
1498}
1499
1500static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1501{
Ben Chenge9695e52009-06-16 16:11:47 -07001502 /* Native register to use if the interested value is vA */
1503 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
1504 /* Native register to use if source is not from Dalvik registers */
1505 int regvNone = selectFirstRegister(cUnit, vNone, false);
1506 /* Similar to regvA but for 64-bit values */
1507 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
1508 /* Similar to regvNone but for 64-bit values */
1509 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
1510
Ben Chengba4fc8b2009-06-01 13:00:29 -07001511 switch (mir->dalvikInsn.opCode) {
1512 /*
1513 * TODO: Verify that we can ignore the resolution check here because
1514 * it will have already successfully been interpreted once
1515 */
1516 case OP_CONST_STRING_JUMBO:
1517 case OP_CONST_STRING: {
1518 void *strPtr = (void*)
1519 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1520 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001521 loadConstant(cUnit, regvNone, (int) strPtr );
1522 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001523 break;
1524 }
1525 /*
1526 * TODO: Verify that we can ignore the resolution check here because
1527 * it will have already successfully been interpreted once
1528 */
1529 case OP_CONST_CLASS: {
1530 void *classPtr = (void*)
1531 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1532 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001533 loadConstant(cUnit, regvNone, (int) classPtr );
1534 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001535 break;
1536 }
1537 case OP_SGET_OBJECT:
1538 case OP_SGET_BOOLEAN:
1539 case OP_SGET_CHAR:
1540 case OP_SGET_BYTE:
1541 case OP_SGET_SHORT:
1542 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001543 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001544 void *fieldPtr = (void*)
1545 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1546 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001547 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001548 newLIR3(cUnit, THUMB_LDR_RRI5, regvNone, regvNone, 0);
Ben Chenge9695e52009-06-16 16:11:47 -07001549 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001550 break;
1551 }
1552 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001553 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001554 void *fieldPtr = (void*)
1555 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001556 int reg0, reg1, reg2;
1557
Ben Chengba4fc8b2009-06-01 13:00:29 -07001558 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001559 reg0 = regvNoneWide;
1560 reg1 = NEXT_REG(reg0);
1561 reg2 = NEXT_REG(reg1);
1562 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001563 newLIR2(cUnit, THUMB_LDMIA, reg2, (1<<reg0 | 1<<reg1));
Ben Chenge9695e52009-06-16 16:11:47 -07001564 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001565 break;
1566 }
1567 case OP_SPUT_OBJECT:
1568 case OP_SPUT_BOOLEAN:
1569 case OP_SPUT_CHAR:
1570 case OP_SPUT_BYTE:
1571 case OP_SPUT_SHORT:
1572 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001573 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001574 void *fieldPtr = (void*)
1575 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001576
Ben Chengba4fc8b2009-06-01 13:00:29 -07001577 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001578 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
1579 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
1580 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001581 newLIR3(cUnit, THUMB_STR_RRI5, regvA, NEXT_REG(regvA), 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001582 break;
1583 }
1584 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001585 int reg0, reg1, reg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001586 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001587 void *fieldPtr = (void*)
1588 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001589
Ben Chengba4fc8b2009-06-01 13:00:29 -07001590 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001591 reg0 = regvAWide;
1592 reg1 = NEXT_REG(reg0);
1593 reg2 = NEXT_REG(reg1);
1594 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
1595 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
1596 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001597 newLIR2(cUnit, THUMB_STMIA, reg2, (1<<reg0 | 1<<reg1));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001598 break;
1599 }
1600 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001601 /*
1602 * Obey the calling convention and don't mess with the register
1603 * usage.
1604 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001605 ClassObject *classPtr = (void*)
1606 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1607 assert(classPtr != NULL);
1608 assert(classPtr->status & CLASS_INITIALIZED);
1609 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
1610 /* It's going to throw, just let the interp. deal with it. */
1611 genInterpSingleStep(cUnit, mir);
1612 return false;
1613 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001614 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07001615 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001616 genExportPC(cUnit, mir, r2, r3 );
1617 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001618 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001619 /*
1620 * TODO: As coded, we'll bail and reinterpret on alloc failure.
1621 * Need a general mechanism to bail to thrown exception code.
1622 */
Ben Chenge9695e52009-06-16 16:11:47 -07001623 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001624 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1625 break;
1626 }
1627 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07001628 /*
1629 * Obey the calling convention and don't mess with the register
1630 * usage.
1631 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001632 ClassObject *classPtr =
1633 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1634 loadConstant(cUnit, r1, (int) classPtr );
1635 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
1636 /*
1637 * TODO - in theory classPtr should be resoved by the time this
1638 * instruction made into a trace, but we are seeing NULL at runtime
1639 * so this check is temporarily used as a workaround.
1640 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001641 ArmLIR * pcrLabel = genZeroCheck(cUnit, r1, mir->offset, NULL);
1642 newLIR2(cUnit, THUMB_CMP_RI8, r0, 0); /* Null? */
1643 ArmLIR *branch1 =
1644 newLIR2(cUnit, THUMB_B_COND, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001645 /* r0 now contains object->clazz */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001646 newLIR3(cUnit, THUMB_LDR_RRI5, r0, r0,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001647 offsetof(Object, clazz) >> 2);
1648 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001649 newLIR2(cUnit, THUMB_CMP_RR, r0, r1);
1650 ArmLIR *branch2 =
1651 newLIR2(cUnit, THUMB_B_COND, 2, ARM_COND_EQ);
1652 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001653 /* check cast failed - punt to the interpreter */
Ben Chenge9695e52009-06-16 16:11:47 -07001654 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001655 /* check cast passed - branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001656 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001657 branch1->generic.target = (LIR *)target;
1658 branch2->generic.target = (LIR *)target;
1659 break;
1660 }
1661 default:
1662 return true;
1663 }
1664 return false;
1665}
1666
1667static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1668{
1669 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1670 switch (dalvikOpCode) {
1671 case OP_MOVE_EXCEPTION: {
1672 int offset = offsetof(InterpState, self);
1673 int exOffset = offsetof(Thread, exception);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001674 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE, offset >> 2);
1675 newLIR3(cUnit, THUMB_LDR_RRI5, r0, r1, exOffset >> 2);
Ben Chenge9695e52009-06-16 16:11:47 -07001676 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001677 break;
1678 }
1679 case OP_MOVE_RESULT:
1680 case OP_MOVE_RESULT_OBJECT: {
1681 int offset = offsetof(InterpState, retval);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001682 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE, offset >> 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001683 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1684 break;
1685 }
1686 case OP_MOVE_RESULT_WIDE: {
1687 int offset = offsetof(InterpState, retval);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001688 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE, offset >> 2);
1689 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE, (offset >> 2)+1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001690 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1691 break;
1692 }
1693 case OP_RETURN_WIDE: {
1694 loadValuePair(cUnit, mir->dalvikInsn.vA, r0, r1);
1695 int offset = offsetof(InterpState, retval);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001696 newLIR3(cUnit, THUMB_STR_RRI5, r0, rGLUE, offset >> 2);
1697 newLIR3(cUnit, THUMB_STR_RRI5, r1, rGLUE, (offset >> 2)+1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001698 genReturnCommon(cUnit,mir);
1699 break;
1700 }
1701 case OP_RETURN:
1702 case OP_RETURN_OBJECT: {
1703 loadValue(cUnit, mir->dalvikInsn.vA, r0);
1704 int offset = offsetof(InterpState, retval);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001705 newLIR3(cUnit, THUMB_STR_RRI5, r0, rGLUE, offset >> 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001706 genReturnCommon(cUnit,mir);
1707 break;
1708 }
1709 /*
1710 * TODO-VERIFY: May be playing a bit fast and loose here. As coded,
1711 * a failure on lock/unlock will cause us to revert to the interpeter
1712 * to try again. This means we essentially ignore the first failure on
1713 * the assumption that the interpreter will correctly handle the 2nd.
1714 */
1715 case OP_MONITOR_ENTER:
1716 case OP_MONITOR_EXIT: {
1717 int offset = offsetof(InterpState, self);
1718 loadValue(cUnit, mir->dalvikInsn.vA, r1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001719 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE, offset >> 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001720 if (dalvikOpCode == OP_MONITOR_ENTER) {
1721 loadConstant(cUnit, r2, (int)dvmLockObject);
1722 } else {
1723 loadConstant(cUnit, r2, (int)dvmUnlockObject);
1724 }
1725 /*
1726 * TODO-VERIFY: Note that we're not doing an EXPORT_PC, as
1727 * Lock/unlock won't throw, and this code does not support
1728 * DEADLOCK_PREDICTION or MONITOR_TRACKING. Should it?
1729 */
Ben Chenge9695e52009-06-16 16:11:47 -07001730 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001731 /* Do the call */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001732 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001733 break;
1734 }
1735 case OP_THROW: {
1736 genInterpSingleStep(cUnit, mir);
1737 break;
1738 }
1739 default:
1740 return true;
1741 }
1742 return false;
1743}
1744
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001745static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001746{
1747 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001748
Ben Chengba4fc8b2009-06-01 13:00:29 -07001749 float __aeabi_i2f( int op1 );
1750 int __aeabi_f2iz( float op1 );
1751 float __aeabi_d2f( double op1 );
1752 double __aeabi_f2d( float op1 );
1753 double __aeabi_i2d( int op1 );
1754 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07001755 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07001756 double __aeabi_l2d( long op1 );
1757
Bill Buzbeed45ba372009-06-15 17:00:57 -07001758 switch (opCode) {
1759 case OP_INT_TO_FLOAT:
1760 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
1761 case OP_FLOAT_TO_INT:
1762 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
1763 case OP_DOUBLE_TO_FLOAT:
1764 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
1765 case OP_FLOAT_TO_DOUBLE:
1766 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
1767 case OP_INT_TO_DOUBLE:
1768 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
1769 case OP_DOUBLE_TO_INT:
1770 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
1771 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001772 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07001773 case OP_LONG_TO_FLOAT:
1774 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
1775 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001776 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07001777 case OP_LONG_TO_DOUBLE:
1778 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
1779 default:
1780 return true;
1781 }
1782 return false;
1783}
1784
1785static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1786{
1787 OpCode opCode = mir->dalvikInsn.opCode;
1788 int vSrc1Dest = mir->dalvikInsn.vA;
1789 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07001790 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07001791
1792 /* TODO - find the proper include file to declare these */
1793
Ben Chengba4fc8b2009-06-01 13:00:29 -07001794 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1795 return genArithOp( cUnit, mir );
1796 }
1797
Ben Chenge9695e52009-06-16 16:11:47 -07001798 /*
1799 * If data type is 64-bit, re-calculate the register numbers in the
1800 * corresponding cases.
1801 */
1802 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1803 reg1 = NEXT_REG(reg0);
1804 reg2 = NEXT_REG(reg1);
1805
Ben Chengba4fc8b2009-06-01 13:00:29 -07001806 switch (opCode) {
1807 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001808 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001809 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001810 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001811 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001812 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001813 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001814 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001815 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001816 case OP_LONG_TO_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001817 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001818 case OP_NEG_INT:
1819 case OP_NOT_INT:
1820 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
1821 case OP_NEG_LONG:
1822 case OP_NOT_LONG:
1823 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
1824 case OP_NEG_FLOAT:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001825 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001826 case OP_NEG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001827 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07001828 case OP_MOVE_WIDE: {
1829 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1830 reg1 = NEXT_REG(reg0);
1831 reg2 = NEXT_REG(reg1);
1832
1833 loadValuePair(cUnit, vSrc2, reg0, reg1);
1834 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001835 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001836 }
1837 case OP_INT_TO_LONG: {
1838 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1839 reg1 = NEXT_REG(reg0);
1840 reg2 = NEXT_REG(reg1);
1841
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001842 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001843 newLIR3(cUnit, THUMB_ASR, reg1, reg0, 31);
Ben Chenge9695e52009-06-16 16:11:47 -07001844 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001845 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001846 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001847 case OP_MOVE:
1848 case OP_MOVE_OBJECT:
1849 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07001850 loadValue(cUnit, vSrc2, reg0);
1851 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001852 break;
1853 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07001854 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001855 newLIR3(cUnit, THUMB_LSL, reg0, reg0, 24);
1856 newLIR3(cUnit, THUMB_ASR, reg0, reg0, 24);
Ben Chenge9695e52009-06-16 16:11:47 -07001857 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001858 break;
1859 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07001860 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001861 newLIR3(cUnit, THUMB_LSL, reg0, reg0, 16);
1862 newLIR3(cUnit, THUMB_ASR, reg0, reg0, 16);
Ben Chenge9695e52009-06-16 16:11:47 -07001863 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001864 break;
1865 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07001866 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001867 newLIR3(cUnit, THUMB_LSL, reg0, reg0, 16);
1868 newLIR3(cUnit, THUMB_LSR, reg0, reg0, 16);
Ben Chenge9695e52009-06-16 16:11:47 -07001869 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001870 break;
1871 case OP_ARRAY_LENGTH: {
1872 int lenOffset = offsetof(ArrayObject, length);
Ben Chenge9695e52009-06-16 16:11:47 -07001873 loadValue(cUnit, vSrc2, reg0);
1874 genNullCheck(cUnit, vSrc2, reg0, mir->offset, NULL);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001875 newLIR3(cUnit, THUMB_LDR_RRI5, reg0, reg0, lenOffset >> 2);
Ben Chenge9695e52009-06-16 16:11:47 -07001876 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001877 break;
1878 }
1879 default:
1880 return true;
1881 }
1882 return false;
1883}
1884
1885static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
1886{
1887 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07001888 int reg0, reg1, reg2;
1889
Ben Chengba4fc8b2009-06-01 13:00:29 -07001890 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
1891 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07001892 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001893 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07001894
1895 reg0 = selectFirstRegister(cUnit, vNone, true);
1896 reg1 = NEXT_REG(reg0);
1897 reg2 = NEXT_REG(reg1);
1898
1899 loadConstant(cUnit, reg0, BBBB);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001900 newLIR3(cUnit, THUMB_ASR, reg1, reg0, 31);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001901
1902 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07001903 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001904 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07001905 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001906 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001907
Ben Chenge9695e52009-06-16 16:11:47 -07001908 reg0 = selectFirstRegister(cUnit, vNone, false);
1909 reg1 = NEXT_REG(reg0);
1910
1911 loadConstant(cUnit, reg0, BBBB);
1912 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001913 } else {
1914 return true;
1915 }
1916 return false;
1917}
1918
1919/* Compare agaist zero */
1920static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001921 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001922{
1923 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001924 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07001925 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001926
Ben Chenge9695e52009-06-16 16:11:47 -07001927 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001928 newLIR2(cUnit, THUMB_CMP_RI8, reg0, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001929
1930 switch (dalvikOpCode) {
1931 case OP_IF_EQZ:
1932 cond = ARM_COND_EQ;
1933 break;
1934 case OP_IF_NEZ:
1935 cond = ARM_COND_NE;
1936 break;
1937 case OP_IF_LTZ:
1938 cond = ARM_COND_LT;
1939 break;
1940 case OP_IF_GEZ:
1941 cond = ARM_COND_GE;
1942 break;
1943 case OP_IF_GTZ:
1944 cond = ARM_COND_GT;
1945 break;
1946 case OP_IF_LEZ:
1947 cond = ARM_COND_LE;
1948 break;
1949 default:
1950 cond = 0;
1951 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
1952 dvmAbort();
1953 }
1954 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1955 /* This mostly likely will be optimized away in a later phase */
1956 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1957 return false;
1958}
1959
1960static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
1961{
1962 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1963 int vSrc = mir->dalvikInsn.vB;
1964 int vDest = mir->dalvikInsn.vA;
1965 int lit = mir->dalvikInsn.vC;
1966 int armOp;
Ben Chenge9695e52009-06-16 16:11:47 -07001967 int reg0, reg1, regDest;
1968
1969 reg0 = selectFirstRegister(cUnit, vSrc, false);
1970 reg1 = NEXT_REG(reg0);
1971 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001972
1973 /* TODO: find the proper .h file to declare these */
1974 int __aeabi_idivmod(int op1, int op2);
1975 int __aeabi_idiv(int op1, int op2);
1976
1977 switch (dalvikOpCode) {
1978 case OP_ADD_INT_LIT8:
1979 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07001980 loadValue(cUnit, vSrc, reg0);
1981 if (lit <= 7 && lit >= 0) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001982 newLIR3(cUnit, THUMB_ADD_RRI3, regDest, reg0, lit);
Ben Chenge9695e52009-06-16 16:11:47 -07001983 storeValue(cUnit, regDest, vDest, reg1);
1984 } else if (lit <= 255 && lit >= 0) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001985 newLIR2(cUnit, THUMB_ADD_RI8, reg0, lit);
Ben Chenge9695e52009-06-16 16:11:47 -07001986 storeValue(cUnit, reg0, vDest, reg1);
1987 } else if (lit >= -7 && lit <= 0) {
1988 /* Convert to a small constant subtraction */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001989 newLIR3(cUnit, THUMB_SUB_RRI3, regDest, reg0, -lit);
Ben Chenge9695e52009-06-16 16:11:47 -07001990 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001991 } else if (lit >= -255 && lit <= 0) {
1992 /* Convert to a small constant subtraction */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001993 newLIR2(cUnit, THUMB_SUB_RI8, reg0, -lit);
Ben Chenge9695e52009-06-16 16:11:47 -07001994 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001995 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001996 loadConstant(cUnit, reg1, lit);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001997 genBinaryOp(cUnit, vDest, THUMB_ADD_RRR, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001998 }
1999 break;
2000
2001 case OP_RSUB_INT_LIT8:
2002 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002003 loadValue(cUnit, vSrc, reg1);
2004 loadConstant(cUnit, reg0, lit);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002005 genBinaryOp(cUnit, vDest, THUMB_SUB_RRR, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002006 break;
2007
2008 case OP_MUL_INT_LIT8:
2009 case OP_MUL_INT_LIT16:
2010 case OP_AND_INT_LIT8:
2011 case OP_AND_INT_LIT16:
2012 case OP_OR_INT_LIT8:
2013 case OP_OR_INT_LIT16:
2014 case OP_XOR_INT_LIT8:
2015 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002016 loadValue(cUnit, vSrc, reg0);
2017 loadConstant(cUnit, reg1, lit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002018 switch (dalvikOpCode) {
2019 case OP_MUL_INT_LIT8:
2020 case OP_MUL_INT_LIT16:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002021 armOp = THUMB_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002022 break;
2023 case OP_AND_INT_LIT8:
2024 case OP_AND_INT_LIT16:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002025 armOp = THUMB_AND_RR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002026 break;
2027 case OP_OR_INT_LIT8:
2028 case OP_OR_INT_LIT16:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002029 armOp = THUMB_ORR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002030 break;
2031 case OP_XOR_INT_LIT8:
2032 case OP_XOR_INT_LIT16:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002033 armOp = THUMB_EOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002034 break;
2035 default:
2036 dvmAbort();
2037 }
Ben Chenge9695e52009-06-16 16:11:47 -07002038 genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002039 break;
2040
2041 case OP_SHL_INT_LIT8:
2042 case OP_SHR_INT_LIT8:
2043 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002044 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002045 switch (dalvikOpCode) {
2046 case OP_SHL_INT_LIT8:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002047 armOp = THUMB_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002048 break;
2049 case OP_SHR_INT_LIT8:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002050 armOp = THUMB_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002051 break;
2052 case OP_USHR_INT_LIT8:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002053 armOp = THUMB_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002054 break;
2055 default: dvmAbort();
2056 }
Ben Chenge9695e52009-06-16 16:11:47 -07002057 newLIR3(cUnit, armOp, reg0, reg0, lit);
2058 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002059 break;
2060
2061 case OP_DIV_INT_LIT8:
2062 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002063 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002064 if (lit == 0) {
2065 /* Let the interpreter deal with div by 0 */
2066 genInterpSingleStep(cUnit, mir);
2067 return false;
2068 }
2069 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2070 loadConstant(cUnit, r1, lit);
2071 loadValue(cUnit, vSrc, r0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002072 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002073 storeValue(cUnit, r0, vDest, r2);
2074 break;
2075
2076 case OP_REM_INT_LIT8:
2077 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002078 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002079 if (lit == 0) {
2080 /* Let the interpreter deal with div by 0 */
2081 genInterpSingleStep(cUnit, mir);
2082 return false;
2083 }
2084 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2085 loadConstant(cUnit, r1, lit);
2086 loadValue(cUnit, vSrc, r0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002087 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002088 storeValue(cUnit, r1, vDest, r2);
2089 break;
2090 default:
2091 return true;
2092 }
2093 return false;
2094}
2095
2096static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2097{
2098 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2099 int fieldOffset;
2100
2101 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2102 InstField *pInstField = (InstField *)
2103 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2104 int fieldOffset;
2105
2106 assert(pInstField != NULL);
2107 fieldOffset = pInstField->byteOffset;
2108 } else {
2109 /* To make the compiler happy */
2110 fieldOffset = 0;
2111 }
2112 switch (dalvikOpCode) {
2113 /*
2114 * TODO: I may be assuming too much here.
2115 * Verify what is known at JIT time.
2116 */
2117 case OP_NEW_ARRAY: {
2118 void *classPtr = (void*)
2119 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2120 assert(classPtr != NULL);
2121 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2122 loadConstant(cUnit, r0, (int) classPtr );
2123 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002124 ArmLIR *pcrLabel =
Ben Chengba4fc8b2009-06-01 13:00:29 -07002125 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2126 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002127 newLIR2(cUnit, THUMB_MOV_IMM,r2,ALLOC_DONT_TRACK);
2128 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002129 /*
2130 * TODO: As coded, we'll bail and reinterpret on alloc failure.
2131 * Need a general mechanism to bail to thrown exception code.
2132 */
Ben Chenge9695e52009-06-16 16:11:47 -07002133 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002134 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2135 break;
2136 }
2137 /*
2138 * TODO: I may be assuming too much here.
2139 * Verify what is known at JIT time.
2140 */
2141 case OP_INSTANCE_OF: {
2142 ClassObject *classPtr =
2143 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2144 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002145 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002146 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002147 newLIR2(cUnit, THUMB_CMP_RI8, r0, 0); /* Null? */
Ben Cheng752c7942009-06-22 10:50:07 -07002148 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002149 ArmLIR *branch1 = newLIR2(cUnit, THUMB_B_COND, 4,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002150 ARM_COND_EQ);
2151 /* r1 now contains object->clazz */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002152 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002153 offsetof(Object, clazz) >> 2);
2154 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002155 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002156 newLIR2(cUnit, THUMB_CMP_RR, r1, r2);
2157 ArmLIR *branch2 = newLIR2(cUnit, THUMB_B_COND, 2,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002158 ARM_COND_EQ);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002159 newLIR2(cUnit, THUMB_MOV_RR, r0, r1);
2160 newLIR2(cUnit, THUMB_MOV_RR, r1, r2);
2161 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002162 /* branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002163 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002164 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2165 branch1->generic.target = (LIR *)target;
2166 branch2->generic.target = (LIR *)target;
2167 break;
2168 }
2169 case OP_IGET_WIDE:
2170 genIGetWide(cUnit, mir, fieldOffset);
2171 break;
2172 case OP_IGET:
2173 case OP_IGET_OBJECT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002174 genIGet(cUnit, mir, THUMB_LDR_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002175 break;
2176 case OP_IGET_BOOLEAN:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002177 genIGet(cUnit, mir, THUMB_LDRB_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002178 break;
2179 case OP_IGET_BYTE:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002180 genIGet(cUnit, mir, THUMB_LDRSB_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002181 break;
2182 case OP_IGET_CHAR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002183 genIGet(cUnit, mir, THUMB_LDRH_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002184 break;
2185 case OP_IGET_SHORT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002186 genIGet(cUnit, mir, THUMB_LDRSH_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002187 break;
2188 case OP_IPUT_WIDE:
2189 genIPutWide(cUnit, mir, fieldOffset);
2190 break;
2191 case OP_IPUT:
2192 case OP_IPUT_OBJECT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002193 genIPut(cUnit, mir, THUMB_STR_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002194 break;
2195 case OP_IPUT_SHORT:
2196 case OP_IPUT_CHAR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002197 genIPut(cUnit, mir, THUMB_STRH_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002198 break;
2199 case OP_IPUT_BYTE:
2200 case OP_IPUT_BOOLEAN:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002201 genIPut(cUnit, mir, THUMB_STRB_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002202 break;
2203 default:
2204 return true;
2205 }
2206 return false;
2207}
2208
2209static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2210{
2211 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2212 int fieldOffset = mir->dalvikInsn.vC;
2213 switch (dalvikOpCode) {
2214 case OP_IGET_QUICK:
2215 case OP_IGET_OBJECT_QUICK:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002216 genIGet(cUnit, mir, THUMB_LDR_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002217 break;
2218 case OP_IPUT_QUICK:
2219 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002220 genIPut(cUnit, mir, THUMB_STR_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002221 break;
2222 case OP_IGET_WIDE_QUICK:
2223 genIGetWide(cUnit, mir, fieldOffset);
2224 break;
2225 case OP_IPUT_WIDE_QUICK:
2226 genIPutWide(cUnit, mir, fieldOffset);
2227 break;
2228 default:
2229 return true;
2230 }
2231 return false;
2232
2233}
2234
2235/* Compare agaist zero */
2236static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002237 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002238{
2239 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002240 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002241 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002242
Ben Chenge9695e52009-06-16 16:11:47 -07002243 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2244 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2245 reg1 = NEXT_REG(reg0);
2246 /* Load vB first since vA can be fetched via a move */
2247 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2248 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2249 } else {
2250 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2251 reg1 = NEXT_REG(reg0);
2252 /* Load vA first since vB can be fetched via a move */
2253 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2254 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2255 }
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002256 newLIR2(cUnit, THUMB_CMP_RR, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002257
2258 switch (dalvikOpCode) {
2259 case OP_IF_EQ:
2260 cond = ARM_COND_EQ;
2261 break;
2262 case OP_IF_NE:
2263 cond = ARM_COND_NE;
2264 break;
2265 case OP_IF_LT:
2266 cond = ARM_COND_LT;
2267 break;
2268 case OP_IF_GE:
2269 cond = ARM_COND_GE;
2270 break;
2271 case OP_IF_GT:
2272 cond = ARM_COND_GT;
2273 break;
2274 case OP_IF_LE:
2275 cond = ARM_COND_LE;
2276 break;
2277 default:
2278 cond = 0;
2279 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2280 dvmAbort();
2281 }
2282 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2283 /* This mostly likely will be optimized away in a later phase */
2284 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2285 return false;
2286}
2287
2288static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2289{
2290 OpCode opCode = mir->dalvikInsn.opCode;
2291 int vSrc1Dest = mir->dalvikInsn.vA;
2292 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002293 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002294
2295 switch (opCode) {
2296 case OP_MOVE_16:
2297 case OP_MOVE_OBJECT_16:
2298 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002299 case OP_MOVE_OBJECT_FROM16: {
2300 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2301 reg1 = NEXT_REG(reg0);
2302 loadValue(cUnit, vSrc2, reg0);
2303 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002304 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002305 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002306 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002307 case OP_MOVE_WIDE_FROM16: {
2308 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2309 reg1 = NEXT_REG(reg0);
2310 reg2 = NEXT_REG(reg1);
2311 loadValuePair(cUnit, vSrc2, reg0, reg1);
2312 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002313 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002314 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002315 default:
2316 return true;
2317 }
2318 return false;
2319}
2320
2321static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2322{
2323 OpCode opCode = mir->dalvikInsn.opCode;
2324 int vA = mir->dalvikInsn.vA;
2325 int vB = mir->dalvikInsn.vB;
2326 int vC = mir->dalvikInsn.vC;
2327
Ben Chenge9695e52009-06-16 16:11:47 -07002328 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002329 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2330 return genArithOp( cUnit, mir );
2331 }
2332
2333 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002334 case OP_CMPL_FLOAT:
2335 case OP_CMPG_FLOAT:
2336 case OP_CMPL_DOUBLE:
2337 case OP_CMPG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002338 return genCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002339 case OP_CMP_LONG:
2340 loadValuePair(cUnit,vB, r0, r1);
2341 loadValuePair(cUnit, vC, r2, r3);
2342 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
2343 storeValue(cUnit, r0, vA, r1);
2344 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002345 case OP_AGET_WIDE:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002346 genArrayGet(cUnit, mir, THUMB_LDR_RRR, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002347 break;
2348 case OP_AGET:
2349 case OP_AGET_OBJECT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002350 genArrayGet(cUnit, mir, THUMB_LDR_RRR, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002351 break;
2352 case OP_AGET_BOOLEAN:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002353 genArrayGet(cUnit, mir, THUMB_LDRB_RRR, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002354 break;
2355 case OP_AGET_BYTE:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002356 genArrayGet(cUnit, mir, THUMB_LDRSB_RRR, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002357 break;
2358 case OP_AGET_CHAR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002359 genArrayGet(cUnit, mir, THUMB_LDRH_RRR, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002360 break;
2361 case OP_AGET_SHORT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002362 genArrayGet(cUnit, mir, THUMB_LDRSH_RRR, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002363 break;
2364 case OP_APUT_WIDE:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002365 genArrayPut(cUnit, mir, THUMB_STR_RRR, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002366 break;
2367 case OP_APUT:
2368 case OP_APUT_OBJECT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002369 genArrayPut(cUnit, mir, THUMB_STR_RRR, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002370 break;
2371 case OP_APUT_SHORT:
2372 case OP_APUT_CHAR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002373 genArrayPut(cUnit, mir, THUMB_STRH_RRR, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002374 break;
2375 case OP_APUT_BYTE:
2376 case OP_APUT_BOOLEAN:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002377 genArrayPut(cUnit, mir, THUMB_STRB_RRR, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002378 break;
2379 default:
2380 return true;
2381 }
2382 return false;
2383}
2384
2385static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2386{
2387 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2388 switch (dalvikOpCode) {
2389 case OP_FILL_ARRAY_DATA: {
2390 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2391 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2392 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2393 (int) (cUnit->method->insns + mir->offset));
2394 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002395 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002396 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002397 break;
2398 }
2399 /*
2400 * TODO
2401 * - Add a 1 to 3-entry per-location cache here to completely
2402 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2403 * - Use out-of-line handlers for both of these
2404 */
2405 case OP_PACKED_SWITCH:
2406 case OP_SPARSE_SWITCH: {
2407 if (dalvikOpCode == OP_PACKED_SWITCH) {
2408 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2409 } else {
2410 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2411 }
2412 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2413 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2414 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002415 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002416 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002417 newLIR3(cUnit, THUMB_LDR_RRI5, r2, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002418 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNoChain)
2419 >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002420 newLIR3(cUnit, THUMB_ADD_RRR, r0, r0, r0);
2421 newLIR3(cUnit, THUMB_ADD_RRR, r4PC, r0, r1);
2422 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002423 break;
2424 }
2425 default:
2426 return true;
2427 }
2428 return false;
2429}
2430
2431static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002432 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002433{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07002434 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002435 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002436
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07002437 if (bb->fallThrough != NULL)
2438 retChainingCell = &labelList[bb->fallThrough->id];
2439
Ben Chengba4fc8b2009-06-01 13:00:29 -07002440 DecodedInstruction *dInsn = &mir->dalvikInsn;
2441 switch (mir->dalvikInsn.opCode) {
2442 /*
2443 * calleeMethod = this->clazz->vtable[
2444 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2445 * ]
2446 */
2447 case OP_INVOKE_VIRTUAL:
2448 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002449 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002450 int methodIndex =
2451 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2452 methodIndex;
2453
2454 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2455 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2456 else
2457 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2458
Ben Cheng38329f52009-07-07 14:19:20 -07002459 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2460 retChainingCell,
2461 predChainingCell,
2462 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002463 break;
2464 }
2465 /*
2466 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2467 * ->pResMethods[BBBB]->methodIndex]
2468 */
2469 /* TODO - not excersized in RunPerf.jar */
2470 case OP_INVOKE_SUPER:
2471 case OP_INVOKE_SUPER_RANGE: {
2472 int mIndex = cUnit->method->clazz->pDvmDex->
2473 pResMethods[dInsn->vB]->methodIndex;
2474 const Method *calleeMethod =
2475 cUnit->method->clazz->super->vtable[mIndex];
2476
2477 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2478 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2479 else
2480 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2481
2482 /* r0 = calleeMethod */
2483 loadConstant(cUnit, r0, (int) calleeMethod);
2484
Ben Cheng38329f52009-07-07 14:19:20 -07002485 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2486 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002487 break;
2488 }
2489 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2490 case OP_INVOKE_DIRECT:
2491 case OP_INVOKE_DIRECT_RANGE: {
2492 const Method *calleeMethod =
2493 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2494
2495 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2496 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2497 else
2498 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2499
2500 /* r0 = calleeMethod */
2501 loadConstant(cUnit, r0, (int) calleeMethod);
2502
Ben Cheng38329f52009-07-07 14:19:20 -07002503 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2504 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002505 break;
2506 }
2507 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2508 case OP_INVOKE_STATIC:
2509 case OP_INVOKE_STATIC_RANGE: {
2510 const Method *calleeMethod =
2511 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2512
2513 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2514 genProcessArgsNoRange(cUnit, mir, dInsn,
2515 NULL /* no null check */);
2516 else
2517 genProcessArgsRange(cUnit, mir, dInsn,
2518 NULL /* no null check */);
2519
2520 /* r0 = calleeMethod */
2521 loadConstant(cUnit, r0, (int) calleeMethod);
2522
Ben Cheng38329f52009-07-07 14:19:20 -07002523 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2524 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002525 break;
2526 }
2527 /*
2528 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2529 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07002530 *
2531 * Given "invoke-interface {v0}", the following is the generated code:
2532 *
2533 * 0x426a9abe : ldr r0, [r5, #0] --+
2534 * 0x426a9ac0 : mov r7, r5 |
2535 * 0x426a9ac2 : sub r7, #24 |
2536 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
2537 * 0x426a9ac6 : beq 0x426a9afe |
2538 * 0x426a9ac8 : stmia r7, <r0> --+
2539 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2540 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
2541 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
2542 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
2543 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
2544 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
2545 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
2546 * 0x426a9ad8 : mov r9, r1 --+
2547 * 0x426a9ada : mov r10, r2 |
2548 * 0x426a9adc : mov r12, r3 |
2549 * 0x426a9ade : mov r0, r3 |
2550 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
2551 * 0x426a9ae2 : ldr r2, [pc, #76] |
2552 * 0x426a9ae4 : ldr r3, [pc, #68] |
2553 * 0x426a9ae6 : ldr r7, [pc, #64] |
2554 * 0x426a9ae8 : blx r7 --+
2555 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
2556 * 0x426a9aec : cmp r1, #0 --> compare against 0
2557 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
2558 * 0x426a9af0 : ldr r7, [r6, #96] --+
2559 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
2560 * 0x426a9af4 : mov r3, r12 |
2561 * 0x426a9af6 : blx r7 --+
2562 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
2563 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2564 * 0x426a9afc : blx_2 see above --+
2565 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
2566 * 0x426a9afe (0042): ldr r0, [pc, #52]
2567 * Exception_Handling:
2568 * 0x426a9b00 (0044): ldr r1, [r6, #84]
2569 * 0x426a9b02 (0046): blx r1
2570 * 0x426a9b04 (0048): .align4
2571 * -------- chaining cell (hot): 0x0021
2572 * 0x426a9b04 (0048): ldr r0, [r6, #92]
2573 * 0x426a9b06 (004a): blx r0
2574 * 0x426a9b08 (004c): data 0x7872(30834)
2575 * 0x426a9b0a (004e): data 0x428b(17035)
2576 * 0x426a9b0c (0050): .align4
2577 * -------- chaining cell (predicted)
2578 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
2579 * 0x426a9b0e (0052): data 0x0000(0)
2580 * 0x426a9b10 (0054): data 0x0000(0) --> class
2581 * 0x426a9b12 (0056): data 0x0000(0)
2582 * 0x426a9b14 (0058): data 0x0000(0) --> method
2583 * 0x426a9b16 (005a): data 0x0000(0)
2584 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
2585 * 0x426a9b1a (005e): data 0x0000(0)
2586 * 0x426a9b28 (006c): .word (0xad0392a5)
2587 * 0x426a9b2c (0070): .word (0x6e750)
2588 * 0x426a9b30 (0074): .word (0x4109a618)
2589 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002590 */
2591 case OP_INVOKE_INTERFACE:
2592 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002593 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002594 int methodIndex = dInsn->vB;
2595
2596 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2597 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2598 else
2599 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2600
Ben Cheng38329f52009-07-07 14:19:20 -07002601 /* "this" is already left in r0 by genProcessArgs* */
2602
2603 /* r4PC = dalvikCallsite */
2604 loadConstant(cUnit, r4PC,
2605 (int) (cUnit->method->insns + mir->offset));
2606
2607 /* r1 = &retChainingCell */
Ben Cheng3f02aa42009-08-14 13:52:09 -07002608 ArmLIR *addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL, r1, 0, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002609 addrRetChain->generic.target = (LIR *) retChainingCell;
2610
2611 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002612 ArmLIR *predictedChainingCell =
Ben Cheng3f02aa42009-08-14 13:52:09 -07002613 newLIR3(cUnit, THUMB_ADD_PC_REL, r2, 0, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002614 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2615
2616 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2617
2618 /* return through lr - jump to the chaining cell */
2619 genUnconditionalBranch(cUnit, predChainingCell);
2620
2621 /*
2622 * null-check on "this" may have been eliminated, but we still need
2623 * a PC-reconstruction label for stack overflow bailout.
2624 */
2625 if (pcrLabel == NULL) {
2626 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002627 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
2628 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07002629 pcrLabel->operands[0] = dPC;
2630 pcrLabel->operands[1] = mir->offset;
2631 /* Insert the place holder to the growable list */
2632 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2633 }
2634
2635 /* return through lr+2 - punt to the interpreter */
2636 genUnconditionalBranch(cUnit, pcrLabel);
2637
2638 /*
2639 * return through lr+4 - fully resolve the callee method.
2640 * r1 <- count
2641 * r2 <- &predictedChainCell
2642 * r3 <- this->class
2643 * r4 <- dPC
2644 * r7 <- this->class->vtable
2645 */
2646
2647 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002648 newLIR2(cUnit, THUMB_MOV_RR_L2H, r9 & THUMB_REG_MASK, r1);
2649 newLIR2(cUnit, THUMB_MOV_RR_L2H, r10 & THUMB_REG_MASK, r2);
2650 newLIR2(cUnit, THUMB_MOV_RR_L2H, r12 & THUMB_REG_MASK, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002651
Ben Chengba4fc8b2009-06-01 13:00:29 -07002652 /* r0 now contains this->clazz */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002653 newLIR2(cUnit, THUMB_MOV_RR, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002654
2655 /* r1 = BBBB */
2656 loadConstant(cUnit, r1, dInsn->vB);
2657
2658 /* r2 = method (caller) */
2659 loadConstant(cUnit, r2, (int) cUnit->method);
2660
2661 /* r3 = pDvmDex */
2662 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
2663
2664 loadConstant(cUnit, r7,
2665 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002666 newLIR1(cUnit, THUMB_BLX_R, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002667
2668 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
2669
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002670 newLIR2(cUnit, THUMB_MOV_RR_H2L, r1, r9 & THUMB_REG_MASK);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002671
Ben Cheng38329f52009-07-07 14:19:20 -07002672 /* Check if rechain limit is reached */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002673 newLIR2(cUnit, THUMB_CMP_RI8, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002674
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002675 ArmLIR *bypassRechaining =
2676 newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07002677
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002678 newLIR3(cUnit, THUMB_LDR_RRI5, r7, rGLUE,
Ben Cheng38329f52009-07-07 14:19:20 -07002679 offsetof(InterpState,
2680 jitToInterpEntries.dvmJitToPatchPredictedChain)
2681 >> 2);
2682
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002683 newLIR2(cUnit, THUMB_MOV_RR_H2L, r2, r10 & THUMB_REG_MASK);
2684 newLIR2(cUnit, THUMB_MOV_RR_H2L, r3, r12 & THUMB_REG_MASK);
Ben Cheng38329f52009-07-07 14:19:20 -07002685
2686 /*
2687 * r0 = calleeMethod
2688 * r2 = &predictedChainingCell
2689 * r3 = class
2690 *
2691 * &returnChainingCell has been loaded into r1 but is not needed
2692 * when patching the chaining cell and will be clobbered upon
2693 * returning so it will be reconstructed again.
2694 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002695 newLIR1(cUnit, THUMB_BLX_R, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002696
2697 /* r1 = &retChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002698 addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL,
Ben Cheng38329f52009-07-07 14:19:20 -07002699 r1, 0, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002700 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07002701
2702 bypassRechaining->generic.target = (LIR *) addrRetChain;
2703
Ben Chengba4fc8b2009-06-01 13:00:29 -07002704 /*
2705 * r0 = this, r1 = calleeMethod,
2706 * r1 = &ChainingCell,
2707 * r4PC = callsiteDPC,
2708 */
2709 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2710#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07002711 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002712#endif
2713 /* Handle exceptions using the interpreter */
2714 genTrap(cUnit, mir->offset, pcrLabel);
2715 break;
2716 }
2717 /* NOP */
2718 case OP_INVOKE_DIRECT_EMPTY: {
2719 return false;
2720 }
2721 case OP_FILLED_NEW_ARRAY:
2722 case OP_FILLED_NEW_ARRAY_RANGE: {
2723 /* Just let the interpreter deal with these */
2724 genInterpSingleStep(cUnit, mir);
2725 break;
2726 }
2727 default:
2728 return true;
2729 }
2730 return false;
2731}
2732
2733static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002734 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002735{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002736 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
2737 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2738 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002739
2740 DecodedInstruction *dInsn = &mir->dalvikInsn;
2741 switch (mir->dalvikInsn.opCode) {
2742 /* calleeMethod = this->clazz->vtable[BBBB] */
2743 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
2744 case OP_INVOKE_VIRTUAL_QUICK: {
2745 int methodIndex = dInsn->vB;
2746 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
2747 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2748 else
2749 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2750
Ben Cheng38329f52009-07-07 14:19:20 -07002751 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2752 retChainingCell,
2753 predChainingCell,
2754 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002755 break;
2756 }
2757 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2758 case OP_INVOKE_SUPER_QUICK:
2759 case OP_INVOKE_SUPER_QUICK_RANGE: {
2760 const Method *calleeMethod =
2761 cUnit->method->clazz->super->vtable[dInsn->vB];
2762
2763 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
2764 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2765 else
2766 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2767
2768 /* r0 = calleeMethod */
2769 loadConstant(cUnit, r0, (int) calleeMethod);
2770
Ben Cheng38329f52009-07-07 14:19:20 -07002771 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2772 calleeMethod);
2773 /* Handle exceptions using the interpreter */
2774 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002775 break;
2776 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002777 default:
2778 return true;
2779 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002780 return false;
2781}
2782
2783/*
2784 * NOTE: We assume here that the special native inline routines
2785 * are side-effect free. By making this assumption, we can safely
2786 * re-execute the routine from the interpreter if it decides it
2787 * wants to throw an exception. We still need to EXPORT_PC(), though.
2788 */
2789static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
2790{
2791 DecodedInstruction *dInsn = &mir->dalvikInsn;
2792 switch( mir->dalvikInsn.opCode) {
2793 case OP_EXECUTE_INLINE: {
2794 unsigned int i;
2795 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002796 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002797 int operation = dInsn->vB;
2798
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002799 switch (operation) {
2800 case INLINE_EMPTYINLINEMETHOD:
2801 return false; /* Nop */
2802 case INLINE_STRING_LENGTH:
2803 return genInlinedStringLength(cUnit, mir);
2804 case INLINE_MATH_ABS_INT:
2805 return genInlinedAbsInt(cUnit, mir);
2806 case INLINE_MATH_ABS_LONG:
2807 return genInlinedAbsLong(cUnit, mir);
2808 case INLINE_MATH_MIN_INT:
2809 return genInlinedMinMaxInt(cUnit, mir, true);
2810 case INLINE_MATH_MAX_INT:
2811 return genInlinedMinMaxInt(cUnit, mir, false);
2812 case INLINE_STRING_CHARAT:
2813 return genInlinedStringCharAt(cUnit, mir);
2814 case INLINE_MATH_SQRT:
2815 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07002816 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002817 else
2818 break; /* Handle with C routine */
2819 case INLINE_MATH_COS:
2820 if (genInlineCos(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07002821 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002822 else
2823 break; /* Handle with C routine */
2824 case INLINE_MATH_SIN:
2825 if (genInlineSin(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07002826 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002827 else
2828 break; /* Handle with C routine */
2829 case INLINE_MATH_ABS_FLOAT:
2830 return genInlinedAbsFloat(cUnit, mir);
2831 case INLINE_MATH_ABS_DOUBLE:
2832 return genInlinedAbsDouble(cUnit, mir);
2833 case INLINE_STRING_COMPARETO:
2834 case INLINE_STRING_EQUALS:
2835 break;
2836 default:
2837 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07002838 }
2839
2840 /* Materialize pointer to retval & push */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002841 newLIR2(cUnit, THUMB_MOV_RR, r4PC, rGLUE);
2842 newLIR2(cUnit, THUMB_ADD_RI8, r4PC, offset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002843 /* Push r4 and (just to take up space) r5) */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002844 newLIR1(cUnit, THUMB_PUSH, (1<<r4PC | 1<<rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002845
2846 /* Get code pointer to inline routine */
2847 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
2848
2849 /* Export PC */
2850 genExportPC(cUnit, mir, r0, r1 );
2851
2852 /* Load arguments to r0 through r3 as applicable */
2853 for (i=0; i < dInsn->vA; i++) {
2854 loadValue(cUnit, dInsn->arg[i], i);
2855 }
2856 /* Call inline routine */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002857 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002858
2859 /* Strip frame */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002860 newLIR1(cUnit, THUMB_ADD_SPI7, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002861
2862 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07002863 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002864
Ben Chenge9695e52009-06-16 16:11:47 -07002865 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002866 break;
2867 }
2868 default:
2869 return true;
2870 }
2871 return false;
2872}
2873
2874static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
2875{
2876 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
2877 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
2878 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2879 return false;
2880}
2881
2882/*****************************************************************************/
2883/*
2884 * The following are special processing routines that handle transfer of
2885 * controls between compiled code and the interpreter. Certain VM states like
2886 * Dalvik PC and special-purpose registers are reconstructed here.
2887 */
2888
Ben Cheng1efc9c52009-06-08 18:25:27 -07002889/* Chaining cell for code that may need warmup. */
2890static void handleNormalChainingCell(CompilationUnit *cUnit,
2891 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002892{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002893 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002894 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002895 newLIR1(cUnit, THUMB_BLX_R, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002896 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
2897}
2898
2899/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07002900 * Chaining cell for instructions that immediately following already translated
2901 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07002902 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07002903static void handleHotChainingCell(CompilationUnit *cUnit,
2904 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002905{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002906 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002907 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002908 newLIR1(cUnit, THUMB_BLX_R, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002909 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
2910}
2911
2912/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07002913static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
2914 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002915{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002916 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002917 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002918 newLIR1(cUnit, THUMB_BLX_R, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002919 addWordData(cUnit, (int) (callee->insns), true);
2920}
2921
Ben Cheng38329f52009-07-07 14:19:20 -07002922/* Chaining cell for monomorphic method invocations. */
2923static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
2924{
2925
2926 /* Should not be executed in the initial state */
2927 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
2928 /* To be filled: class */
2929 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
2930 /* To be filled: method */
2931 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
2932 /*
2933 * Rechain count. The initial value of 0 here will trigger chaining upon
2934 * the first invocation of this callsite.
2935 */
2936 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
2937}
2938
Ben Chengba4fc8b2009-06-01 13:00:29 -07002939/* Load the Dalvik PC into r0 and jump to the specified target */
2940static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002941 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002942{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002943 ArmLIR **pcrLabel =
2944 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002945 int numElems = cUnit->pcReconstructionList.numUsed;
2946 int i;
2947 for (i = 0; i < numElems; i++) {
2948 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
2949 /* r0 = dalvik PC */
2950 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
2951 genUnconditionalBranch(cUnit, targetLabel);
2952 }
2953}
2954
2955/* Entry function to invoke the backend of the JIT compiler */
2956void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
2957{
2958 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002959 ArmLIR *labelList =
2960 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002961 GrowableList chainingListByType[CHAINING_CELL_LAST];
2962 int i;
2963
2964 /*
Ben Cheng38329f52009-07-07 14:19:20 -07002965 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07002966 */
2967 for (i = 0; i < CHAINING_CELL_LAST; i++) {
2968 dvmInitGrowableList(&chainingListByType[i], 2);
2969 }
2970
2971 BasicBlock **blockList = cUnit->blockList;
2972
Bill Buzbee6e963e12009-06-17 16:56:19 -07002973 if (cUnit->executionCount) {
2974 /*
2975 * Reserve 6 bytes at the beginning of the trace
2976 * +----------------------------+
2977 * | execution count (4 bytes) |
2978 * +----------------------------+
2979 * | chain cell offset (2 bytes)|
2980 * +----------------------------+
2981 * ...and then code to increment the execution
2982 * count:
2983 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
2984 * sub r0, #10 @ back up to addr of executionCount
2985 * ldr r1, [r0]
2986 * add r1, #1
2987 * str r1, [r0]
2988 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002989 newLIR1(cUnit, ARM_16BIT_DATA, 0);
2990 newLIR1(cUnit, ARM_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07002991 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002992 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07002993 cUnit->headerSize = 6;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002994 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc & THUMB_REG_MASK);
2995 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
2996 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
2997 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
2998 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07002999 } else {
3000 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003001 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003002 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003003 cUnit->headerSize = 2;
3004 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003005
Ben Chengba4fc8b2009-06-01 13:00:29 -07003006 /* Handle the content in each basic block */
3007 for (i = 0; i < cUnit->numBlocks; i++) {
3008 blockList[i]->visited = true;
3009 MIR *mir;
3010
3011 labelList[i].operands[0] = blockList[i]->startOffset;
3012
3013 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3014 /*
3015 * Append the label pseudo LIR first. Chaining cells will be handled
3016 * separately afterwards.
3017 */
3018 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3019 }
3020
3021 if (blockList[i]->blockType == DALVIK_BYTECODE) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003022 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003023 /* Reset the register state */
3024 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003025 } else {
3026 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003027 case CHAINING_CELL_NORMAL:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003028 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003029 /* handle the codegen later */
3030 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003031 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003032 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003033 case CHAINING_CELL_INVOKE_SINGLETON:
3034 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003035 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003036 labelList[i].operands[0] =
3037 (int) blockList[i]->containingMethod;
3038 /* handle the codegen later */
3039 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003040 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3041 (void *) i);
3042 break;
3043 case CHAINING_CELL_INVOKE_PREDICTED:
3044 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003045 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
Ben Cheng38329f52009-07-07 14:19:20 -07003046 /* handle the codegen later */
3047 dvmInsertGrowableList(
3048 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3049 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003050 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003051 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003052 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003053 ARM_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003054 /* handle the codegen later */
3055 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003056 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003057 (void *) i);
3058 break;
3059 case PC_RECONSTRUCTION:
3060 /* Make sure exception handling block is next */
3061 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003062 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003063 assert (i == cUnit->numBlocks - 2);
3064 handlePCReconstruction(cUnit, &labelList[i+1]);
3065 break;
3066 case EXCEPTION_HANDLING:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003067 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003068 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003069 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003070 offsetof(InterpState,
3071 jitToInterpEntries.dvmJitToInterpPunt)
3072 >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003073 newLIR1(cUnit, THUMB_BLX_R, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003074 }
3075 break;
3076 default:
3077 break;
3078 }
3079 continue;
3080 }
Ben Chenge9695e52009-06-16 16:11:47 -07003081
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003082 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003083
Ben Chengba4fc8b2009-06-01 13:00:29 -07003084 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
3085 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3086 InstructionFormat dalvikFormat =
3087 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003088 ArmLIR *boundaryLIR =
3089 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
Ben Chenge9695e52009-06-16 16:11:47 -07003090 mir->offset,dalvikOpCode);
3091 /* Remember the first LIR for this block */
3092 if (headLIR == NULL) {
3093 headLIR = boundaryLIR;
3094 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003095 bool notHandled;
3096 /*
3097 * Debugging: screen the opcode first to see if it is in the
3098 * do[-not]-compile list
3099 */
3100 bool singleStepMe =
3101 gDvmJit.includeSelectedOp !=
3102 ((gDvmJit.opList[dalvikOpCode >> 3] &
3103 (1 << (dalvikOpCode & 0x7))) !=
3104 0);
3105 if (singleStepMe || cUnit->allSingleStep) {
3106 notHandled = false;
3107 genInterpSingleStep(cUnit, mir);
3108 } else {
3109 opcodeCoverage[dalvikOpCode]++;
3110 switch (dalvikFormat) {
3111 case kFmt10t:
3112 case kFmt20t:
3113 case kFmt30t:
3114 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3115 mir, blockList[i], labelList);
3116 break;
3117 case kFmt10x:
3118 notHandled = handleFmt10x(cUnit, mir);
3119 break;
3120 case kFmt11n:
3121 case kFmt31i:
3122 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3123 break;
3124 case kFmt11x:
3125 notHandled = handleFmt11x(cUnit, mir);
3126 break;
3127 case kFmt12x:
3128 notHandled = handleFmt12x(cUnit, mir);
3129 break;
3130 case kFmt20bc:
3131 notHandled = handleFmt20bc(cUnit, mir);
3132 break;
3133 case kFmt21c:
3134 case kFmt31c:
3135 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3136 break;
3137 case kFmt21h:
3138 notHandled = handleFmt21h(cUnit, mir);
3139 break;
3140 case kFmt21s:
3141 notHandled = handleFmt21s(cUnit, mir);
3142 break;
3143 case kFmt21t:
3144 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3145 labelList);
3146 break;
3147 case kFmt22b:
3148 case kFmt22s:
3149 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3150 break;
3151 case kFmt22c:
3152 notHandled = handleFmt22c(cUnit, mir);
3153 break;
3154 case kFmt22cs:
3155 notHandled = handleFmt22cs(cUnit, mir);
3156 break;
3157 case kFmt22t:
3158 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3159 labelList);
3160 break;
3161 case kFmt22x:
3162 case kFmt32x:
3163 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3164 break;
3165 case kFmt23x:
3166 notHandled = handleFmt23x(cUnit, mir);
3167 break;
3168 case kFmt31t:
3169 notHandled = handleFmt31t(cUnit, mir);
3170 break;
3171 case kFmt3rc:
3172 case kFmt35c:
3173 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3174 labelList);
3175 break;
3176 case kFmt3rms:
3177 case kFmt35ms:
3178 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3179 labelList);
3180 break;
3181 case kFmt3inline:
3182 notHandled = handleFmt3inline(cUnit, mir);
3183 break;
3184 case kFmt51l:
3185 notHandled = handleFmt51l(cUnit, mir);
3186 break;
3187 default:
3188 notHandled = true;
3189 break;
3190 }
3191 }
3192 if (notHandled) {
3193 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3194 mir->offset,
3195 dalvikOpCode, getOpcodeName(dalvikOpCode),
3196 dalvikFormat);
3197 dvmAbort();
3198 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003199 }
3200 }
Ben Chenge9695e52009-06-16 16:11:47 -07003201 /* Eliminate redundant loads/stores and delay stores into later slots */
3202 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3203 cUnit->lastLIRInsn);
Ben Cheng1efc9c52009-06-08 18:25:27 -07003204 /*
3205 * Check if the block is terminated due to trace length constraint -
3206 * insert an unconditional branch to the chaining cell.
3207 */
3208 if (blockList[i]->needFallThroughBranch) {
3209 genUnconditionalBranch(cUnit,
3210 &labelList[blockList[i]->fallThrough->id]);
3211 }
3212
Ben Chengba4fc8b2009-06-01 13:00:29 -07003213 }
3214
Ben Chenge9695e52009-06-16 16:11:47 -07003215 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003216 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3217 size_t j;
3218 int *blockIdList = (int *) chainingListByType[i].elemList;
3219
3220 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3221
3222 /* No chaining cells of this type */
3223 if (cUnit->numChainingCells[i] == 0)
3224 continue;
3225
3226 /* Record the first LIR for a new type of chaining cell */
3227 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3228
3229 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3230 int blockId = blockIdList[j];
3231
3232 /* Align this chaining cell first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003233 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003234
3235 /* Insert the pseudo chaining instruction */
3236 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3237
3238
3239 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003240 case CHAINING_CELL_NORMAL:
3241 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003242 blockList[blockId]->startOffset);
3243 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003244 case CHAINING_CELL_INVOKE_SINGLETON:
3245 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003246 blockList[blockId]->containingMethod);
3247 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003248 case CHAINING_CELL_INVOKE_PREDICTED:
3249 handleInvokePredictedChainingCell(cUnit);
3250 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003251 case CHAINING_CELL_HOT:
3252 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003253 blockList[blockId]->startOffset);
3254 break;
3255 default:
3256 dvmAbort();
3257 break;
3258 }
3259 }
3260 }
Ben Chenge9695e52009-06-16 16:11:47 -07003261
3262 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003263}
3264
3265/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07003266bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003267{
Bill Buzbee716f1202009-07-23 13:22:09 -07003268 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003269
3270 if (gDvmJit.codeCacheFull) {
Bill Buzbee716f1202009-07-23 13:22:09 -07003271 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003272 }
3273
3274 switch (work->kind) {
3275 case kWorkOrderMethod:
Bill Buzbee716f1202009-07-23 13:22:09 -07003276 res = dvmCompileMethod(work->info, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003277 break;
3278 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003279 /* Start compilation with maximally allowed trace length */
Bill Buzbee716f1202009-07-23 13:22:09 -07003280 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003281 break;
3282 default:
Bill Buzbee716f1202009-07-23 13:22:09 -07003283 res = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003284 dvmAbort();
3285 }
3286 return res;
3287}
3288
Ben Chengba4fc8b2009-06-01 13:00:29 -07003289/* Architectural-specific debugging helpers go here */
3290void dvmCompilerArchDump(void)
3291{
3292 /* Print compiled opcode in this VM instance */
3293 int i, start, streak;
3294 char buf[1024];
3295
3296 streak = i = 0;
3297 buf[0] = 0;
3298 while (opcodeCoverage[i] == 0 && i < 256) {
3299 i++;
3300 }
3301 if (i == 256) {
3302 return;
3303 }
3304 for (start = i++, streak = 1; i < 256; i++) {
3305 if (opcodeCoverage[i]) {
3306 streak++;
3307 } else {
3308 if (streak == 1) {
3309 sprintf(buf+strlen(buf), "%x,", start);
3310 } else {
3311 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3312 }
3313 streak = 0;
3314 while (opcodeCoverage[i] == 0 && i < 256) {
3315 i++;
3316 }
3317 if (i < 256) {
3318 streak = 1;
3319 start = i;
3320 }
3321 }
3322 }
3323 if (streak) {
3324 if (streak == 1) {
3325 sprintf(buf+strlen(buf), "%x", start);
3326 } else {
3327 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3328 }
3329 }
3330 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07003331 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003332 }
3333}