blob: 5b3f80210e8d898a0bf56ce6a00aa8c99d94f401 [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 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001157 ArmLIR *addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL,
Ben Cheng38329f52009-07-07 14:19:20 -07001158 r1, 0, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001159 /* r4PC = dalvikCallsite */
1160 loadConstant(cUnit, r4PC,
1161 (int) (cUnit->method->insns + mir->offset));
1162 addrRetChain->generic.target = (LIR *) retChainingCell;
1163 /*
Ben Cheng38329f52009-07-07 14:19:20 -07001164 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001165 * r1 = &ChainingCell
1166 * r4PC = callsiteDPC
1167 */
1168 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07001169 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001170#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07001171 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001172#endif
1173 } else {
1174 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1175#if defined(INVOKE_STATS)
1176 gDvmJit.invokeChain++;
1177#endif
Ben Cheng38329f52009-07-07 14:19:20 -07001178 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001179 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1180 }
1181 /* Handle exceptions using the interpreter */
1182 genTrap(cUnit, mir->offset, pcrLabel);
1183}
1184
Ben Cheng38329f52009-07-07 14:19:20 -07001185/*
1186 * Generate code to check the validity of a predicted chain and take actions
1187 * based on the result.
1188 *
1189 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1190 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1191 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1192 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1193 * 0x426a99b2 : blx_2 see above --+
1194 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1195 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1196 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1197 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1198 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1199 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1200 * 0x426a99c0 : blx r7 --+
1201 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1202 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1203 * 0x426a99c6 : blx_2 see above --+
1204 */
1205static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1206 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001207 ArmLIR *retChainingCell,
1208 ArmLIR *predChainingCell,
1209 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07001210{
1211 /* "this" is already left in r0 by genProcessArgs* */
1212
1213 /* r4PC = dalvikCallsite */
1214 loadConstant(cUnit, r4PC,
1215 (int) (cUnit->method->insns + mir->offset));
1216
1217 /* r1 = &retChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001218 ArmLIR *addrRetChain = newLIR2(cUnit, THUMB_ADD_PC_REL,
Ben Cheng38329f52009-07-07 14:19:20 -07001219 r1, 0);
1220 addrRetChain->generic.target = (LIR *) retChainingCell;
1221
1222 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001223 ArmLIR *predictedChainingCell =
1224 newLIR2(cUnit, THUMB_ADD_PC_REL, r2, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001225 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1226
1227 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1228
1229 /* return through lr - jump to the chaining cell */
1230 genUnconditionalBranch(cUnit, predChainingCell);
1231
1232 /*
1233 * null-check on "this" may have been eliminated, but we still need a PC-
1234 * reconstruction label for stack overflow bailout.
1235 */
1236 if (pcrLabel == NULL) {
1237 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001238 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1239 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07001240 pcrLabel->operands[0] = dPC;
1241 pcrLabel->operands[1] = mir->offset;
1242 /* Insert the place holder to the growable list */
1243 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1244 }
1245
1246 /* return through lr+2 - punt to the interpreter */
1247 genUnconditionalBranch(cUnit, pcrLabel);
1248
1249 /*
1250 * return through lr+4 - fully resolve the callee method.
1251 * r1 <- count
1252 * r2 <- &predictedChainCell
1253 * r3 <- this->class
1254 * r4 <- dPC
1255 * r7 <- this->class->vtable
1256 */
1257
1258 /* r0 <- calleeMethod */
1259 if (methodIndex < 32) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001260 newLIR3(cUnit, THUMB_LDR_RRI5, r0, r7, methodIndex);
Ben Cheng38329f52009-07-07 14:19:20 -07001261 } else {
1262 loadConstant(cUnit, r0, methodIndex<<2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001263 newLIR3(cUnit, THUMB_LDR_RRR, r0, r7, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001264 }
1265
1266 /* Check if rechain limit is reached */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001267 newLIR2(cUnit, THUMB_CMP_RI8, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001268
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001269 ArmLIR *bypassRechaining =
1270 newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07001271
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001272 newLIR3(cUnit, THUMB_LDR_RRI5, r7, rGLUE,
Ben Cheng38329f52009-07-07 14:19:20 -07001273 offsetof(InterpState,
1274 jitToInterpEntries.dvmJitToPatchPredictedChain)
1275 >> 2);
1276
1277 /*
1278 * r0 = calleeMethod
1279 * r2 = &predictedChainingCell
1280 * r3 = class
1281 *
1282 * &returnChainingCell has been loaded into r1 but is not needed
1283 * when patching the chaining cell and will be clobbered upon
1284 * returning so it will be reconstructed again.
1285 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001286 newLIR1(cUnit, THUMB_BLX_R, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001287
1288 /* r1 = &retChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001289 addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL, r1, 0, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001290 addrRetChain->generic.target = (LIR *) retChainingCell;
1291
1292 bypassRechaining->generic.target = (LIR *) addrRetChain;
1293 /*
1294 * r0 = calleeMethod,
1295 * r1 = &ChainingCell,
1296 * r4PC = callsiteDPC,
1297 */
1298 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1299#if defined(INVOKE_STATS)
1300 gDvmJit.invokePredictedChain++;
1301#endif
1302 /* Handle exceptions using the interpreter */
1303 genTrap(cUnit, mir->offset, pcrLabel);
1304}
1305
1306/*
1307 * Up calling this function, "this" is stored in r0. The actual class will be
1308 * chased down off r0 and the predicted one will be retrieved through
1309 * predictedChainingCell then a comparison is performed to see whether the
1310 * previously established chaining is still valid.
1311 *
1312 * The return LIR is a branch based on the comparison result. The actual branch
1313 * target will be setup in the caller.
1314 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001315static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1316 ArmLIR *predChainingCell,
1317 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07001318 MIR *mir)
1319{
1320 /* r3 now contains this->clazz */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001321 newLIR3(cUnit, THUMB_LDR_RRI5, r3, r0,
Ben Cheng38329f52009-07-07 14:19:20 -07001322 offsetof(Object, clazz) >> 2);
1323
1324 /*
1325 * r2 now contains predicted class. The starting offset of the
1326 * cached value is 4 bytes into the chaining cell.
1327 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001328 ArmLIR *getPredictedClass =
1329 newLIR3(cUnit, THUMB_LDR_PC_REL, r2, 0,
Ben Cheng38329f52009-07-07 14:19:20 -07001330 offsetof(PredictedChainingCell, clazz));
1331 getPredictedClass->generic.target = (LIR *) predChainingCell;
1332
1333 /*
1334 * r0 now contains predicted method. The starting offset of the
1335 * cached value is 8 bytes into the chaining cell.
1336 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001337 ArmLIR *getPredictedMethod =
1338 newLIR3(cUnit, THUMB_LDR_PC_REL, r0, 0,
Ben Cheng38329f52009-07-07 14:19:20 -07001339 offsetof(PredictedChainingCell, method));
1340 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1341
1342 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001343 ArmLIR *getRechainingRequestCount =
1344 newLIR3(cUnit, THUMB_LDR_PC_REL, r7, 0,
Ben Cheng38329f52009-07-07 14:19:20 -07001345 offsetof(PredictedChainingCell, counter));
1346 getRechainingRequestCount->generic.target =
1347 (LIR *) predChainingCell;
1348
1349 /* r4PC = dalvikCallsite */
1350 loadConstant(cUnit, r4PC,
1351 (int) (cUnit->method->insns + mir->offset));
1352
1353 /* r1 = &retChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001354 ArmLIR *addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL,
Ben Cheng38329f52009-07-07 14:19:20 -07001355 r1, 0, 0);
1356 addrRetChain->generic.target = (LIR *) retChainingCell;
1357
1358 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001359 newLIR2(cUnit, THUMB_CMP_RR, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001360
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001361 return newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_EQ);
Ben Cheng38329f52009-07-07 14:19:20 -07001362}
1363
Ben Chengba4fc8b2009-06-01 13:00:29 -07001364/* Geneate a branch to go back to the interpreter */
1365static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1366{
1367 /* r0 = dalvik pc */
1368 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001369 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001370 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpPunt) >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001371 newLIR1(cUnit, THUMB_BLX_R, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001372}
1373
1374/*
1375 * Attempt to single step one instruction using the interpreter and return
1376 * to the compiled code for the next Dalvik instruction
1377 */
1378static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1379{
1380 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1381 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1382 kInstrCanThrow;
1383 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1384 genPuntToInterp(cUnit, mir->offset);
1385 return;
1386 }
1387 int entryAddr = offsetof(InterpState,
1388 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001389 newLIR3(cUnit, THUMB_LDR_RRI5, r2, rGLUE, entryAddr >> 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001390 /* r0 = dalvik pc */
1391 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1392 /* r1 = dalvik pc of following instruction */
1393 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001394 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001395}
1396
1397
1398/*****************************************************************************/
1399/*
1400 * The following are the first-level codegen routines that analyze the format
1401 * of each bytecode then either dispatch special purpose codegen routines
1402 * or produce corresponding Thumb instructions directly.
1403 */
1404
1405static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001406 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001407{
1408 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1409 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1410 return false;
1411}
1412
1413static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1414{
1415 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1416 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1417 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
1418 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1419 return true;
1420 }
1421 switch (dalvikOpCode) {
1422 case OP_RETURN_VOID:
1423 genReturnCommon(cUnit,mir);
1424 break;
1425 case OP_UNUSED_73:
1426 case OP_UNUSED_79:
1427 case OP_UNUSED_7A:
1428 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1429 return true;
1430 case OP_NOP:
1431 break;
1432 default:
1433 return true;
1434 }
1435 return false;
1436}
1437
1438static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1439{
Ben Chenge9695e52009-06-16 16:11:47 -07001440 int reg0, reg1, reg2;
1441
Ben Chengba4fc8b2009-06-01 13:00:29 -07001442 switch (mir->dalvikInsn.opCode) {
1443 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07001444 case OP_CONST_4: {
1445 /* Avoid using the previously used register */
1446 reg0 = selectFirstRegister(cUnit, vNone, false);
1447 reg1 = NEXT_REG(reg0);
1448 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1449 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001450 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001451 }
1452 case OP_CONST_WIDE_32: {
1453 /* Avoid using the previously used register */
1454 reg0 = selectFirstRegister(cUnit, vNone, true);
1455 reg1 = NEXT_REG(reg0);
1456 reg2 = NEXT_REG(reg1);
1457 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001458 newLIR3(cUnit, THUMB_ASR, reg1, reg0, 31);
Ben Chenge9695e52009-06-16 16:11:47 -07001459 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001460 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001461 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001462 default:
1463 return true;
1464 }
1465 return false;
1466}
1467
1468static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1469{
Ben Chenge9695e52009-06-16 16:11:47 -07001470 int reg0, reg1, reg2;
1471
1472 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001473 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07001474 case OP_CONST_HIGH16: {
1475 reg0 = selectFirstRegister(cUnit, vNone, false);
1476 reg1 = NEXT_REG(reg0);
1477 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
1478 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001479 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001480 }
1481 case OP_CONST_WIDE_HIGH16: {
1482 reg0 = selectFirstRegister(cUnit, vNone, true);
1483 reg1 = NEXT_REG(reg0);
1484 reg2 = NEXT_REG(reg1);
1485 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
1486 loadConstant(cUnit, reg0, 0);
1487 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001488 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001489 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001490 default:
1491 return true;
1492 }
1493 return false;
1494}
1495
1496static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1497{
1498 /* For OP_THROW_VERIFICATION_ERROR */
1499 genInterpSingleStep(cUnit, mir);
1500 return false;
1501}
1502
1503static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1504{
Ben Chenge9695e52009-06-16 16:11:47 -07001505 /* Native register to use if the interested value is vA */
1506 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
1507 /* Native register to use if source is not from Dalvik registers */
1508 int regvNone = selectFirstRegister(cUnit, vNone, false);
1509 /* Similar to regvA but for 64-bit values */
1510 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
1511 /* Similar to regvNone but for 64-bit values */
1512 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
1513
Ben Chengba4fc8b2009-06-01 13:00:29 -07001514 switch (mir->dalvikInsn.opCode) {
1515 /*
1516 * TODO: Verify that we can ignore the resolution check here because
1517 * it will have already successfully been interpreted once
1518 */
1519 case OP_CONST_STRING_JUMBO:
1520 case OP_CONST_STRING: {
1521 void *strPtr = (void*)
1522 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1523 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001524 loadConstant(cUnit, regvNone, (int) strPtr );
1525 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001526 break;
1527 }
1528 /*
1529 * TODO: Verify that we can ignore the resolution check here because
1530 * it will have already successfully been interpreted once
1531 */
1532 case OP_CONST_CLASS: {
1533 void *classPtr = (void*)
1534 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1535 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001536 loadConstant(cUnit, regvNone, (int) classPtr );
1537 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001538 break;
1539 }
1540 case OP_SGET_OBJECT:
1541 case OP_SGET_BOOLEAN:
1542 case OP_SGET_CHAR:
1543 case OP_SGET_BYTE:
1544 case OP_SGET_SHORT:
1545 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001546 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001547 void *fieldPtr = (void*)
1548 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1549 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001550 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001551 newLIR3(cUnit, THUMB_LDR_RRI5, regvNone, regvNone, 0);
Ben Chenge9695e52009-06-16 16:11:47 -07001552 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001553 break;
1554 }
1555 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001556 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001557 void *fieldPtr = (void*)
1558 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001559 int reg0, reg1, reg2;
1560
Ben Chengba4fc8b2009-06-01 13:00:29 -07001561 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001562 reg0 = regvNoneWide;
1563 reg1 = NEXT_REG(reg0);
1564 reg2 = NEXT_REG(reg1);
1565 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001566 newLIR2(cUnit, THUMB_LDMIA, reg2, (1<<reg0 | 1<<reg1));
Ben Chenge9695e52009-06-16 16:11:47 -07001567 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001568 break;
1569 }
1570 case OP_SPUT_OBJECT:
1571 case OP_SPUT_BOOLEAN:
1572 case OP_SPUT_CHAR:
1573 case OP_SPUT_BYTE:
1574 case OP_SPUT_SHORT:
1575 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001576 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001577 void *fieldPtr = (void*)
1578 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001579
Ben Chengba4fc8b2009-06-01 13:00:29 -07001580 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001581 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
1582 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
1583 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001584 newLIR3(cUnit, THUMB_STR_RRI5, regvA, NEXT_REG(regvA), 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001585 break;
1586 }
1587 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001588 int reg0, reg1, reg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001589 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001590 void *fieldPtr = (void*)
1591 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001592
Ben Chengba4fc8b2009-06-01 13:00:29 -07001593 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001594 reg0 = regvAWide;
1595 reg1 = NEXT_REG(reg0);
1596 reg2 = NEXT_REG(reg1);
1597 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
1598 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
1599 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001600 newLIR2(cUnit, THUMB_STMIA, reg2, (1<<reg0 | 1<<reg1));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001601 break;
1602 }
1603 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001604 /*
1605 * Obey the calling convention and don't mess with the register
1606 * usage.
1607 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001608 ClassObject *classPtr = (void*)
1609 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1610 assert(classPtr != NULL);
1611 assert(classPtr->status & CLASS_INITIALIZED);
1612 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
1613 /* It's going to throw, just let the interp. deal with it. */
1614 genInterpSingleStep(cUnit, mir);
1615 return false;
1616 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001617 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07001618 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001619 genExportPC(cUnit, mir, r2, r3 );
1620 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001621 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001622 /*
1623 * TODO: As coded, we'll bail and reinterpret on alloc failure.
1624 * Need a general mechanism to bail to thrown exception code.
1625 */
Ben Chenge9695e52009-06-16 16:11:47 -07001626 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001627 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1628 break;
1629 }
1630 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07001631 /*
1632 * Obey the calling convention and don't mess with the register
1633 * usage.
1634 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001635 ClassObject *classPtr =
1636 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1637 loadConstant(cUnit, r1, (int) classPtr );
1638 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
1639 /*
1640 * TODO - in theory classPtr should be resoved by the time this
1641 * instruction made into a trace, but we are seeing NULL at runtime
1642 * so this check is temporarily used as a workaround.
1643 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001644 ArmLIR * pcrLabel = genZeroCheck(cUnit, r1, mir->offset, NULL);
1645 newLIR2(cUnit, THUMB_CMP_RI8, r0, 0); /* Null? */
1646 ArmLIR *branch1 =
1647 newLIR2(cUnit, THUMB_B_COND, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001648 /* r0 now contains object->clazz */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001649 newLIR3(cUnit, THUMB_LDR_RRI5, r0, r0,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001650 offsetof(Object, clazz) >> 2);
1651 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001652 newLIR2(cUnit, THUMB_CMP_RR, r0, r1);
1653 ArmLIR *branch2 =
1654 newLIR2(cUnit, THUMB_B_COND, 2, ARM_COND_EQ);
1655 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001656 /* check cast failed - punt to the interpreter */
Ben Chenge9695e52009-06-16 16:11:47 -07001657 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001658 /* check cast passed - branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001659 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001660 branch1->generic.target = (LIR *)target;
1661 branch2->generic.target = (LIR *)target;
1662 break;
1663 }
1664 default:
1665 return true;
1666 }
1667 return false;
1668}
1669
1670static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1671{
1672 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1673 switch (dalvikOpCode) {
1674 case OP_MOVE_EXCEPTION: {
1675 int offset = offsetof(InterpState, self);
1676 int exOffset = offsetof(Thread, exception);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001677 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE, offset >> 2);
1678 newLIR3(cUnit, THUMB_LDR_RRI5, r0, r1, exOffset >> 2);
Ben Chenge9695e52009-06-16 16:11:47 -07001679 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001680 break;
1681 }
1682 case OP_MOVE_RESULT:
1683 case OP_MOVE_RESULT_OBJECT: {
1684 int offset = offsetof(InterpState, retval);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001685 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE, offset >> 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001686 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1687 break;
1688 }
1689 case OP_MOVE_RESULT_WIDE: {
1690 int offset = offsetof(InterpState, retval);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001691 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE, offset >> 2);
1692 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE, (offset >> 2)+1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001693 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1694 break;
1695 }
1696 case OP_RETURN_WIDE: {
1697 loadValuePair(cUnit, mir->dalvikInsn.vA, r0, r1);
1698 int offset = offsetof(InterpState, retval);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001699 newLIR3(cUnit, THUMB_STR_RRI5, r0, rGLUE, offset >> 2);
1700 newLIR3(cUnit, THUMB_STR_RRI5, r1, rGLUE, (offset >> 2)+1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001701 genReturnCommon(cUnit,mir);
1702 break;
1703 }
1704 case OP_RETURN:
1705 case OP_RETURN_OBJECT: {
1706 loadValue(cUnit, mir->dalvikInsn.vA, r0);
1707 int offset = offsetof(InterpState, retval);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001708 newLIR3(cUnit, THUMB_STR_RRI5, r0, rGLUE, offset >> 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001709 genReturnCommon(cUnit,mir);
1710 break;
1711 }
1712 /*
1713 * TODO-VERIFY: May be playing a bit fast and loose here. As coded,
1714 * a failure on lock/unlock will cause us to revert to the interpeter
1715 * to try again. This means we essentially ignore the first failure on
1716 * the assumption that the interpreter will correctly handle the 2nd.
1717 */
1718 case OP_MONITOR_ENTER:
1719 case OP_MONITOR_EXIT: {
1720 int offset = offsetof(InterpState, self);
1721 loadValue(cUnit, mir->dalvikInsn.vA, r1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001722 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE, offset >> 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001723 if (dalvikOpCode == OP_MONITOR_ENTER) {
1724 loadConstant(cUnit, r2, (int)dvmLockObject);
1725 } else {
1726 loadConstant(cUnit, r2, (int)dvmUnlockObject);
1727 }
1728 /*
1729 * TODO-VERIFY: Note that we're not doing an EXPORT_PC, as
1730 * Lock/unlock won't throw, and this code does not support
1731 * DEADLOCK_PREDICTION or MONITOR_TRACKING. Should it?
1732 */
Ben Chenge9695e52009-06-16 16:11:47 -07001733 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001734 /* Do the call */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001735 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001736 break;
1737 }
1738 case OP_THROW: {
1739 genInterpSingleStep(cUnit, mir);
1740 break;
1741 }
1742 default:
1743 return true;
1744 }
1745 return false;
1746}
1747
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001748static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001749{
1750 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001751
Ben Chengba4fc8b2009-06-01 13:00:29 -07001752 float __aeabi_i2f( int op1 );
1753 int __aeabi_f2iz( float op1 );
1754 float __aeabi_d2f( double op1 );
1755 double __aeabi_f2d( float op1 );
1756 double __aeabi_i2d( int op1 );
1757 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07001758 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07001759 double __aeabi_l2d( long op1 );
1760
Bill Buzbeed45ba372009-06-15 17:00:57 -07001761 switch (opCode) {
1762 case OP_INT_TO_FLOAT:
1763 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
1764 case OP_FLOAT_TO_INT:
1765 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
1766 case OP_DOUBLE_TO_FLOAT:
1767 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
1768 case OP_FLOAT_TO_DOUBLE:
1769 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
1770 case OP_INT_TO_DOUBLE:
1771 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
1772 case OP_DOUBLE_TO_INT:
1773 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
1774 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001775 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07001776 case OP_LONG_TO_FLOAT:
1777 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
1778 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001779 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07001780 case OP_LONG_TO_DOUBLE:
1781 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
1782 default:
1783 return true;
1784 }
1785 return false;
1786}
1787
1788static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1789{
1790 OpCode opCode = mir->dalvikInsn.opCode;
1791 int vSrc1Dest = mir->dalvikInsn.vA;
1792 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07001793 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07001794
1795 /* TODO - find the proper include file to declare these */
1796
Ben Chengba4fc8b2009-06-01 13:00:29 -07001797 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1798 return genArithOp( cUnit, mir );
1799 }
1800
Ben Chenge9695e52009-06-16 16:11:47 -07001801 /*
1802 * If data type is 64-bit, re-calculate the register numbers in the
1803 * corresponding cases.
1804 */
1805 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1806 reg1 = NEXT_REG(reg0);
1807 reg2 = NEXT_REG(reg1);
1808
Ben Chengba4fc8b2009-06-01 13:00:29 -07001809 switch (opCode) {
1810 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001811 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001812 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001813 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001814 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001815 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001816 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001817 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001818 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001819 case OP_LONG_TO_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001820 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001821 case OP_NEG_INT:
1822 case OP_NOT_INT:
1823 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
1824 case OP_NEG_LONG:
1825 case OP_NOT_LONG:
1826 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
1827 case OP_NEG_FLOAT:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001828 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001829 case OP_NEG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001830 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07001831 case OP_MOVE_WIDE: {
1832 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1833 reg1 = NEXT_REG(reg0);
1834 reg2 = NEXT_REG(reg1);
1835
1836 loadValuePair(cUnit, vSrc2, reg0, reg1);
1837 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001838 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001839 }
1840 case OP_INT_TO_LONG: {
1841 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1842 reg1 = NEXT_REG(reg0);
1843 reg2 = NEXT_REG(reg1);
1844
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001845 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001846 newLIR3(cUnit, THUMB_ASR, reg1, reg0, 31);
Ben Chenge9695e52009-06-16 16:11:47 -07001847 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001848 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001849 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001850 case OP_MOVE:
1851 case OP_MOVE_OBJECT:
1852 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07001853 loadValue(cUnit, vSrc2, reg0);
1854 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001855 break;
1856 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07001857 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001858 newLIR3(cUnit, THUMB_LSL, reg0, reg0, 24);
1859 newLIR3(cUnit, THUMB_ASR, reg0, reg0, 24);
Ben Chenge9695e52009-06-16 16:11:47 -07001860 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001861 break;
1862 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07001863 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001864 newLIR3(cUnit, THUMB_LSL, reg0, reg0, 16);
1865 newLIR3(cUnit, THUMB_ASR, reg0, reg0, 16);
Ben Chenge9695e52009-06-16 16:11:47 -07001866 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001867 break;
1868 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07001869 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001870 newLIR3(cUnit, THUMB_LSL, reg0, reg0, 16);
1871 newLIR3(cUnit, THUMB_LSR, reg0, reg0, 16);
Ben Chenge9695e52009-06-16 16:11:47 -07001872 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001873 break;
1874 case OP_ARRAY_LENGTH: {
1875 int lenOffset = offsetof(ArrayObject, length);
Ben Chenge9695e52009-06-16 16:11:47 -07001876 loadValue(cUnit, vSrc2, reg0);
1877 genNullCheck(cUnit, vSrc2, reg0, mir->offset, NULL);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001878 newLIR3(cUnit, THUMB_LDR_RRI5, reg0, reg0, lenOffset >> 2);
Ben Chenge9695e52009-06-16 16:11:47 -07001879 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001880 break;
1881 }
1882 default:
1883 return true;
1884 }
1885 return false;
1886}
1887
1888static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
1889{
1890 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07001891 int reg0, reg1, reg2;
1892
Ben Chengba4fc8b2009-06-01 13:00:29 -07001893 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
1894 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07001895 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001896 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07001897
1898 reg0 = selectFirstRegister(cUnit, vNone, true);
1899 reg1 = NEXT_REG(reg0);
1900 reg2 = NEXT_REG(reg1);
1901
1902 loadConstant(cUnit, reg0, BBBB);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001903 newLIR3(cUnit, THUMB_ASR, reg1, reg0, 31);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001904
1905 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07001906 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001907 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07001908 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001909 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001910
Ben Chenge9695e52009-06-16 16:11:47 -07001911 reg0 = selectFirstRegister(cUnit, vNone, false);
1912 reg1 = NEXT_REG(reg0);
1913
1914 loadConstant(cUnit, reg0, BBBB);
1915 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001916 } else {
1917 return true;
1918 }
1919 return false;
1920}
1921
1922/* Compare agaist zero */
1923static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001924 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001925{
1926 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001927 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07001928 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001929
Ben Chenge9695e52009-06-16 16:11:47 -07001930 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001931 newLIR2(cUnit, THUMB_CMP_RI8, reg0, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001932
1933 switch (dalvikOpCode) {
1934 case OP_IF_EQZ:
1935 cond = ARM_COND_EQ;
1936 break;
1937 case OP_IF_NEZ:
1938 cond = ARM_COND_NE;
1939 break;
1940 case OP_IF_LTZ:
1941 cond = ARM_COND_LT;
1942 break;
1943 case OP_IF_GEZ:
1944 cond = ARM_COND_GE;
1945 break;
1946 case OP_IF_GTZ:
1947 cond = ARM_COND_GT;
1948 break;
1949 case OP_IF_LEZ:
1950 cond = ARM_COND_LE;
1951 break;
1952 default:
1953 cond = 0;
1954 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
1955 dvmAbort();
1956 }
1957 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1958 /* This mostly likely will be optimized away in a later phase */
1959 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1960 return false;
1961}
1962
1963static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
1964{
1965 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1966 int vSrc = mir->dalvikInsn.vB;
1967 int vDest = mir->dalvikInsn.vA;
1968 int lit = mir->dalvikInsn.vC;
1969 int armOp;
Ben Chenge9695e52009-06-16 16:11:47 -07001970 int reg0, reg1, regDest;
1971
1972 reg0 = selectFirstRegister(cUnit, vSrc, false);
1973 reg1 = NEXT_REG(reg0);
1974 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001975
1976 /* TODO: find the proper .h file to declare these */
1977 int __aeabi_idivmod(int op1, int op2);
1978 int __aeabi_idiv(int op1, int op2);
1979
1980 switch (dalvikOpCode) {
1981 case OP_ADD_INT_LIT8:
1982 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07001983 loadValue(cUnit, vSrc, reg0);
1984 if (lit <= 7 && lit >= 0) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001985 newLIR3(cUnit, THUMB_ADD_RRI3, regDest, reg0, lit);
Ben Chenge9695e52009-06-16 16:11:47 -07001986 storeValue(cUnit, regDest, vDest, reg1);
1987 } else if (lit <= 255 && lit >= 0) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001988 newLIR2(cUnit, THUMB_ADD_RI8, reg0, lit);
Ben Chenge9695e52009-06-16 16:11:47 -07001989 storeValue(cUnit, reg0, vDest, reg1);
1990 } else if (lit >= -7 && lit <= 0) {
1991 /* Convert to a small constant subtraction */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001992 newLIR3(cUnit, THUMB_SUB_RRI3, regDest, reg0, -lit);
Ben Chenge9695e52009-06-16 16:11:47 -07001993 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001994 } else if (lit >= -255 && lit <= 0) {
1995 /* Convert to a small constant subtraction */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001996 newLIR2(cUnit, THUMB_SUB_RI8, reg0, -lit);
Ben Chenge9695e52009-06-16 16:11:47 -07001997 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001998 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001999 loadConstant(cUnit, reg1, lit);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002000 genBinaryOp(cUnit, vDest, THUMB_ADD_RRR, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002001 }
2002 break;
2003
2004 case OP_RSUB_INT_LIT8:
2005 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002006 loadValue(cUnit, vSrc, reg1);
2007 loadConstant(cUnit, reg0, lit);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002008 genBinaryOp(cUnit, vDest, THUMB_SUB_RRR, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002009 break;
2010
2011 case OP_MUL_INT_LIT8:
2012 case OP_MUL_INT_LIT16:
2013 case OP_AND_INT_LIT8:
2014 case OP_AND_INT_LIT16:
2015 case OP_OR_INT_LIT8:
2016 case OP_OR_INT_LIT16:
2017 case OP_XOR_INT_LIT8:
2018 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002019 loadValue(cUnit, vSrc, reg0);
2020 loadConstant(cUnit, reg1, lit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002021 switch (dalvikOpCode) {
2022 case OP_MUL_INT_LIT8:
2023 case OP_MUL_INT_LIT16:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002024 armOp = THUMB_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002025 break;
2026 case OP_AND_INT_LIT8:
2027 case OP_AND_INT_LIT16:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002028 armOp = THUMB_AND_RR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002029 break;
2030 case OP_OR_INT_LIT8:
2031 case OP_OR_INT_LIT16:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002032 armOp = THUMB_ORR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002033 break;
2034 case OP_XOR_INT_LIT8:
2035 case OP_XOR_INT_LIT16:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002036 armOp = THUMB_EOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002037 break;
2038 default:
2039 dvmAbort();
2040 }
Ben Chenge9695e52009-06-16 16:11:47 -07002041 genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002042 break;
2043
2044 case OP_SHL_INT_LIT8:
2045 case OP_SHR_INT_LIT8:
2046 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002047 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002048 switch (dalvikOpCode) {
2049 case OP_SHL_INT_LIT8:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002050 armOp = THUMB_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002051 break;
2052 case OP_SHR_INT_LIT8:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002053 armOp = THUMB_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002054 break;
2055 case OP_USHR_INT_LIT8:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002056 armOp = THUMB_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002057 break;
2058 default: dvmAbort();
2059 }
Ben Chenge9695e52009-06-16 16:11:47 -07002060 newLIR3(cUnit, armOp, reg0, reg0, lit);
2061 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002062 break;
2063
2064 case OP_DIV_INT_LIT8:
2065 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002066 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002067 if (lit == 0) {
2068 /* Let the interpreter deal with div by 0 */
2069 genInterpSingleStep(cUnit, mir);
2070 return false;
2071 }
2072 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2073 loadConstant(cUnit, r1, lit);
2074 loadValue(cUnit, vSrc, r0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002075 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002076 storeValue(cUnit, r0, vDest, r2);
2077 break;
2078
2079 case OP_REM_INT_LIT8:
2080 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002081 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002082 if (lit == 0) {
2083 /* Let the interpreter deal with div by 0 */
2084 genInterpSingleStep(cUnit, mir);
2085 return false;
2086 }
2087 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2088 loadConstant(cUnit, r1, lit);
2089 loadValue(cUnit, vSrc, r0);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002090 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002091 storeValue(cUnit, r1, vDest, r2);
2092 break;
2093 default:
2094 return true;
2095 }
2096 return false;
2097}
2098
2099static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2100{
2101 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2102 int fieldOffset;
2103
2104 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2105 InstField *pInstField = (InstField *)
2106 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2107 int fieldOffset;
2108
2109 assert(pInstField != NULL);
2110 fieldOffset = pInstField->byteOffset;
2111 } else {
2112 /* To make the compiler happy */
2113 fieldOffset = 0;
2114 }
2115 switch (dalvikOpCode) {
2116 /*
2117 * TODO: I may be assuming too much here.
2118 * Verify what is known at JIT time.
2119 */
2120 case OP_NEW_ARRAY: {
2121 void *classPtr = (void*)
2122 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2123 assert(classPtr != NULL);
2124 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2125 loadConstant(cUnit, r0, (int) classPtr );
2126 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002127 ArmLIR *pcrLabel =
Ben Chengba4fc8b2009-06-01 13:00:29 -07002128 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2129 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002130 newLIR2(cUnit, THUMB_MOV_IMM,r2,ALLOC_DONT_TRACK);
2131 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002132 /*
2133 * TODO: As coded, we'll bail and reinterpret on alloc failure.
2134 * Need a general mechanism to bail to thrown exception code.
2135 */
Ben Chenge9695e52009-06-16 16:11:47 -07002136 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002137 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2138 break;
2139 }
2140 /*
2141 * TODO: I may be assuming too much here.
2142 * Verify what is known at JIT time.
2143 */
2144 case OP_INSTANCE_OF: {
2145 ClassObject *classPtr =
2146 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2147 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002148 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002149 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002150 newLIR2(cUnit, THUMB_CMP_RI8, r0, 0); /* Null? */
Ben Cheng752c7942009-06-22 10:50:07 -07002151 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002152 ArmLIR *branch1 = newLIR2(cUnit, THUMB_B_COND, 4,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002153 ARM_COND_EQ);
2154 /* r1 now contains object->clazz */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002155 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002156 offsetof(Object, clazz) >> 2);
2157 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002158 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002159 newLIR2(cUnit, THUMB_CMP_RR, r1, r2);
2160 ArmLIR *branch2 = newLIR2(cUnit, THUMB_B_COND, 2,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002161 ARM_COND_EQ);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002162 newLIR2(cUnit, THUMB_MOV_RR, r0, r1);
2163 newLIR2(cUnit, THUMB_MOV_RR, r1, r2);
2164 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002165 /* branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002166 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002167 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2168 branch1->generic.target = (LIR *)target;
2169 branch2->generic.target = (LIR *)target;
2170 break;
2171 }
2172 case OP_IGET_WIDE:
2173 genIGetWide(cUnit, mir, fieldOffset);
2174 break;
2175 case OP_IGET:
2176 case OP_IGET_OBJECT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002177 genIGet(cUnit, mir, THUMB_LDR_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002178 break;
2179 case OP_IGET_BOOLEAN:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002180 genIGet(cUnit, mir, THUMB_LDRB_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002181 break;
2182 case OP_IGET_BYTE:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002183 genIGet(cUnit, mir, THUMB_LDRSB_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002184 break;
2185 case OP_IGET_CHAR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002186 genIGet(cUnit, mir, THUMB_LDRH_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002187 break;
2188 case OP_IGET_SHORT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002189 genIGet(cUnit, mir, THUMB_LDRSH_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002190 break;
2191 case OP_IPUT_WIDE:
2192 genIPutWide(cUnit, mir, fieldOffset);
2193 break;
2194 case OP_IPUT:
2195 case OP_IPUT_OBJECT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002196 genIPut(cUnit, mir, THUMB_STR_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002197 break;
2198 case OP_IPUT_SHORT:
2199 case OP_IPUT_CHAR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002200 genIPut(cUnit, mir, THUMB_STRH_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002201 break;
2202 case OP_IPUT_BYTE:
2203 case OP_IPUT_BOOLEAN:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002204 genIPut(cUnit, mir, THUMB_STRB_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002205 break;
2206 default:
2207 return true;
2208 }
2209 return false;
2210}
2211
2212static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2213{
2214 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2215 int fieldOffset = mir->dalvikInsn.vC;
2216 switch (dalvikOpCode) {
2217 case OP_IGET_QUICK:
2218 case OP_IGET_OBJECT_QUICK:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002219 genIGet(cUnit, mir, THUMB_LDR_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002220 break;
2221 case OP_IPUT_QUICK:
2222 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002223 genIPut(cUnit, mir, THUMB_STR_RRR, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002224 break;
2225 case OP_IGET_WIDE_QUICK:
2226 genIGetWide(cUnit, mir, fieldOffset);
2227 break;
2228 case OP_IPUT_WIDE_QUICK:
2229 genIPutWide(cUnit, mir, fieldOffset);
2230 break;
2231 default:
2232 return true;
2233 }
2234 return false;
2235
2236}
2237
2238/* Compare agaist zero */
2239static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002240 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002241{
2242 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002243 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002244 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002245
Ben Chenge9695e52009-06-16 16:11:47 -07002246 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2247 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2248 reg1 = NEXT_REG(reg0);
2249 /* Load vB first since vA can be fetched via a move */
2250 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2251 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2252 } else {
2253 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2254 reg1 = NEXT_REG(reg0);
2255 /* Load vA first since vB can be fetched via a move */
2256 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2257 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2258 }
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002259 newLIR2(cUnit, THUMB_CMP_RR, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002260
2261 switch (dalvikOpCode) {
2262 case OP_IF_EQ:
2263 cond = ARM_COND_EQ;
2264 break;
2265 case OP_IF_NE:
2266 cond = ARM_COND_NE;
2267 break;
2268 case OP_IF_LT:
2269 cond = ARM_COND_LT;
2270 break;
2271 case OP_IF_GE:
2272 cond = ARM_COND_GE;
2273 break;
2274 case OP_IF_GT:
2275 cond = ARM_COND_GT;
2276 break;
2277 case OP_IF_LE:
2278 cond = ARM_COND_LE;
2279 break;
2280 default:
2281 cond = 0;
2282 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2283 dvmAbort();
2284 }
2285 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2286 /* This mostly likely will be optimized away in a later phase */
2287 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2288 return false;
2289}
2290
2291static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2292{
2293 OpCode opCode = mir->dalvikInsn.opCode;
2294 int vSrc1Dest = mir->dalvikInsn.vA;
2295 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002296 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002297
2298 switch (opCode) {
2299 case OP_MOVE_16:
2300 case OP_MOVE_OBJECT_16:
2301 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002302 case OP_MOVE_OBJECT_FROM16: {
2303 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2304 reg1 = NEXT_REG(reg0);
2305 loadValue(cUnit, vSrc2, reg0);
2306 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002307 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002308 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002309 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002310 case OP_MOVE_WIDE_FROM16: {
2311 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2312 reg1 = NEXT_REG(reg0);
2313 reg2 = NEXT_REG(reg1);
2314 loadValuePair(cUnit, vSrc2, reg0, reg1);
2315 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002316 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002317 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002318 default:
2319 return true;
2320 }
2321 return false;
2322}
2323
2324static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2325{
2326 OpCode opCode = mir->dalvikInsn.opCode;
2327 int vA = mir->dalvikInsn.vA;
2328 int vB = mir->dalvikInsn.vB;
2329 int vC = mir->dalvikInsn.vC;
2330
Ben Chenge9695e52009-06-16 16:11:47 -07002331 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002332 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2333 return genArithOp( cUnit, mir );
2334 }
2335
2336 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002337 case OP_CMPL_FLOAT:
2338 case OP_CMPG_FLOAT:
2339 case OP_CMPL_DOUBLE:
2340 case OP_CMPG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002341 return genCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002342 case OP_CMP_LONG:
2343 loadValuePair(cUnit,vB, r0, r1);
2344 loadValuePair(cUnit, vC, r2, r3);
2345 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
2346 storeValue(cUnit, r0, vA, r1);
2347 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002348 case OP_AGET_WIDE:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002349 genArrayGet(cUnit, mir, THUMB_LDR_RRR, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002350 break;
2351 case OP_AGET:
2352 case OP_AGET_OBJECT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002353 genArrayGet(cUnit, mir, THUMB_LDR_RRR, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002354 break;
2355 case OP_AGET_BOOLEAN:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002356 genArrayGet(cUnit, mir, THUMB_LDRB_RRR, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002357 break;
2358 case OP_AGET_BYTE:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002359 genArrayGet(cUnit, mir, THUMB_LDRSB_RRR, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002360 break;
2361 case OP_AGET_CHAR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002362 genArrayGet(cUnit, mir, THUMB_LDRH_RRR, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002363 break;
2364 case OP_AGET_SHORT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002365 genArrayGet(cUnit, mir, THUMB_LDRSH_RRR, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002366 break;
2367 case OP_APUT_WIDE:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002368 genArrayPut(cUnit, mir, THUMB_STR_RRR, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002369 break;
2370 case OP_APUT:
2371 case OP_APUT_OBJECT:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002372 genArrayPut(cUnit, mir, THUMB_STR_RRR, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002373 break;
2374 case OP_APUT_SHORT:
2375 case OP_APUT_CHAR:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002376 genArrayPut(cUnit, mir, THUMB_STRH_RRR, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002377 break;
2378 case OP_APUT_BYTE:
2379 case OP_APUT_BOOLEAN:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002380 genArrayPut(cUnit, mir, THUMB_STRB_RRR, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002381 break;
2382 default:
2383 return true;
2384 }
2385 return false;
2386}
2387
2388static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2389{
2390 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2391 switch (dalvikOpCode) {
2392 case OP_FILL_ARRAY_DATA: {
2393 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2394 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2395 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2396 (int) (cUnit->method->insns + mir->offset));
2397 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002398 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002399 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002400 break;
2401 }
2402 /*
2403 * TODO
2404 * - Add a 1 to 3-entry per-location cache here to completely
2405 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2406 * - Use out-of-line handlers for both of these
2407 */
2408 case OP_PACKED_SWITCH:
2409 case OP_SPARSE_SWITCH: {
2410 if (dalvikOpCode == OP_PACKED_SWITCH) {
2411 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2412 } else {
2413 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2414 }
2415 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2416 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2417 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002418 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002419 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002420 newLIR3(cUnit, THUMB_LDR_RRI5, r2, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002421 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNoChain)
2422 >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002423 newLIR3(cUnit, THUMB_ADD_RRR, r0, r0, r0);
2424 newLIR3(cUnit, THUMB_ADD_RRR, r4PC, r0, r1);
2425 newLIR1(cUnit, THUMB_BLX_R, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002426 break;
2427 }
2428 default:
2429 return true;
2430 }
2431 return false;
2432}
2433
2434static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002435 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002436{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07002437 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002438 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002439
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07002440 if (bb->fallThrough != NULL)
2441 retChainingCell = &labelList[bb->fallThrough->id];
2442
Ben Chengba4fc8b2009-06-01 13:00:29 -07002443 DecodedInstruction *dInsn = &mir->dalvikInsn;
2444 switch (mir->dalvikInsn.opCode) {
2445 /*
2446 * calleeMethod = this->clazz->vtable[
2447 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2448 * ]
2449 */
2450 case OP_INVOKE_VIRTUAL:
2451 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002452 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002453 int methodIndex =
2454 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2455 methodIndex;
2456
2457 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2458 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2459 else
2460 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2461
Ben Cheng38329f52009-07-07 14:19:20 -07002462 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2463 retChainingCell,
2464 predChainingCell,
2465 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002466 break;
2467 }
2468 /*
2469 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2470 * ->pResMethods[BBBB]->methodIndex]
2471 */
2472 /* TODO - not excersized in RunPerf.jar */
2473 case OP_INVOKE_SUPER:
2474 case OP_INVOKE_SUPER_RANGE: {
2475 int mIndex = cUnit->method->clazz->pDvmDex->
2476 pResMethods[dInsn->vB]->methodIndex;
2477 const Method *calleeMethod =
2478 cUnit->method->clazz->super->vtable[mIndex];
2479
2480 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2481 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2482 else
2483 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2484
2485 /* r0 = calleeMethod */
2486 loadConstant(cUnit, r0, (int) calleeMethod);
2487
Ben Cheng38329f52009-07-07 14:19:20 -07002488 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2489 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002490 break;
2491 }
2492 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2493 case OP_INVOKE_DIRECT:
2494 case OP_INVOKE_DIRECT_RANGE: {
2495 const Method *calleeMethod =
2496 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2497
2498 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2499 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2500 else
2501 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2502
2503 /* r0 = calleeMethod */
2504 loadConstant(cUnit, r0, (int) calleeMethod);
2505
Ben Cheng38329f52009-07-07 14:19:20 -07002506 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2507 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002508 break;
2509 }
2510 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2511 case OP_INVOKE_STATIC:
2512 case OP_INVOKE_STATIC_RANGE: {
2513 const Method *calleeMethod =
2514 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2515
2516 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2517 genProcessArgsNoRange(cUnit, mir, dInsn,
2518 NULL /* no null check */);
2519 else
2520 genProcessArgsRange(cUnit, mir, dInsn,
2521 NULL /* no null check */);
2522
2523 /* r0 = calleeMethod */
2524 loadConstant(cUnit, r0, (int) calleeMethod);
2525
Ben Cheng38329f52009-07-07 14:19:20 -07002526 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2527 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002528 break;
2529 }
2530 /*
2531 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2532 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07002533 *
2534 * Given "invoke-interface {v0}", the following is the generated code:
2535 *
2536 * 0x426a9abe : ldr r0, [r5, #0] --+
2537 * 0x426a9ac0 : mov r7, r5 |
2538 * 0x426a9ac2 : sub r7, #24 |
2539 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
2540 * 0x426a9ac6 : beq 0x426a9afe |
2541 * 0x426a9ac8 : stmia r7, <r0> --+
2542 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2543 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
2544 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
2545 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
2546 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
2547 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
2548 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
2549 * 0x426a9ad8 : mov r9, r1 --+
2550 * 0x426a9ada : mov r10, r2 |
2551 * 0x426a9adc : mov r12, r3 |
2552 * 0x426a9ade : mov r0, r3 |
2553 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
2554 * 0x426a9ae2 : ldr r2, [pc, #76] |
2555 * 0x426a9ae4 : ldr r3, [pc, #68] |
2556 * 0x426a9ae6 : ldr r7, [pc, #64] |
2557 * 0x426a9ae8 : blx r7 --+
2558 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
2559 * 0x426a9aec : cmp r1, #0 --> compare against 0
2560 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
2561 * 0x426a9af0 : ldr r7, [r6, #96] --+
2562 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
2563 * 0x426a9af4 : mov r3, r12 |
2564 * 0x426a9af6 : blx r7 --+
2565 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
2566 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2567 * 0x426a9afc : blx_2 see above --+
2568 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
2569 * 0x426a9afe (0042): ldr r0, [pc, #52]
2570 * Exception_Handling:
2571 * 0x426a9b00 (0044): ldr r1, [r6, #84]
2572 * 0x426a9b02 (0046): blx r1
2573 * 0x426a9b04 (0048): .align4
2574 * -------- chaining cell (hot): 0x0021
2575 * 0x426a9b04 (0048): ldr r0, [r6, #92]
2576 * 0x426a9b06 (004a): blx r0
2577 * 0x426a9b08 (004c): data 0x7872(30834)
2578 * 0x426a9b0a (004e): data 0x428b(17035)
2579 * 0x426a9b0c (0050): .align4
2580 * -------- chaining cell (predicted)
2581 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
2582 * 0x426a9b0e (0052): data 0x0000(0)
2583 * 0x426a9b10 (0054): data 0x0000(0) --> class
2584 * 0x426a9b12 (0056): data 0x0000(0)
2585 * 0x426a9b14 (0058): data 0x0000(0) --> method
2586 * 0x426a9b16 (005a): data 0x0000(0)
2587 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
2588 * 0x426a9b1a (005e): data 0x0000(0)
2589 * 0x426a9b28 (006c): .word (0xad0392a5)
2590 * 0x426a9b2c (0070): .word (0x6e750)
2591 * 0x426a9b30 (0074): .word (0x4109a618)
2592 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002593 */
2594 case OP_INVOKE_INTERFACE:
2595 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002596 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002597 int methodIndex = dInsn->vB;
2598
2599 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2600 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2601 else
2602 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2603
Ben Cheng38329f52009-07-07 14:19:20 -07002604 /* "this" is already left in r0 by genProcessArgs* */
2605
2606 /* r4PC = dalvikCallsite */
2607 loadConstant(cUnit, r4PC,
2608 (int) (cUnit->method->insns + mir->offset));
2609
2610 /* r1 = &retChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002611 ArmLIR *addrRetChain = newLIR2(cUnit, THUMB_ADD_PC_REL,
Ben Cheng38329f52009-07-07 14:19:20 -07002612 r1, 0);
2613 addrRetChain->generic.target = (LIR *) retChainingCell;
2614
2615 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002616 ArmLIR *predictedChainingCell =
2617 newLIR2(cUnit, THUMB_ADD_PC_REL, r2, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002618 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2619
2620 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2621
2622 /* return through lr - jump to the chaining cell */
2623 genUnconditionalBranch(cUnit, predChainingCell);
2624
2625 /*
2626 * null-check on "this" may have been eliminated, but we still need
2627 * a PC-reconstruction label for stack overflow bailout.
2628 */
2629 if (pcrLabel == NULL) {
2630 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002631 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
2632 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07002633 pcrLabel->operands[0] = dPC;
2634 pcrLabel->operands[1] = mir->offset;
2635 /* Insert the place holder to the growable list */
2636 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2637 }
2638
2639 /* return through lr+2 - punt to the interpreter */
2640 genUnconditionalBranch(cUnit, pcrLabel);
2641
2642 /*
2643 * return through lr+4 - fully resolve the callee method.
2644 * r1 <- count
2645 * r2 <- &predictedChainCell
2646 * r3 <- this->class
2647 * r4 <- dPC
2648 * r7 <- this->class->vtable
2649 */
2650
2651 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002652 newLIR2(cUnit, THUMB_MOV_RR_L2H, r9 & THUMB_REG_MASK, r1);
2653 newLIR2(cUnit, THUMB_MOV_RR_L2H, r10 & THUMB_REG_MASK, r2);
2654 newLIR2(cUnit, THUMB_MOV_RR_L2H, r12 & THUMB_REG_MASK, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002655
Ben Chengba4fc8b2009-06-01 13:00:29 -07002656 /* r0 now contains this->clazz */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002657 newLIR2(cUnit, THUMB_MOV_RR, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002658
2659 /* r1 = BBBB */
2660 loadConstant(cUnit, r1, dInsn->vB);
2661
2662 /* r2 = method (caller) */
2663 loadConstant(cUnit, r2, (int) cUnit->method);
2664
2665 /* r3 = pDvmDex */
2666 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
2667
2668 loadConstant(cUnit, r7,
2669 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002670 newLIR1(cUnit, THUMB_BLX_R, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002671
2672 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
2673
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002674 newLIR2(cUnit, THUMB_MOV_RR_H2L, r1, r9 & THUMB_REG_MASK);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002675
Ben Cheng38329f52009-07-07 14:19:20 -07002676 /* Check if rechain limit is reached */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002677 newLIR2(cUnit, THUMB_CMP_RI8, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002678
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002679 ArmLIR *bypassRechaining =
2680 newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07002681
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002682 newLIR3(cUnit, THUMB_LDR_RRI5, r7, rGLUE,
Ben Cheng38329f52009-07-07 14:19:20 -07002683 offsetof(InterpState,
2684 jitToInterpEntries.dvmJitToPatchPredictedChain)
2685 >> 2);
2686
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002687 newLIR2(cUnit, THUMB_MOV_RR_H2L, r2, r10 & THUMB_REG_MASK);
2688 newLIR2(cUnit, THUMB_MOV_RR_H2L, r3, r12 & THUMB_REG_MASK);
Ben Cheng38329f52009-07-07 14:19:20 -07002689
2690 /*
2691 * r0 = calleeMethod
2692 * r2 = &predictedChainingCell
2693 * r3 = class
2694 *
2695 * &returnChainingCell has been loaded into r1 but is not needed
2696 * when patching the chaining cell and will be clobbered upon
2697 * returning so it will be reconstructed again.
2698 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002699 newLIR1(cUnit, THUMB_BLX_R, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002700
2701 /* r1 = &retChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002702 addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL,
Ben Cheng38329f52009-07-07 14:19:20 -07002703 r1, 0, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002704 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07002705
2706 bypassRechaining->generic.target = (LIR *) addrRetChain;
2707
Ben Chengba4fc8b2009-06-01 13:00:29 -07002708 /*
2709 * r0 = this, r1 = calleeMethod,
2710 * r1 = &ChainingCell,
2711 * r4PC = callsiteDPC,
2712 */
2713 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2714#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07002715 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002716#endif
2717 /* Handle exceptions using the interpreter */
2718 genTrap(cUnit, mir->offset, pcrLabel);
2719 break;
2720 }
2721 /* NOP */
2722 case OP_INVOKE_DIRECT_EMPTY: {
2723 return false;
2724 }
2725 case OP_FILLED_NEW_ARRAY:
2726 case OP_FILLED_NEW_ARRAY_RANGE: {
2727 /* Just let the interpreter deal with these */
2728 genInterpSingleStep(cUnit, mir);
2729 break;
2730 }
2731 default:
2732 return true;
2733 }
2734 return false;
2735}
2736
2737static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002738 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002739{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002740 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
2741 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2742 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002743
2744 DecodedInstruction *dInsn = &mir->dalvikInsn;
2745 switch (mir->dalvikInsn.opCode) {
2746 /* calleeMethod = this->clazz->vtable[BBBB] */
2747 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
2748 case OP_INVOKE_VIRTUAL_QUICK: {
2749 int methodIndex = dInsn->vB;
2750 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
2751 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2752 else
2753 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2754
Ben Cheng38329f52009-07-07 14:19:20 -07002755 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2756 retChainingCell,
2757 predChainingCell,
2758 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002759 break;
2760 }
2761 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2762 case OP_INVOKE_SUPER_QUICK:
2763 case OP_INVOKE_SUPER_QUICK_RANGE: {
2764 const Method *calleeMethod =
2765 cUnit->method->clazz->super->vtable[dInsn->vB];
2766
2767 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
2768 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2769 else
2770 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2771
2772 /* r0 = calleeMethod */
2773 loadConstant(cUnit, r0, (int) calleeMethod);
2774
Ben Cheng38329f52009-07-07 14:19:20 -07002775 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2776 calleeMethod);
2777 /* Handle exceptions using the interpreter */
2778 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002779 break;
2780 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002781 default:
2782 return true;
2783 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002784 return false;
2785}
2786
2787/*
2788 * NOTE: We assume here that the special native inline routines
2789 * are side-effect free. By making this assumption, we can safely
2790 * re-execute the routine from the interpreter if it decides it
2791 * wants to throw an exception. We still need to EXPORT_PC(), though.
2792 */
2793static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
2794{
2795 DecodedInstruction *dInsn = &mir->dalvikInsn;
2796 switch( mir->dalvikInsn.opCode) {
2797 case OP_EXECUTE_INLINE: {
2798 unsigned int i;
2799 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002800 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002801 int operation = dInsn->vB;
2802
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002803 switch (operation) {
2804 case INLINE_EMPTYINLINEMETHOD:
2805 return false; /* Nop */
2806 case INLINE_STRING_LENGTH:
2807 return genInlinedStringLength(cUnit, mir);
2808 case INLINE_MATH_ABS_INT:
2809 return genInlinedAbsInt(cUnit, mir);
2810 case INLINE_MATH_ABS_LONG:
2811 return genInlinedAbsLong(cUnit, mir);
2812 case INLINE_MATH_MIN_INT:
2813 return genInlinedMinMaxInt(cUnit, mir, true);
2814 case INLINE_MATH_MAX_INT:
2815 return genInlinedMinMaxInt(cUnit, mir, false);
2816 case INLINE_STRING_CHARAT:
2817 return genInlinedStringCharAt(cUnit, mir);
2818 case INLINE_MATH_SQRT:
2819 if (genInlineSqrt(cUnit, mir))
2820 return true;
2821 else
2822 break; /* Handle with C routine */
2823 case INLINE_MATH_COS:
2824 if (genInlineCos(cUnit, mir))
2825 return true;
2826 else
2827 break; /* Handle with C routine */
2828 case INLINE_MATH_SIN:
2829 if (genInlineSin(cUnit, mir))
2830 return true;
2831 else
2832 break; /* Handle with C routine */
2833 case INLINE_MATH_ABS_FLOAT:
2834 return genInlinedAbsFloat(cUnit, mir);
2835 case INLINE_MATH_ABS_DOUBLE:
2836 return genInlinedAbsDouble(cUnit, mir);
2837 case INLINE_STRING_COMPARETO:
2838 case INLINE_STRING_EQUALS:
2839 break;
2840 default:
2841 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07002842 }
2843
2844 /* Materialize pointer to retval & push */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002845 newLIR2(cUnit, THUMB_MOV_RR, r4PC, rGLUE);
2846 newLIR2(cUnit, THUMB_ADD_RI8, r4PC, offset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002847 /* Push r4 and (just to take up space) r5) */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002848 newLIR1(cUnit, THUMB_PUSH, (1<<r4PC | 1<<rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002849
2850 /* Get code pointer to inline routine */
2851 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
2852
2853 /* Export PC */
2854 genExportPC(cUnit, mir, r0, r1 );
2855
2856 /* Load arguments to r0 through r3 as applicable */
2857 for (i=0; i < dInsn->vA; i++) {
2858 loadValue(cUnit, dInsn->arg[i], i);
2859 }
2860 /* Call inline routine */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002861 newLIR1(cUnit, THUMB_BLX_R, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002862
2863 /* Strip frame */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002864 newLIR1(cUnit, THUMB_ADD_SPI7, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002865
2866 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07002867 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002868
Ben Chenge9695e52009-06-16 16:11:47 -07002869 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002870 break;
2871 }
2872 default:
2873 return true;
2874 }
2875 return false;
2876}
2877
2878static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
2879{
2880 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
2881 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
2882 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2883 return false;
2884}
2885
2886/*****************************************************************************/
2887/*
2888 * The following are special processing routines that handle transfer of
2889 * controls between compiled code and the interpreter. Certain VM states like
2890 * Dalvik PC and special-purpose registers are reconstructed here.
2891 */
2892
Ben Cheng1efc9c52009-06-08 18:25:27 -07002893/* Chaining cell for code that may need warmup. */
2894static void handleNormalChainingCell(CompilationUnit *cUnit,
2895 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002896{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002897 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002898 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002899 newLIR1(cUnit, THUMB_BLX_R, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002900 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
2901}
2902
2903/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07002904 * Chaining cell for instructions that immediately following already translated
2905 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07002906 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07002907static void handleHotChainingCell(CompilationUnit *cUnit,
2908 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002909{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002910 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002911 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002912 newLIR1(cUnit, THUMB_BLX_R, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002913 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
2914}
2915
2916/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07002917static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
2918 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002919{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002920 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002921 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002922 newLIR1(cUnit, THUMB_BLX_R, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002923 addWordData(cUnit, (int) (callee->insns), true);
2924}
2925
Ben Cheng38329f52009-07-07 14:19:20 -07002926/* Chaining cell for monomorphic method invocations. */
2927static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
2928{
2929
2930 /* Should not be executed in the initial state */
2931 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
2932 /* To be filled: class */
2933 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
2934 /* To be filled: method */
2935 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
2936 /*
2937 * Rechain count. The initial value of 0 here will trigger chaining upon
2938 * the first invocation of this callsite.
2939 */
2940 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
2941}
2942
Ben Chengba4fc8b2009-06-01 13:00:29 -07002943/* Load the Dalvik PC into r0 and jump to the specified target */
2944static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002945 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002946{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002947 ArmLIR **pcrLabel =
2948 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002949 int numElems = cUnit->pcReconstructionList.numUsed;
2950 int i;
2951 for (i = 0; i < numElems; i++) {
2952 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
2953 /* r0 = dalvik PC */
2954 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
2955 genUnconditionalBranch(cUnit, targetLabel);
2956 }
2957}
2958
2959/* Entry function to invoke the backend of the JIT compiler */
2960void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
2961{
2962 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002963 ArmLIR *labelList =
2964 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002965 GrowableList chainingListByType[CHAINING_CELL_LAST];
2966 int i;
2967
2968 /*
Ben Cheng38329f52009-07-07 14:19:20 -07002969 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07002970 */
2971 for (i = 0; i < CHAINING_CELL_LAST; i++) {
2972 dvmInitGrowableList(&chainingListByType[i], 2);
2973 }
2974
2975 BasicBlock **blockList = cUnit->blockList;
2976
Bill Buzbee6e963e12009-06-17 16:56:19 -07002977 if (cUnit->executionCount) {
2978 /*
2979 * Reserve 6 bytes at the beginning of the trace
2980 * +----------------------------+
2981 * | execution count (4 bytes) |
2982 * +----------------------------+
2983 * | chain cell offset (2 bytes)|
2984 * +----------------------------+
2985 * ...and then code to increment the execution
2986 * count:
2987 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
2988 * sub r0, #10 @ back up to addr of executionCount
2989 * ldr r1, [r0]
2990 * add r1, #1
2991 * str r1, [r0]
2992 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002993 newLIR1(cUnit, ARM_16BIT_DATA, 0);
2994 newLIR1(cUnit, ARM_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07002995 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002996 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07002997 cUnit->headerSize = 6;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002998 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc & THUMB_REG_MASK);
2999 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3000 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3001 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3002 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003003 } else {
3004 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003005 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003006 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003007 cUnit->headerSize = 2;
3008 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003009
Ben Chengba4fc8b2009-06-01 13:00:29 -07003010 /* Handle the content in each basic block */
3011 for (i = 0; i < cUnit->numBlocks; i++) {
3012 blockList[i]->visited = true;
3013 MIR *mir;
3014
3015 labelList[i].operands[0] = blockList[i]->startOffset;
3016
3017 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3018 /*
3019 * Append the label pseudo LIR first. Chaining cells will be handled
3020 * separately afterwards.
3021 */
3022 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3023 }
3024
3025 if (blockList[i]->blockType == DALVIK_BYTECODE) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003026 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003027 /* Reset the register state */
3028 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003029 } else {
3030 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003031 case CHAINING_CELL_NORMAL:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003032 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003033 /* handle the codegen later */
3034 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003035 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003036 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003037 case CHAINING_CELL_INVOKE_SINGLETON:
3038 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003039 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003040 labelList[i].operands[0] =
3041 (int) blockList[i]->containingMethod;
3042 /* handle the codegen later */
3043 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003044 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3045 (void *) i);
3046 break;
3047 case CHAINING_CELL_INVOKE_PREDICTED:
3048 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003049 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
Ben Cheng38329f52009-07-07 14:19:20 -07003050 /* handle the codegen later */
3051 dvmInsertGrowableList(
3052 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3053 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003054 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003055 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003056 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003057 ARM_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003058 /* handle the codegen later */
3059 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003060 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003061 (void *) i);
3062 break;
3063 case PC_RECONSTRUCTION:
3064 /* Make sure exception handling block is next */
3065 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003066 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003067 assert (i == cUnit->numBlocks - 2);
3068 handlePCReconstruction(cUnit, &labelList[i+1]);
3069 break;
3070 case EXCEPTION_HANDLING:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003071 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003072 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003073 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003074 offsetof(InterpState,
3075 jitToInterpEntries.dvmJitToInterpPunt)
3076 >> 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003077 newLIR1(cUnit, THUMB_BLX_R, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003078 }
3079 break;
3080 default:
3081 break;
3082 }
3083 continue;
3084 }
Ben Chenge9695e52009-06-16 16:11:47 -07003085
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003086 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003087
Ben Chengba4fc8b2009-06-01 13:00:29 -07003088 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
3089 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3090 InstructionFormat dalvikFormat =
3091 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003092 ArmLIR *boundaryLIR =
3093 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
Ben Chenge9695e52009-06-16 16:11:47 -07003094 mir->offset,dalvikOpCode);
3095 /* Remember the first LIR for this block */
3096 if (headLIR == NULL) {
3097 headLIR = boundaryLIR;
3098 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003099 bool notHandled;
3100 /*
3101 * Debugging: screen the opcode first to see if it is in the
3102 * do[-not]-compile list
3103 */
3104 bool singleStepMe =
3105 gDvmJit.includeSelectedOp !=
3106 ((gDvmJit.opList[dalvikOpCode >> 3] &
3107 (1 << (dalvikOpCode & 0x7))) !=
3108 0);
3109 if (singleStepMe || cUnit->allSingleStep) {
3110 notHandled = false;
3111 genInterpSingleStep(cUnit, mir);
3112 } else {
3113 opcodeCoverage[dalvikOpCode]++;
3114 switch (dalvikFormat) {
3115 case kFmt10t:
3116 case kFmt20t:
3117 case kFmt30t:
3118 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3119 mir, blockList[i], labelList);
3120 break;
3121 case kFmt10x:
3122 notHandled = handleFmt10x(cUnit, mir);
3123 break;
3124 case kFmt11n:
3125 case kFmt31i:
3126 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3127 break;
3128 case kFmt11x:
3129 notHandled = handleFmt11x(cUnit, mir);
3130 break;
3131 case kFmt12x:
3132 notHandled = handleFmt12x(cUnit, mir);
3133 break;
3134 case kFmt20bc:
3135 notHandled = handleFmt20bc(cUnit, mir);
3136 break;
3137 case kFmt21c:
3138 case kFmt31c:
3139 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3140 break;
3141 case kFmt21h:
3142 notHandled = handleFmt21h(cUnit, mir);
3143 break;
3144 case kFmt21s:
3145 notHandled = handleFmt21s(cUnit, mir);
3146 break;
3147 case kFmt21t:
3148 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3149 labelList);
3150 break;
3151 case kFmt22b:
3152 case kFmt22s:
3153 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3154 break;
3155 case kFmt22c:
3156 notHandled = handleFmt22c(cUnit, mir);
3157 break;
3158 case kFmt22cs:
3159 notHandled = handleFmt22cs(cUnit, mir);
3160 break;
3161 case kFmt22t:
3162 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3163 labelList);
3164 break;
3165 case kFmt22x:
3166 case kFmt32x:
3167 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3168 break;
3169 case kFmt23x:
3170 notHandled = handleFmt23x(cUnit, mir);
3171 break;
3172 case kFmt31t:
3173 notHandled = handleFmt31t(cUnit, mir);
3174 break;
3175 case kFmt3rc:
3176 case kFmt35c:
3177 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3178 labelList);
3179 break;
3180 case kFmt3rms:
3181 case kFmt35ms:
3182 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3183 labelList);
3184 break;
3185 case kFmt3inline:
3186 notHandled = handleFmt3inline(cUnit, mir);
3187 break;
3188 case kFmt51l:
3189 notHandled = handleFmt51l(cUnit, mir);
3190 break;
3191 default:
3192 notHandled = true;
3193 break;
3194 }
3195 }
3196 if (notHandled) {
3197 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3198 mir->offset,
3199 dalvikOpCode, getOpcodeName(dalvikOpCode),
3200 dalvikFormat);
3201 dvmAbort();
3202 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003203 }
3204 }
Ben Chenge9695e52009-06-16 16:11:47 -07003205 /* Eliminate redundant loads/stores and delay stores into later slots */
3206 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3207 cUnit->lastLIRInsn);
Ben Cheng1efc9c52009-06-08 18:25:27 -07003208 /*
3209 * Check if the block is terminated due to trace length constraint -
3210 * insert an unconditional branch to the chaining cell.
3211 */
3212 if (blockList[i]->needFallThroughBranch) {
3213 genUnconditionalBranch(cUnit,
3214 &labelList[blockList[i]->fallThrough->id]);
3215 }
3216
Ben Chengba4fc8b2009-06-01 13:00:29 -07003217 }
3218
Ben Chenge9695e52009-06-16 16:11:47 -07003219 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003220 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3221 size_t j;
3222 int *blockIdList = (int *) chainingListByType[i].elemList;
3223
3224 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3225
3226 /* No chaining cells of this type */
3227 if (cUnit->numChainingCells[i] == 0)
3228 continue;
3229
3230 /* Record the first LIR for a new type of chaining cell */
3231 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3232
3233 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3234 int blockId = blockIdList[j];
3235
3236 /* Align this chaining cell first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003237 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003238
3239 /* Insert the pseudo chaining instruction */
3240 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3241
3242
3243 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003244 case CHAINING_CELL_NORMAL:
3245 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003246 blockList[blockId]->startOffset);
3247 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003248 case CHAINING_CELL_INVOKE_SINGLETON:
3249 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003250 blockList[blockId]->containingMethod);
3251 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003252 case CHAINING_CELL_INVOKE_PREDICTED:
3253 handleInvokePredictedChainingCell(cUnit);
3254 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003255 case CHAINING_CELL_HOT:
3256 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003257 blockList[blockId]->startOffset);
3258 break;
3259 default:
3260 dvmAbort();
3261 break;
3262 }
3263 }
3264 }
Ben Chenge9695e52009-06-16 16:11:47 -07003265
3266 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003267}
3268
3269/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07003270bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003271{
Bill Buzbee716f1202009-07-23 13:22:09 -07003272 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003273
3274 if (gDvmJit.codeCacheFull) {
Bill Buzbee716f1202009-07-23 13:22:09 -07003275 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003276 }
3277
3278 switch (work->kind) {
3279 case kWorkOrderMethod:
Bill Buzbee716f1202009-07-23 13:22:09 -07003280 res = dvmCompileMethod(work->info, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003281 break;
3282 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003283 /* Start compilation with maximally allowed trace length */
Bill Buzbee716f1202009-07-23 13:22:09 -07003284 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003285 break;
3286 default:
Bill Buzbee716f1202009-07-23 13:22:09 -07003287 res = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003288 dvmAbort();
3289 }
3290 return res;
3291}
3292
Ben Chengba4fc8b2009-06-01 13:00:29 -07003293/* Architectural-specific debugging helpers go here */
3294void dvmCompilerArchDump(void)
3295{
3296 /* Print compiled opcode in this VM instance */
3297 int i, start, streak;
3298 char buf[1024];
3299
3300 streak = i = 0;
3301 buf[0] = 0;
3302 while (opcodeCoverage[i] == 0 && i < 256) {
3303 i++;
3304 }
3305 if (i == 256) {
3306 return;
3307 }
3308 for (start = i++, streak = 1; i < 256; i++) {
3309 if (opcodeCoverage[i]) {
3310 streak++;
3311 } else {
3312 if (streak == 1) {
3313 sprintf(buf+strlen(buf), "%x,", start);
3314 } else {
3315 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3316 }
3317 streak = 0;
3318 while (opcodeCoverage[i] == 0 && i < 256) {
3319 i++;
3320 }
3321 if (i < 256) {
3322 streak = 1;
3323 start = i;
3324 }
3325 }
3326 }
3327 if (streak) {
3328 if (streak == 1) {
3329 sprintf(buf+strlen(buf), "%x", start);
3330 } else {
3331 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3332 }
3333 }
3334 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07003335 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003336 }
3337}