blob: 3ba3cc6abd986766459ff96afedeb2752ef1e793 [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
17#include "Dalvik.h"
18#include "interp/InterpDefs.h"
19#include "libdex/OpCode.h"
20#include "dexdump/OpCodeNames.h"
21#include "vm/compiler/CompilerInternals.h"
Bill Buzbeed45ba372009-06-15 17:00:57 -070022#include "FpCodegen.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070023#include "Armv5teLIR.h"
24#include "vm/mterp/common/FindInterface.h"
25
Ben Chengba4fc8b2009-06-01 13:00:29 -070026/* Array holding the entry offset of each template relative to the first one */
27static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
28
29/* Track exercised opcodes */
30static int opcodeCoverage[256];
31
Ben Chenge9695e52009-06-16 16:11:47 -070032/* non-existent register */
33#define vNone (-1)
34
35/* get the next register in r0..r3 in a round-robin fashion */
36#define NEXT_REG(reg) ((reg + 1) & 3)
37
Ben Chengba4fc8b2009-06-01 13:00:29 -070038/*****************************************************************************/
39
40/*
41 * The following are building blocks to construct low-level IRs with 0 - 3
42 * operands.
43 */
44static Armv5teLIR *newLIR0(CompilationUnit *cUnit, Armv5teOpCode opCode)
45{
46 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070047 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
Ben Chengba4fc8b2009-06-01 13:00:29 -070048 insn->opCode = opCode;
49 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
50 return insn;
51}
52
53static Armv5teLIR *newLIR1(CompilationUnit *cUnit, Armv5teOpCode opCode,
54 int dest)
55{
56 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070057 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -070058 insn->opCode = opCode;
59 insn->operands[0] = dest;
60 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
61 return insn;
62}
63
64static Armv5teLIR *newLIR2(CompilationUnit *cUnit, Armv5teOpCode opCode,
65 int dest, int src1)
66{
67 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070068 assert(isPseudoOpCode(opCode) ||
69 (EncodingMap[opCode].flags & IS_BINARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -070070 insn->opCode = opCode;
71 insn->operands[0] = dest;
72 insn->operands[1] = src1;
73 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
74 return insn;
75}
76
77static Armv5teLIR *newLIR3(CompilationUnit *cUnit, Armv5teOpCode opCode,
78 int dest, int src1, int src2)
79{
80 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070081 assert(isPseudoOpCode(opCode) ||
82 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -070083 insn->opCode = opCode;
84 insn->operands[0] = dest;
85 insn->operands[1] = src1;
86 insn->operands[2] = src2;
87 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
88 return insn;
89}
90
91static Armv5teLIR *newLIR23(CompilationUnit *cUnit, Armv5teOpCode opCode,
92 int srcdest, int src2)
93{
94 assert(!isPseudoOpCode(opCode));
Ben Chenge9695e52009-06-16 16:11:47 -070095 if (EncodingMap[opCode].flags & IS_BINARY_OP)
Ben Chengba4fc8b2009-06-01 13:00:29 -070096 return newLIR2(cUnit, opCode, srcdest, src2);
97 else
98 return newLIR3(cUnit, opCode, srcdest, srcdest, src2);
99}
100
101/*****************************************************************************/
102
103/*
Ben Chenge9695e52009-06-16 16:11:47 -0700104 * The following are utility routines to help maintain the RegisterScoreboard
105 * state to facilitate register renaming.
106 */
107
108/* Reset the tracker to unknown state */
109static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
110{
111 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
112
113 dvmClearAllBits(registerScoreboard->nullCheckedRegs);
114 registerScoreboard->liveDalvikReg = vNone;
115 registerScoreboard->nativeReg = vNone;
116 registerScoreboard->nativeRegHi = vNone;
117}
118
119/* Kill the corresponding bit in the null-checked register list */
120static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
121{
122 dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
123}
124
125/* The Dalvik register pair held in native registers have changed */
126static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
127 int vReg, int mRegLo, int mRegHi)
128{
129 cUnit->registerScoreboard.liveDalvikReg = vReg;
130 cUnit->registerScoreboard.nativeReg = mRegLo;
131 cUnit->registerScoreboard.nativeRegHi = mRegHi;
132 cUnit->registerScoreboard.isWide = true;
133}
134
135/* The Dalvik register held in a native register has changed */
136static inline void updateLiveRegister(CompilationUnit *cUnit,
137 int vReg, int mReg)
138{
139 cUnit->registerScoreboard.liveDalvikReg = vReg;
140 cUnit->registerScoreboard.nativeReg = mReg;
141 cUnit->registerScoreboard.isWide = false;
142}
143
144/*
145 * Given a Dalvik register id vSrc, use a very simple algorithm to increase
146 * the lifetime of cached Dalvik value in a native register.
147 */
148static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
149 bool isWide)
150{
151 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
152
153 /* No live value - suggest to use r0 */
154 if (registerScoreboard->liveDalvikReg == vNone)
155 return r0;
156
157 /* Reuse the previously used native reg */
158 if (registerScoreboard->liveDalvikReg == vSrc) {
159 if (isWide != true) {
160 return registerScoreboard->nativeReg;
161 } else {
162 /* Return either r0 or r2 */
163 return (registerScoreboard->nativeReg + 1) & 2;
164 }
165 }
166
167 /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
168 if (isWide) {
169 return (registerScoreboard->nativeReg + 2) & 2;
170 } else {
171 return (registerScoreboard->nativeReg + 1) & 3;
172 }
173
174}
175/*****************************************************************************/
176
177/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700178 * The following are building blocks to insert constants into the pool or
179 * instruction streams.
180 */
181
182/* Add a 32-bit constant either in the constant pool or mixed with code */
183static Armv5teLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
184{
185 /* Add the constant to the literal pool */
186 if (!inPlace) {
187 Armv5teLIR *newValue = dvmCompilerNew(sizeof(Armv5teLIR), true);
188 newValue->operands[0] = value;
189 newValue->generic.next = cUnit->wordList;
190 cUnit->wordList = (LIR *) newValue;
191 return newValue;
192 } else {
193 /* Add the constant in the middle of code stream */
194 newLIR1(cUnit, ARMV5TE_16BIT_DATA, (value & 0xffff));
195 newLIR1(cUnit, ARMV5TE_16BIT_DATA, (value >> 16));
196 }
197 return NULL;
198}
199
200/*
201 * Search the existing constants in the literal pool for an exact or close match
202 * within specified delta (greater or equal to 0).
203 */
204static Armv5teLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
205 unsigned int delta)
206{
207 LIR *dataTarget = cUnit->wordList;
208 while (dataTarget) {
209 if (((unsigned) (value - ((Armv5teLIR *) dataTarget)->operands[0])) <=
210 delta)
211 return (Armv5teLIR *) dataTarget;
212 dataTarget = dataTarget->next;
213 }
214 return NULL;
215}
216
217/*
218 * Load a immediate using a shortcut if possible; otherwise
219 * grab from the per-translation literal pool
220 */
221void loadConstant(CompilationUnit *cUnit, int rDest, int value)
222{
223 /* See if the value can be constructed cheaply */
224 if ((value >= 0) && (value <= 255)) {
225 newLIR2(cUnit, ARMV5TE_MOV_IMM, rDest, value);
226 return;
227 } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
228 newLIR2(cUnit, ARMV5TE_MOV_IMM, rDest, ~value);
229 newLIR2(cUnit, ARMV5TE_MVN, rDest, rDest);
230 return;
231 }
232 /* No shortcut - go ahead and use literal pool */
233 Armv5teLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
234 if (dataTarget == NULL) {
235 dataTarget = addWordData(cUnit, value, false);
236 }
237 Armv5teLIR *loadPcRel = dvmCompilerNew(sizeof(Armv5teLIR), true);
238 loadPcRel->opCode = ARMV5TE_LDR_PC_REL;
239 loadPcRel->generic.target = (LIR *) dataTarget;
240 loadPcRel->operands[0] = rDest;
241 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
242
243 /*
244 * To save space in the constant pool, we use the ADD_RRI8 instruction to
245 * add up to 255 to an existing constant value.
246 */
247 if (dataTarget->operands[0] != value) {
248 newLIR2(cUnit, ARMV5TE_ADD_RI8, rDest, value - dataTarget->operands[0]);
249 }
250}
251
252/* Export the Dalvik PC assicated with an instruction to the StackSave area */
253static void genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC, int rAddr)
254{
255 int offset = offsetof(StackSaveArea, xtra.currentPc);
256 loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
257 newLIR2(cUnit, ARMV5TE_MOV_RR, rAddr, rFP);
258 newLIR2(cUnit, ARMV5TE_SUB_RI8, rAddr, sizeof(StackSaveArea) - offset);
259 newLIR3(cUnit, ARMV5TE_STR_RRI5, rDPC, rAddr, 0);
260}
261
262/* Generate conditional branch instructions */
263static void genConditionalBranch(CompilationUnit *cUnit,
264 Armv5teConditionCode cond,
265 Armv5teLIR *target)
266{
267 Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
268 branch->generic.target = (LIR *) target;
269}
270
271/* Generate unconditional branch instructions */
272static void genUnconditionalBranch(CompilationUnit *cUnit, Armv5teLIR *target)
273{
274 Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
275 branch->generic.target = (LIR *) target;
276}
277
278#define USE_IN_CACHE_HANDLER 1
279
280/*
281 * Jump to the out-of-line handler in ARM mode to finish executing the
282 * remaining of more complex instructions.
283 */
284static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
285{
286#if USE_IN_CACHE_HANDLER
287 /*
288 * NOTE - In practice BLX only needs one operand, but since the assembler
289 * may abort itself and retry due to other out-of-range conditions we
290 * cannot really use operand[0] to store the absolute target address since
291 * it may get clobbered by the final relative offset. Therefore,
292 * we fake BLX_1 is a two operand instruction and the absolute target
293 * address is stored in operand[1].
294 */
295 newLIR2(cUnit, ARMV5TE_BLX_1,
296 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
297 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
298 newLIR2(cUnit, ARMV5TE_BLX_2,
299 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
300 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
301#else
302 /*
303 * In case we want to access the statically compiled handlers for
304 * debugging purposes, define USE_IN_CACHE_HANDLER to 0
305 */
306 void *templatePtr;
307
308#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
309#include "../../template/armv5te/TemplateOpList.h"
310#undef JIT_TEMPLATE
311 switch (opCode) {
312#define JIT_TEMPLATE(X) \
313 case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; }
314#include "../../template/armv5te/TemplateOpList.h"
315#undef JIT_TEMPLATE
316 default: templatePtr = NULL;
317 }
318 loadConstant(cUnit, r7, (int) templatePtr);
319 newLIR1(cUnit, ARMV5TE_BLX_R, r7);
320#endif
321}
322
323/* Perform the actual operation for OP_RETURN_* */
324static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
325{
326 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
327#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -0700328 gDvmJit.returnOp++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700329#endif
330 int dPC = (int) (cUnit->method->insns + mir->offset);
331 Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
332 /* Set up the place holder to reconstruct this Dalvik PC */
333 Armv5teLIR *pcrLabel = dvmCompilerNew(sizeof(Armv5teLIR), true);
334 pcrLabel->opCode = ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL;
335 pcrLabel->operands[0] = dPC;
336 pcrLabel->operands[1] = mir->offset;
337 /* Insert the place holder to the growable list */
338 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
339 /* Branch to the PC reconstruction code */
340 branch->generic.target = (LIR *) pcrLabel;
341}
342
343/*
344 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
345 * rDestHi
346 */
347static void loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
348 int rDestHi)
349{
350 /* Use reg + imm5*4 to load the values if possible */
351 if (vSrc <= 30) {
352 newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDestLo, rFP, vSrc);
353 newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDestHi, rFP, vSrc+1);
354 } else {
355 if (vSrc <= 64) {
356 /* Sneak 4 into the base address first */
357 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDestLo, rFP, 4);
Ben Cheng38329f52009-07-07 14:19:20 -0700358 newLIR2(cUnit, ARMV5TE_ADD_RI8, rDestLo, (vSrc-1)*4);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700359 } else {
360 /* Offset too far from rFP */
361 loadConstant(cUnit, rDestLo, vSrc*4);
362 newLIR3(cUnit, ARMV5TE_ADD_RRR, rDestLo, rFP, rDestLo);
363 }
Ben Chenge9695e52009-06-16 16:11:47 -0700364 assert(rDestLo < rDestHi);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700365 newLIR2(cUnit, ARMV5TE_LDMIA, rDestLo, (1<<rDestLo) | (1<<(rDestHi)));
366 }
367}
368
369/*
370 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
371 * vDest+1
372 */
373static void storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
374 int vDest, int rScratch)
375{
Ben Chenge9695e52009-06-16 16:11:47 -0700376 killNullCheckedRegister(cUnit, vDest);
377 killNullCheckedRegister(cUnit, vDest+1);
378 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
379
Ben Chengba4fc8b2009-06-01 13:00:29 -0700380 /* Use reg + imm5*4 to store the values if possible */
381 if (vDest <= 30) {
382 newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrcLo, rFP, vDest);
383 newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrcHi, rFP, vDest+1);
384 } else {
385 if (vDest <= 64) {
386 /* Sneak 4 into the base address first */
387 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rScratch, rFP, 4);
388 newLIR2(cUnit, ARMV5TE_ADD_RI8, rScratch, (vDest-1)*4);
389 } else {
390 /* Offset too far from rFP */
391 loadConstant(cUnit, rScratch, vDest*4);
392 newLIR3(cUnit, ARMV5TE_ADD_RRR, rScratch, rFP, rScratch);
393 }
Ben Chenge9695e52009-06-16 16:11:47 -0700394 assert(rSrcLo < rSrcHi);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700395 newLIR2(cUnit, ARMV5TE_STMIA, rScratch, (1<<rSrcLo) | (1 << (rSrcHi)));
396 }
397}
398
399/* Load the address of a Dalvik register on the frame */
400static void loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
401{
402 /* RRI3 can add up to 7 */
403 if (vSrc <= 1) {
404 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDest, rFP, vSrc*4);
405 } else if (vSrc <= 64) {
406 /* Sneak 4 into the base address first */
407 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDest, rFP, 4);
408 newLIR2(cUnit, ARMV5TE_ADD_RI8, rDest, (vSrc-1)*4);
409 } else {
410 loadConstant(cUnit, rDest, vSrc*4);
411 newLIR3(cUnit, ARMV5TE_ADD_RRR, rDest, rFP, rDest);
412 }
413}
414
Ben Chengba4fc8b2009-06-01 13:00:29 -0700415/* Load a single value from rFP[src] and store them into rDest */
416static void loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
417{
418 /* Use reg + imm5*4 to load the value if possible */
419 if (vSrc <= 31) {
420 newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDest, rFP, vSrc);
421 } else {
422 loadConstant(cUnit, rDest, vSrc*4);
423 newLIR3(cUnit, ARMV5TE_LDR_RRR, rDest, rFP, rDest);
424 }
425}
426
427/* Store a value from rSrc to vDest */
428static void storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
429 int rScratch)
430{
Ben Chenge9695e52009-06-16 16:11:47 -0700431 killNullCheckedRegister(cUnit, vDest);
432 updateLiveRegister(cUnit, vDest, rSrc);
433
Ben Chengba4fc8b2009-06-01 13:00:29 -0700434 /* Use reg + imm5*4 to store the value if possible */
435 if (vDest <= 31) {
436 newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrc, rFP, vDest);
437 } else {
438 loadConstant(cUnit, rScratch, vDest*4);
439 newLIR3(cUnit, ARMV5TE_STR_RRR, rSrc, rFP, rScratch);
440 }
441}
442
Ben Chengba4fc8b2009-06-01 13:00:29 -0700443/*
444 * Perform a binary operation on 64-bit operands and leave the results in the
445 * r0/r1 pair.
446 */
447static void genBinaryOpWide(CompilationUnit *cUnit, int vDest,
Ben Chenge9695e52009-06-16 16:11:47 -0700448 Armv5teOpCode preinst, Armv5teOpCode inst,
449 int reg0, int reg2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700450{
Ben Chenge9695e52009-06-16 16:11:47 -0700451 int reg1 = NEXT_REG(reg0);
452 int reg3 = NEXT_REG(reg2);
453 newLIR23(cUnit, preinst, reg0, reg2);
454 newLIR23(cUnit, inst, reg1, reg3);
455 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700456}
457
458/* Perform a binary operation on 32-bit operands and leave the results in r0. */
Ben Chenge9695e52009-06-16 16:11:47 -0700459static void genBinaryOp(CompilationUnit *cUnit, int vDest, Armv5teOpCode inst,
460 int reg0, int reg1, int regDest)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700461{
Ben Chenge9695e52009-06-16 16:11:47 -0700462 if (EncodingMap[inst].flags & IS_BINARY_OP) {
463 newLIR2(cUnit, inst, reg0, reg1);
464 storeValue(cUnit, reg0, vDest, reg1);
465 } else {
466 newLIR3(cUnit, inst, regDest, reg0, reg1);
467 storeValue(cUnit, regDest, vDest, reg1);
468 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700469}
470
471/* Create the PC reconstruction slot if not already done */
472static inline Armv5teLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
473 Armv5teLIR *branch,
474 Armv5teLIR *pcrLabel)
475{
476 /* Set up the place holder to reconstruct this Dalvik PC */
477 if (pcrLabel == NULL) {
478 int dPC = (int) (cUnit->method->insns + dOffset);
479 pcrLabel = dvmCompilerNew(sizeof(Armv5teLIR), true);
480 pcrLabel->opCode = ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL;
481 pcrLabel->operands[0] = dPC;
482 pcrLabel->operands[1] = dOffset;
483 /* Insert the place holder to the growable list */
484 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
485 }
486 /* Branch to the PC reconstruction code */
487 branch->generic.target = (LIR *) pcrLabel;
488 return pcrLabel;
489}
490
491/*
492 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
493 * satisfies.
494 */
495static inline Armv5teLIR *genRegImmCheck(CompilationUnit *cUnit,
496 Armv5teConditionCode cond, int reg,
497 int checkValue, int dOffset,
498 Armv5teLIR *pcrLabel)
499{
500 newLIR2(cUnit, ARMV5TE_CMP_RI8, reg, checkValue);
501 Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
502 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
503}
504
505/*
506 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
507 * satisfies.
508 */
509static inline Armv5teLIR *inertRegRegCheck(CompilationUnit *cUnit,
510 Armv5teConditionCode cond,
511 int reg1, int reg2, int dOffset,
512 Armv5teLIR *pcrLabel)
513{
514 newLIR2(cUnit, ARMV5TE_CMP_RR, reg1, reg2);
515 Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
516 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
517}
518
Ben Chenge9695e52009-06-16 16:11:47 -0700519/*
520 * Perform null-check on a register. vReg is the Dalvik register being checked,
521 * and mReg is the machine register holding the actual value. If internal state
522 * indicates that vReg has been checked before the check request is ignored.
523 */
524static Armv5teLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
525 int dOffset, Armv5teLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700526{
Ben Chenge9695e52009-06-16 16:11:47 -0700527 /* This particular Dalvik register has been null-checked */
528 if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
529 return pcrLabel;
530 }
531 dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
532 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
533}
534
535/*
536 * Perform zero-check on a register. Similar to genNullCheck but the value being
537 * checked does not have a corresponding Dalvik register.
538 */
539static Armv5teLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
540 int dOffset, Armv5teLIR *pcrLabel)
541{
542 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700543}
544
545/* Perform bound check on two registers */
546static Armv5teLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
547 int rBound, int dOffset, Armv5teLIR *pcrLabel)
548{
549 return inertRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
550 pcrLabel);
551}
552
553/* Generate a unconditional branch to go to the interpreter */
554static inline Armv5teLIR *genTrap(CompilationUnit *cUnit, int dOffset,
555 Armv5teLIR *pcrLabel)
556{
557 Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
558 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
559}
560
561/* Load a wide field from an object instance */
562static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
563{
564 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700565 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700566
Ben Chenge9695e52009-06-16 16:11:47 -0700567 /* Allocate reg0..reg3 into physical registers r0..r3 */
568
569 /* See if vB is in a native register. If so, reuse it. */
570 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
571 /* Ping reg3 to the other register of the same pair containing reg2 */
572 reg3 = reg2 ^ 0x1;
573 /*
574 * Ping reg0 to the first register of the alternate register pair
575 */
576 reg0 = (reg2 + 2) & 0x2;
577 reg1 = NEXT_REG(reg0);
578
579 loadValue(cUnit, dInsn->vB, reg2);
580 loadConstant(cUnit, reg3, fieldOffset);
581 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
582 newLIR3(cUnit, ARMV5TE_ADD_RRR, reg2, reg2, reg3);
583 newLIR2(cUnit, ARMV5TE_LDMIA, reg2, (1<<reg0 | 1<<reg1));
584 storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700585}
586
587/* Store a wide field to an object instance */
588static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
589{
590 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700591 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700592
Ben Chenge9695e52009-06-16 16:11:47 -0700593 /* Allocate reg0..reg3 into physical registers r0..r3 */
594
595 /* See if vB is in a native register. If so, reuse it. */
596 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
597 /* Ping reg3 to the other register of the same pair containing reg2 */
598 reg3 = reg2 ^ 0x1;
599 /*
600 * Ping reg0 to the first register of the alternate register pair
601 */
602 reg0 = (reg2 + 2) & 0x2;
603 reg1 = NEXT_REG(reg0);
604
605
606 loadValue(cUnit, dInsn->vB, reg2);
607 loadValuePair(cUnit, dInsn->vA, reg0, reg1);
608 updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
609 loadConstant(cUnit, reg3, fieldOffset);
610 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
611 newLIR3(cUnit, ARMV5TE_ADD_RRR, reg2, reg2, reg3);
612 newLIR2(cUnit, ARMV5TE_STMIA, reg2, (1<<reg0 | 1<<reg1));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700613}
614
615/*
616 * Load a field from an object instance
617 *
618 * Inst should be one of:
619 * ARMV5TE_LDR_RRR
620 * ARMV5TE_LDRB_RRR
621 * ARMV5TE_LDRH_RRR
622 * ARMV5TE_LDRSB_RRR
623 * ARMV5TE_LDRSH_RRR
624 */
625static void genIGet(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
626 int fieldOffset)
627{
628 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700629 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700630
Ben Chenge9695e52009-06-16 16:11:47 -0700631 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
632 reg1 = NEXT_REG(reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700633 /* TUNING: write a utility routine to load via base + constant offset */
Ben Chenge9695e52009-06-16 16:11:47 -0700634 loadValue(cUnit, dInsn->vB, reg0);
635 loadConstant(cUnit, reg1, fieldOffset);
636 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
637 newLIR3(cUnit, inst, reg0, reg0, reg1);
638 storeValue(cUnit, reg0, dInsn->vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700639}
640
641/*
642 * Store a field to an object instance
643 *
644 * Inst should be one of:
645 * ARMV5TE_STR_RRR
646 * ARMV5TE_STRB_RRR
647 * ARMV5TE_STRH_RRR
648 */
649static void genIPut(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
650 int fieldOffset)
651{
652 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700653 int reg0, reg1, reg2;
654
655 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
656 reg1 = NEXT_REG(reg0);
657 reg2 = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700658
659 /* TUNING: write a utility routine to load via base + constant offset */
Ben Chenge9695e52009-06-16 16:11:47 -0700660 loadValue(cUnit, dInsn->vB, reg0);
661 loadConstant(cUnit, reg1, fieldOffset);
662 loadValue(cUnit, dInsn->vA, reg2);
663 updateLiveRegister(cUnit, dInsn->vA, reg2);
664 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
665 newLIR3(cUnit, inst, reg2, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700666}
667
668
669/* TODO: This should probably be done as an out-of-line instruction handler. */
670
671/*
672 * Generate array load
673 *
674 * Inst should be one of:
675 * ARMV5TE_LDR_RRR
676 * ARMV5TE_LDRB_RRR
677 * ARMV5TE_LDRH_RRR
678 * ARMV5TE_LDRSB_RRR
679 * ARMV5TE_LDRSH_RRR
680 */
681static void genArrayGet(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
682 int vArray, int vIndex, int vDest, int scale)
683{
684 int lenOffset = offsetof(ArrayObject, length);
685 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700686 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700687
Ben Chenge9695e52009-06-16 16:11:47 -0700688 reg0 = selectFirstRegister(cUnit, vArray, false);
689 reg1 = NEXT_REG(reg0);
690 reg2 = NEXT_REG(reg1);
691 reg3 = NEXT_REG(reg2);
692
693 loadValue(cUnit, vArray, reg2);
694 loadValue(cUnit, vIndex, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700695
696 /* null object? */
Ben Chenge9695e52009-06-16 16:11:47 -0700697 Armv5teLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
698 NULL);
699 newLIR3(cUnit, ARMV5TE_LDR_RRI5, reg0, reg2, lenOffset >> 2); /* Get len */
700 newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, dataOffset); /* reg2 -> array data */
701 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700702 if (scale) {
Ben Chenge9695e52009-06-16 16:11:47 -0700703 newLIR3(cUnit, ARMV5TE_LSL, reg3, reg3, scale);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700704 }
705 if (scale==3) {
Ben Chenge9695e52009-06-16 16:11:47 -0700706 newLIR3(cUnit, inst, reg0, reg2, reg3);
707 newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, 4);
708 newLIR3(cUnit, inst, reg1, reg2, reg3);
709 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700710 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700711 newLIR3(cUnit, inst, reg0, reg2, reg3);
712 storeValue(cUnit, reg0, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700713 }
714}
715
716/* TODO: This should probably be done as an out-of-line instruction handler. */
717
718/*
719 * Generate array store
720 *
721 * Inst should be one of:
722 * ARMV5TE_STR_RRR
723 * ARMV5TE_STRB_RRR
724 * ARMV5TE_STRH_RRR
725 */
726static void genArrayPut(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
727 int vArray, int vIndex, int vSrc, int scale)
728{
729 int lenOffset = offsetof(ArrayObject, length);
730 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700731 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700732
Ben Chenge9695e52009-06-16 16:11:47 -0700733 reg0 = selectFirstRegister(cUnit, vArray, false);
734 reg1 = NEXT_REG(reg0);
735 reg2 = NEXT_REG(reg1);
736 reg3 = NEXT_REG(reg2);
737
738 loadValue(cUnit, vArray, reg2);
739 loadValue(cUnit, vIndex, reg3);
740
Ben Cheng1efc9c52009-06-08 18:25:27 -0700741 /* null object? */
Ben Chenge9695e52009-06-16 16:11:47 -0700742 Armv5teLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
743 NULL);
744 newLIR3(cUnit, ARMV5TE_LDR_RRI5, reg0, reg2, lenOffset >> 2); /* Get len */
745 newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, dataOffset); /* reg2 -> array data */
746 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
747 /* at this point, reg2 points to array, reg3 is unscaled index */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700748 if (scale==3) {
Ben Chenge9695e52009-06-16 16:11:47 -0700749 loadValuePair(cUnit, vSrc, reg0, reg1);
750 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700751 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700752 loadValue(cUnit, vSrc, reg0);
753 updateLiveRegister(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700754 }
755 if (scale) {
Ben Chenge9695e52009-06-16 16:11:47 -0700756 newLIR3(cUnit, ARMV5TE_LSL, reg3, reg3, scale);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700757 }
758 /*
Ben Chenge9695e52009-06-16 16:11:47 -0700759 * at this point, reg2 points to array, reg3 is scaled index, and
760 * reg0[reg1] is data
Ben Chengba4fc8b2009-06-01 13:00:29 -0700761 */
762 if (scale==3) {
Ben Chenge9695e52009-06-16 16:11:47 -0700763 newLIR3(cUnit, inst, reg0, reg2, reg3);
764 newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, 4);
765 newLIR3(cUnit, inst, reg1, reg2, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700766 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700767 newLIR3(cUnit, inst, reg0, reg2, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700768 }
769}
770
771static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
772 int vSrc1, int vShift)
773{
Ben Chenge9695e52009-06-16 16:11:47 -0700774 /*
775 * Don't mess with the regsiters here as there is a particular calling
776 * convention to the out-of-line handler.
777 */
778 loadValue(cUnit, vShift, r2);
779 loadValuePair(cUnit, vSrc1, r0, r1);
780 switch( mir->dalvikInsn.opCode) {
781 case OP_SHL_LONG:
782 case OP_SHL_LONG_2ADDR:
783 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
784 break;
785 case OP_SHR_LONG:
786 case OP_SHR_LONG_2ADDR:
787 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
788 break;
789 case OP_USHR_LONG:
790 case OP_USHR_LONG_2ADDR:
791 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
792 break;
793 default:
794 return true;
795 }
796 storeValuePair(cUnit, r0, r1, vDest, r2);
797 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700798}
Bill Buzbeed45ba372009-06-15 17:00:57 -0700799bool dvmCompilerGenArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
800 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700801{
Ben Chenge9695e52009-06-16 16:11:47 -0700802 /*
803 * Don't optimize the regsiter usage here as they are governed by the EABI
804 * calling convention.
805 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700806 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -0700807 int reg0, reg1;
808
Ben Chengba4fc8b2009-06-01 13:00:29 -0700809 /* TODO: use a proper include file to define these */
810 float __aeabi_fadd(float a, float b);
811 float __aeabi_fsub(float a, float b);
812 float __aeabi_fdiv(float a, float b);
813 float __aeabi_fmul(float a, float b);
814 float fmodf(float a, float b);
815
Ben Chenge9695e52009-06-16 16:11:47 -0700816 reg0 = selectFirstRegister(cUnit, vSrc2, false);
817 reg1 = NEXT_REG(reg0);
818
Ben Chengba4fc8b2009-06-01 13:00:29 -0700819 switch (mir->dalvikInsn.opCode) {
820 case OP_ADD_FLOAT_2ADDR:
821 case OP_ADD_FLOAT:
822 funct = (void*) __aeabi_fadd;
823 break;
824 case OP_SUB_FLOAT_2ADDR:
825 case OP_SUB_FLOAT:
826 funct = (void*) __aeabi_fsub;
827 break;
828 case OP_DIV_FLOAT_2ADDR:
829 case OP_DIV_FLOAT:
830 funct = (void*) __aeabi_fdiv;
831 break;
832 case OP_MUL_FLOAT_2ADDR:
833 case OP_MUL_FLOAT:
834 funct = (void*) __aeabi_fmul;
835 break;
836 case OP_REM_FLOAT_2ADDR:
837 case OP_REM_FLOAT:
838 funct = (void*) fmodf;
839 break;
840 case OP_NEG_FLOAT: {
Ben Chenge9695e52009-06-16 16:11:47 -0700841 loadValue(cUnit, vSrc2, reg0);
842 loadConstant(cUnit, reg1, 0x80000000);
843 newLIR3(cUnit, ARMV5TE_ADD_RRR, reg0, reg0, reg1);
844 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700845 return false;
846 }
847 default:
848 return true;
849 }
850 loadConstant(cUnit, r2, (int)funct);
851 loadValue(cUnit, vSrc1, r0);
852 loadValue(cUnit, vSrc2, r1);
853 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
854 storeValue(cUnit, r0, vDest, r1);
855 return false;
856}
857
Bill Buzbeed45ba372009-06-15 17:00:57 -0700858bool dvmCompilerGenArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
859 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700860{
861 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -0700862 int reg0, reg1, reg2;
863
Ben Chengba4fc8b2009-06-01 13:00:29 -0700864 /* TODO: use a proper include file to define these */
865 double __aeabi_dadd(double a, double b);
866 double __aeabi_dsub(double a, double b);
867 double __aeabi_ddiv(double a, double b);
868 double __aeabi_dmul(double a, double b);
869 double fmod(double a, double b);
870
Ben Chenge9695e52009-06-16 16:11:47 -0700871 reg0 = selectFirstRegister(cUnit, vSrc2, true);
872 reg1 = NEXT_REG(reg0);
873 reg2 = NEXT_REG(reg1);
874
Ben Chengba4fc8b2009-06-01 13:00:29 -0700875 switch (mir->dalvikInsn.opCode) {
876 case OP_ADD_DOUBLE_2ADDR:
877 case OP_ADD_DOUBLE:
878 funct = (void*) __aeabi_dadd;
879 break;
880 case OP_SUB_DOUBLE_2ADDR:
881 case OP_SUB_DOUBLE:
882 funct = (void*) __aeabi_dsub;
883 break;
884 case OP_DIV_DOUBLE_2ADDR:
885 case OP_DIV_DOUBLE:
886 funct = (void*) __aeabi_ddiv;
887 break;
888 case OP_MUL_DOUBLE_2ADDR:
889 case OP_MUL_DOUBLE:
890 funct = (void*) __aeabi_dmul;
891 break;
892 case OP_REM_DOUBLE_2ADDR:
893 case OP_REM_DOUBLE:
894 funct = (void*) fmod;
895 break;
896 case OP_NEG_DOUBLE: {
Ben Chenge9695e52009-06-16 16:11:47 -0700897 loadValuePair(cUnit, vSrc2, reg0, reg1);
898 loadConstant(cUnit, reg2, 0x80000000);
899 newLIR3(cUnit, ARMV5TE_ADD_RRR, reg1, reg1, reg2);
900 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700901 return false;
902 }
903 default:
904 return true;
905 }
Ben Chenge9695e52009-06-16 16:11:47 -0700906 /*
907 * Don't optimize the regsiter usage here as they are governed by the EABI
908 * calling convention.
909 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700910 loadConstant(cUnit, r4PC, (int)funct);
911 loadValuePair(cUnit, vSrc1, r0, r1);
912 loadValuePair(cUnit, vSrc2, r2, r3);
913 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
914 storeValuePair(cUnit, r0, r1, vDest, r2);
915 return false;
916}
917
918static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
919 int vSrc1, int vSrc2)
920{
921 int firstOp = ARMV5TE_BKPT;
922 int secondOp = ARMV5TE_BKPT;
923 bool callOut = false;
924 void *callTgt;
925 int retReg = r0;
Ben Chenge9695e52009-06-16 16:11:47 -0700926 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700927 /* TODO - find proper .h file to declare these */
928 long long __aeabi_ldivmod(long long op1, long long op2);
929
930 switch (mir->dalvikInsn.opCode) {
931 case OP_NOT_LONG:
932 firstOp = ARMV5TE_MVN;
933 secondOp = ARMV5TE_MVN;
934 break;
935 case OP_ADD_LONG:
936 case OP_ADD_LONG_2ADDR:
937 firstOp = ARMV5TE_ADD_RRR;
938 secondOp = ARMV5TE_ADC;
939 break;
940 case OP_SUB_LONG:
941 case OP_SUB_LONG_2ADDR:
942 firstOp = ARMV5TE_SUB_RRR;
943 secondOp = ARMV5TE_SBC;
944 break;
945 case OP_MUL_LONG:
946 case OP_MUL_LONG_2ADDR:
947 loadValuePair(cUnit, vSrc1, r0, r1);
948 loadValuePair(cUnit, vSrc2, r2, r3);
949 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
950 storeValuePair(cUnit, r0, r1, vDest, r2);
951 return false;
952 break;
953 case OP_DIV_LONG:
954 case OP_DIV_LONG_2ADDR:
955 callOut = true;
956 retReg = r0;
957 callTgt = (void*)__aeabi_ldivmod;
958 break;
959 /* NOTE - result is in r2/r3 instead of r0/r1 */
960 case OP_REM_LONG:
961 case OP_REM_LONG_2ADDR:
962 callOut = true;
963 callTgt = (void*)__aeabi_ldivmod;
964 retReg = r2;
965 break;
966 case OP_AND_LONG:
967 case OP_AND_LONG_2ADDR:
968 firstOp = ARMV5TE_AND_RR;
969 secondOp = ARMV5TE_AND_RR;
970 break;
971 case OP_OR_LONG:
972 case OP_OR_LONG_2ADDR:
973 firstOp = ARMV5TE_ORR;
974 secondOp = ARMV5TE_ORR;
975 break;
976 case OP_XOR_LONG:
977 case OP_XOR_LONG_2ADDR:
978 firstOp = ARMV5TE_EOR;
979 secondOp = ARMV5TE_EOR;
980 break;
Ben Chenge9695e52009-06-16 16:11:47 -0700981 case OP_NEG_LONG: {
982 reg0 = selectFirstRegister(cUnit, vSrc2, true);
983 reg1 = NEXT_REG(reg0);
984 reg2 = NEXT_REG(reg1);
985 reg3 = NEXT_REG(reg2);
986
987 loadValuePair(cUnit, vSrc2, reg0, reg1);
988 loadConstant(cUnit, reg3, 0);
989 newLIR3(cUnit, ARMV5TE_SUB_RRR, reg2, reg3, reg0);
990 newLIR2(cUnit, ARMV5TE_SBC, reg3, reg1);
Ben Cheng38329f52009-07-07 14:19:20 -0700991 storeValuePair(cUnit, reg2, reg3, vDest, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700992 return false;
Ben Chenge9695e52009-06-16 16:11:47 -0700993 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700994 default:
995 LOGE("Invalid long arith op");
996 dvmAbort();
997 }
998 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -0700999 reg0 = selectFirstRegister(cUnit, vSrc1, true);
1000 reg1 = NEXT_REG(reg0);
1001 reg2 = NEXT_REG(reg1);
1002 reg3 = NEXT_REG(reg2);
1003
1004 loadValuePair(cUnit, vSrc1, reg0, reg1);
1005 loadValuePair(cUnit, vSrc2, reg2, reg3);
1006 genBinaryOpWide(cUnit, vDest, firstOp, secondOp, reg0, reg2);
1007 /*
1008 * Don't optimize the regsiter usage here as they are governed by the EABI
1009 * calling convention.
1010 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001011 } else {
1012 loadValuePair(cUnit, vSrc2, r2, r3);
1013 loadConstant(cUnit, r4PC, (int) callTgt);
1014 loadValuePair(cUnit, vSrc1, r0, r1);
1015 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
1016 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
1017 }
1018 return false;
1019}
1020
1021static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
1022 int vSrc1, int vSrc2)
1023{
1024 int armOp = ARMV5TE_BKPT;
1025 bool callOut = false;
1026 bool checkZero = false;
1027 int retReg = r0;
1028 void *callTgt;
Ben Chenge9695e52009-06-16 16:11:47 -07001029 int reg0, reg1, regDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001030
1031 /* TODO - find proper .h file to declare these */
1032 int __aeabi_idivmod(int op1, int op2);
1033 int __aeabi_idiv(int op1, int op2);
1034
1035 switch (mir->dalvikInsn.opCode) {
1036 case OP_NEG_INT:
1037 armOp = ARMV5TE_NEG;
1038 break;
1039 case OP_NOT_INT:
1040 armOp = ARMV5TE_MVN;
1041 break;
1042 case OP_ADD_INT:
1043 case OP_ADD_INT_2ADDR:
1044 armOp = ARMV5TE_ADD_RRR;
1045 break;
1046 case OP_SUB_INT:
1047 case OP_SUB_INT_2ADDR:
1048 armOp = ARMV5TE_SUB_RRR;
1049 break;
1050 case OP_MUL_INT:
1051 case OP_MUL_INT_2ADDR:
1052 armOp = ARMV5TE_MUL;
1053 break;
1054 case OP_DIV_INT:
1055 case OP_DIV_INT_2ADDR:
1056 callOut = true;
1057 checkZero = true;
1058 callTgt = __aeabi_idiv;
1059 retReg = r0;
1060 break;
1061 /* NOTE: returns in r1 */
1062 case OP_REM_INT:
1063 case OP_REM_INT_2ADDR:
1064 callOut = true;
1065 checkZero = true;
1066 callTgt = __aeabi_idivmod;
1067 retReg = r1;
1068 break;
1069 case OP_AND_INT:
1070 case OP_AND_INT_2ADDR:
1071 armOp = ARMV5TE_AND_RR;
1072 break;
1073 case OP_OR_INT:
1074 case OP_OR_INT_2ADDR:
1075 armOp = ARMV5TE_ORR;
1076 break;
1077 case OP_XOR_INT:
1078 case OP_XOR_INT_2ADDR:
1079 armOp = ARMV5TE_EOR;
1080 break;
1081 case OP_SHL_INT:
1082 case OP_SHL_INT_2ADDR:
1083 armOp = ARMV5TE_LSLV;
1084 break;
1085 case OP_SHR_INT:
1086 case OP_SHR_INT_2ADDR:
1087 armOp = ARMV5TE_ASRV;
1088 break;
1089 case OP_USHR_INT:
1090 case OP_USHR_INT_2ADDR:
1091 armOp = ARMV5TE_LSRV;
1092 break;
1093 default:
1094 LOGE("Invalid word arith op: 0x%x(%d)",
1095 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1096 dvmAbort();
1097 }
1098 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001099 /* Try to allocate reg0 to the currently cached source operand */
1100 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
1101 reg0 = selectFirstRegister(cUnit, vSrc1, false);
1102 reg1 = NEXT_REG(reg0);
1103 regDest = NEXT_REG(reg1);
1104
1105 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
1106 loadValue(cUnit, vSrc2, reg1);
1107 genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
1108 } else {
1109 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1110 reg1 = NEXT_REG(reg0);
1111 regDest = NEXT_REG(reg1);
1112
1113 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
1114 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
1115 genBinaryOp(cUnit, vDest, armOp, reg1, reg0, regDest);
1116 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001117 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001118 /*
1119 * Load the callout target first since it will never be eliminated
1120 * and its value will be used first.
1121 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001122 loadConstant(cUnit, r2, (int) callTgt);
Ben Chenge9695e52009-06-16 16:11:47 -07001123 /*
1124 * Load vSrc2 first if it is not cached in a native register or it
1125 * is in r0 which will be clobbered if vSrc1 is loaded first.
1126 */
1127 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
1128 cUnit->registerScoreboard.nativeReg == r0) {
1129 /* Cannot be optimized and won't clobber r0 */
1130 loadValue(cUnit, vSrc2, r1);
1131 /* May be optimized if vSrc1 is cached */
1132 loadValue(cUnit, vSrc1, r0);
1133 } else {
1134 loadValue(cUnit, vSrc1, r0);
1135 loadValue(cUnit, vSrc2, r1);
1136 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001137 if (checkZero) {
Ben Chenge9695e52009-06-16 16:11:47 -07001138 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001139 }
1140 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1141 storeValue(cUnit, retReg, vDest, r2);
1142 }
1143 return false;
1144}
1145
1146static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
1147{
1148 OpCode opCode = mir->dalvikInsn.opCode;
1149 int vA = mir->dalvikInsn.vA;
1150 int vB = mir->dalvikInsn.vB;
1151 int vC = mir->dalvikInsn.vC;
1152
1153 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
1154 return genArithOpLong(cUnit,mir, vA, vA, vB);
1155 }
1156 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
1157 return genArithOpLong(cUnit,mir, vA, vB, vC);
1158 }
1159 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
1160 return genShiftOpLong(cUnit,mir, vA, vA, vB);
1161 }
1162 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
1163 return genShiftOpLong(cUnit,mir, vA, vB, vC);
1164 }
1165 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
1166 return genArithOpInt(cUnit,mir, vA, vA, vB);
1167 }
1168 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
1169 return genArithOpInt(cUnit,mir, vA, vB, vC);
1170 }
1171 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07001172 return dvmCompilerGenArithOpFloat(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001173 }
1174 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07001175 return dvmCompilerGenArithOpFloat(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001176 }
1177 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07001178 return dvmCompilerGenArithOpDouble(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001179 }
1180 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07001181 return dvmCompilerGenArithOpDouble(cUnit,mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001182 }
1183 return true;
1184}
1185
Bill Buzbeed45ba372009-06-15 17:00:57 -07001186static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1187 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001188{
Ben Chenge9695e52009-06-16 16:11:47 -07001189 /*
1190 * Don't optimize the register usage since it calls out to template
1191 * functions
1192 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001193 loadConstant(cUnit, r2, (int)funct);
1194 if (srcSize == 1) {
1195 loadValue(cUnit, mir->dalvikInsn.vB, r0);
1196 } else {
1197 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
1198 }
1199 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1200 if (tgtSize == 1) {
1201 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1202 } else {
1203 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1204 }
1205 return false;
1206}
1207
1208/* Experimental example of completely inlining a native replacement */
1209static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
1210{
Ben Chenge9695e52009-06-16 16:11:47 -07001211 /* Don't optimize the register usage */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001212 int offset = (int) &((InterpState *) NULL)->retval;
1213 DecodedInstruction *dInsn = &mir->dalvikInsn;
1214 assert(dInsn->vA == 1);
1215 loadValue(cUnit, dInsn->arg[0], r0);
1216 loadConstant(cUnit, r1, gDvm.offJavaLangString_count);
Ben Chenge9695e52009-06-16 16:11:47 -07001217 genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001218 newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r0, r1);
1219 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
1220 return false;
1221}
1222
1223static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1224 DecodedInstruction *dInsn,
1225 Armv5teLIR **pcrLabel)
1226{
1227 unsigned int i;
1228 unsigned int regMask = 0;
1229
1230 /* Load arguments to r0..r4 */
1231 for (i = 0; i < dInsn->vA; i++) {
1232 regMask |= 1 << i;
1233 loadValue(cUnit, dInsn->arg[i], i);
1234 }
1235 if (regMask) {
1236 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
1237 newLIR2(cUnit, ARMV5TE_MOV_RR, r7, rFP);
1238 newLIR2(cUnit, ARMV5TE_SUB_RI8, r7,
1239 sizeof(StackSaveArea) + (dInsn->vA << 2));
1240 /* generate null check */
1241 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001242 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1243 NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001244 }
1245 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1246 }
1247}
1248
1249static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1250 DecodedInstruction *dInsn,
1251 Armv5teLIR **pcrLabel)
1252{
1253 int srcOffset = dInsn->vC << 2;
1254 int numArgs = dInsn->vA;
1255 int regMask;
1256 /*
1257 * r4PC : &rFP[vC]
1258 * r7: &newFP[0]
1259 */
1260 if (srcOffset < 8) {
1261 newLIR3(cUnit, ARMV5TE_ADD_RRI3, r4PC, rFP, srcOffset);
1262 } else {
1263 loadConstant(cUnit, r4PC, srcOffset);
1264 newLIR3(cUnit, ARMV5TE_ADD_RRR, r4PC, rFP, r4PC);
1265 }
1266 /* load [r0 .. min(numArgs,4)] */
1267 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
1268 newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
1269
1270 if (sizeof(StackSaveArea) + (numArgs << 2) < 256) {
1271 newLIR2(cUnit, ARMV5TE_MOV_RR, r7, rFP);
1272 newLIR2(cUnit, ARMV5TE_SUB_RI8, r7,
1273 sizeof(StackSaveArea) + (numArgs << 2));
1274 } else {
1275 loadConstant(cUnit, r7, sizeof(StackSaveArea) + (numArgs << 2));
1276 newLIR3(cUnit, ARMV5TE_SUB_RRR, r7, rFP, r7);
1277 }
1278
1279 /* generate null check */
1280 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001281 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001282 }
1283
1284 /*
1285 * Handle remaining 4n arguments:
1286 * store previously loaded 4 values and load the next 4 values
1287 */
1288 if (numArgs >= 8) {
1289 Armv5teLIR *loopLabel = NULL;
1290 /*
1291 * r0 contains "this" and it will be used later, so push it to the stack
1292 * first. Pushing r5 is just for stack alignment purposes.
1293 */
1294 newLIR1(cUnit, ARMV5TE_PUSH, 1 << r0 | 1 << 5);
1295 /* No need to generate the loop structure if numArgs <= 11 */
1296 if (numArgs > 11) {
1297 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
1298 loopLabel = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
1299 }
1300 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1301 newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
1302 /* No need to generate the loop structure if numArgs <= 11 */
1303 if (numArgs > 11) {
1304 newLIR2(cUnit, ARMV5TE_SUB_RI8, 5, 4);
1305 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1306 }
1307 }
1308
1309 /* Save the last batch of loaded values */
1310 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1311
1312 /* Generate the loop epilogue - don't use r0 */
1313 if ((numArgs > 4) && (numArgs % 4)) {
1314 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
1315 newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
1316 }
1317 if (numArgs >= 8)
1318 newLIR1(cUnit, ARMV5TE_POP, 1 << r0 | 1 << 5);
1319
1320 /* Save the modulo 4 arguments */
1321 if ((numArgs > 4) && (numArgs % 4)) {
1322 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1323 }
1324}
1325
Ben Cheng38329f52009-07-07 14:19:20 -07001326/*
1327 * Generate code to setup the call stack then jump to the chaining cell if it
1328 * is not a native method.
1329 */
1330static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
1331 BasicBlock *bb, Armv5teLIR *labelList,
1332 Armv5teLIR *pcrLabel,
1333 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001334{
1335 Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
1336
1337 /* r1 = &retChainingCell */
Ben Cheng38329f52009-07-07 14:19:20 -07001338 Armv5teLIR *addrRetChain = newLIR3(cUnit, ARMV5TE_ADD_PC_REL,
1339 r1, 0, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001340 /* r4PC = dalvikCallsite */
1341 loadConstant(cUnit, r4PC,
1342 (int) (cUnit->method->insns + mir->offset));
1343 addrRetChain->generic.target = (LIR *) retChainingCell;
1344 /*
Ben Cheng38329f52009-07-07 14:19:20 -07001345 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001346 * r1 = &ChainingCell
1347 * r4PC = callsiteDPC
1348 */
1349 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07001350 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001351#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07001352 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001353#endif
1354 } else {
1355 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1356#if defined(INVOKE_STATS)
1357 gDvmJit.invokeChain++;
1358#endif
Ben Cheng38329f52009-07-07 14:19:20 -07001359 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001360 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1361 }
1362 /* Handle exceptions using the interpreter */
1363 genTrap(cUnit, mir->offset, pcrLabel);
1364}
1365
Ben Cheng38329f52009-07-07 14:19:20 -07001366/*
1367 * Generate code to check the validity of a predicted chain and take actions
1368 * based on the result.
1369 *
1370 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1371 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1372 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1373 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1374 * 0x426a99b2 : blx_2 see above --+
1375 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1376 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1377 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1378 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1379 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1380 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1381 * 0x426a99c0 : blx r7 --+
1382 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1383 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1384 * 0x426a99c6 : blx_2 see above --+
1385 */
1386static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1387 int methodIndex,
1388 Armv5teLIR *retChainingCell,
1389 Armv5teLIR *predChainingCell,
1390 Armv5teLIR *pcrLabel)
1391{
1392 /* "this" is already left in r0 by genProcessArgs* */
1393
1394 /* r4PC = dalvikCallsite */
1395 loadConstant(cUnit, r4PC,
1396 (int) (cUnit->method->insns + mir->offset));
1397
1398 /* r1 = &retChainingCell */
1399 Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
1400 r1, 0);
1401 addrRetChain->generic.target = (LIR *) retChainingCell;
1402
1403 /* r2 = &predictedChainingCell */
1404 Armv5teLIR *predictedChainingCell =
1405 newLIR2(cUnit, ARMV5TE_ADD_PC_REL, r2, 0);
1406 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1407
1408 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1409
1410 /* return through lr - jump to the chaining cell */
1411 genUnconditionalBranch(cUnit, predChainingCell);
1412
1413 /*
1414 * null-check on "this" may have been eliminated, but we still need a PC-
1415 * reconstruction label for stack overflow bailout.
1416 */
1417 if (pcrLabel == NULL) {
1418 int dPC = (int) (cUnit->method->insns + mir->offset);
1419 pcrLabel = dvmCompilerNew(sizeof(Armv5teLIR), true);
1420 pcrLabel->opCode = ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL;
1421 pcrLabel->operands[0] = dPC;
1422 pcrLabel->operands[1] = mir->offset;
1423 /* Insert the place holder to the growable list */
1424 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1425 }
1426
1427 /* return through lr+2 - punt to the interpreter */
1428 genUnconditionalBranch(cUnit, pcrLabel);
1429
1430 /*
1431 * return through lr+4 - fully resolve the callee method.
1432 * r1 <- count
1433 * r2 <- &predictedChainCell
1434 * r3 <- this->class
1435 * r4 <- dPC
1436 * r7 <- this->class->vtable
1437 */
1438
1439 /* r0 <- calleeMethod */
1440 if (methodIndex < 32) {
1441 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r7, methodIndex);
1442 } else {
1443 loadConstant(cUnit, r0, methodIndex<<2);
1444 newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r7, r0);
1445 }
1446
1447 /* Check if rechain limit is reached */
1448 newLIR2(cUnit, ARMV5TE_CMP_RI8, r1, 0);
1449
1450 Armv5teLIR *bypassRechaining =
1451 newLIR2(cUnit, ARMV5TE_B_COND, 0, ARM_COND_GT);
1452
1453 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r7, rGLUE,
1454 offsetof(InterpState,
1455 jitToInterpEntries.dvmJitToPatchPredictedChain)
1456 >> 2);
1457
1458 /*
1459 * r0 = calleeMethod
1460 * r2 = &predictedChainingCell
1461 * r3 = class
1462 *
1463 * &returnChainingCell has been loaded into r1 but is not needed
1464 * when patching the chaining cell and will be clobbered upon
1465 * returning so it will be reconstructed again.
1466 */
1467 newLIR1(cUnit, ARMV5TE_BLX_R, r7);
1468
1469 /* r1 = &retChainingCell */
1470 addrRetChain = newLIR3(cUnit, ARMV5TE_ADD_PC_REL, r1, 0, 0);
1471 addrRetChain->generic.target = (LIR *) retChainingCell;
1472
1473 bypassRechaining->generic.target = (LIR *) addrRetChain;
1474 /*
1475 * r0 = calleeMethod,
1476 * r1 = &ChainingCell,
1477 * r4PC = callsiteDPC,
1478 */
1479 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1480#if defined(INVOKE_STATS)
1481 gDvmJit.invokePredictedChain++;
1482#endif
1483 /* Handle exceptions using the interpreter */
1484 genTrap(cUnit, mir->offset, pcrLabel);
1485}
1486
1487/*
1488 * Up calling this function, "this" is stored in r0. The actual class will be
1489 * chased down off r0 and the predicted one will be retrieved through
1490 * predictedChainingCell then a comparison is performed to see whether the
1491 * previously established chaining is still valid.
1492 *
1493 * The return LIR is a branch based on the comparison result. The actual branch
1494 * target will be setup in the caller.
1495 */
1496static Armv5teLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1497 Armv5teLIR *predChainingCell,
1498 Armv5teLIR *retChainingCell,
1499 MIR *mir)
1500{
1501 /* r3 now contains this->clazz */
1502 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r3, r0,
1503 offsetof(Object, clazz) >> 2);
1504
1505 /*
1506 * r2 now contains predicted class. The starting offset of the
1507 * cached value is 4 bytes into the chaining cell.
1508 */
1509 Armv5teLIR *getPredictedClass =
1510 newLIR3(cUnit, ARMV5TE_LDR_PC_REL, r2, 0,
1511 offsetof(PredictedChainingCell, clazz));
1512 getPredictedClass->generic.target = (LIR *) predChainingCell;
1513
1514 /*
1515 * r0 now contains predicted method. The starting offset of the
1516 * cached value is 8 bytes into the chaining cell.
1517 */
1518 Armv5teLIR *getPredictedMethod =
1519 newLIR3(cUnit, ARMV5TE_LDR_PC_REL, r0, 0,
1520 offsetof(PredictedChainingCell, method));
1521 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1522
1523 /* Load the stats counter to see if it is time to unchain and refresh */
1524 Armv5teLIR *getRechainingRequestCount =
1525 newLIR3(cUnit, ARMV5TE_LDR_PC_REL, r7, 0,
1526 offsetof(PredictedChainingCell, counter));
1527 getRechainingRequestCount->generic.target =
1528 (LIR *) predChainingCell;
1529
1530 /* r4PC = dalvikCallsite */
1531 loadConstant(cUnit, r4PC,
1532 (int) (cUnit->method->insns + mir->offset));
1533
1534 /* r1 = &retChainingCell */
1535 Armv5teLIR *addrRetChain = newLIR3(cUnit, ARMV5TE_ADD_PC_REL,
1536 r1, 0, 0);
1537 addrRetChain->generic.target = (LIR *) retChainingCell;
1538
1539 /* Check if r2 (predicted class) == r3 (actual class) */
1540 newLIR2(cUnit, ARMV5TE_CMP_RR, r2, r3);
1541
1542 return newLIR2(cUnit, ARMV5TE_B_COND, 0, ARM_COND_EQ);
1543}
1544
Ben Chengba4fc8b2009-06-01 13:00:29 -07001545/* Geneate a branch to go back to the interpreter */
1546static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1547{
1548 /* r0 = dalvik pc */
1549 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
1550 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE,
1551 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpPunt) >> 2);
1552 newLIR1(cUnit, ARMV5TE_BLX_R, r1);
1553}
1554
1555/*
1556 * Attempt to single step one instruction using the interpreter and return
1557 * to the compiled code for the next Dalvik instruction
1558 */
1559static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1560{
1561 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1562 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1563 kInstrCanThrow;
1564 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1565 genPuntToInterp(cUnit, mir->offset);
1566 return;
1567 }
1568 int entryAddr = offsetof(InterpState,
1569 jitToInterpEntries.dvmJitToInterpSingleStep);
1570 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r2, rGLUE, entryAddr >> 2);
1571 /* r0 = dalvik pc */
1572 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1573 /* r1 = dalvik pc of following instruction */
1574 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
1575 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1576}
1577
1578
1579/*****************************************************************************/
1580/*
1581 * The following are the first-level codegen routines that analyze the format
1582 * of each bytecode then either dispatch special purpose codegen routines
1583 * or produce corresponding Thumb instructions directly.
1584 */
1585
1586static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
1587 BasicBlock *bb, Armv5teLIR *labelList)
1588{
1589 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1590 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1591 return false;
1592}
1593
1594static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1595{
1596 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1597 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1598 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
1599 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1600 return true;
1601 }
1602 switch (dalvikOpCode) {
1603 case OP_RETURN_VOID:
1604 genReturnCommon(cUnit,mir);
1605 break;
1606 case OP_UNUSED_73:
1607 case OP_UNUSED_79:
1608 case OP_UNUSED_7A:
1609 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1610 return true;
1611 case OP_NOP:
1612 break;
1613 default:
1614 return true;
1615 }
1616 return false;
1617}
1618
1619static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1620{
Ben Chenge9695e52009-06-16 16:11:47 -07001621 int reg0, reg1, reg2;
1622
Ben Chengba4fc8b2009-06-01 13:00:29 -07001623 switch (mir->dalvikInsn.opCode) {
1624 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07001625 case OP_CONST_4: {
1626 /* Avoid using the previously used register */
1627 reg0 = selectFirstRegister(cUnit, vNone, false);
1628 reg1 = NEXT_REG(reg0);
1629 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1630 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001631 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001632 }
1633 case OP_CONST_WIDE_32: {
1634 /* Avoid using the previously used register */
1635 reg0 = selectFirstRegister(cUnit, vNone, true);
1636 reg1 = NEXT_REG(reg0);
1637 reg2 = NEXT_REG(reg1);
1638 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1639 newLIR3(cUnit, ARMV5TE_ASR, reg1, reg0, 31);
1640 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001641 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001642 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001643 default:
1644 return true;
1645 }
1646 return false;
1647}
1648
1649static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1650{
Ben Chenge9695e52009-06-16 16:11:47 -07001651 int reg0, reg1, reg2;
1652
1653 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001654 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07001655 case OP_CONST_HIGH16: {
1656 reg0 = selectFirstRegister(cUnit, vNone, false);
1657 reg1 = NEXT_REG(reg0);
1658 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
1659 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001660 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001661 }
1662 case OP_CONST_WIDE_HIGH16: {
1663 reg0 = selectFirstRegister(cUnit, vNone, true);
1664 reg1 = NEXT_REG(reg0);
1665 reg2 = NEXT_REG(reg1);
1666 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
1667 loadConstant(cUnit, reg0, 0);
1668 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001669 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001670 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001671 default:
1672 return true;
1673 }
1674 return false;
1675}
1676
1677static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1678{
1679 /* For OP_THROW_VERIFICATION_ERROR */
1680 genInterpSingleStep(cUnit, mir);
1681 return false;
1682}
1683
1684static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1685{
Ben Chenge9695e52009-06-16 16:11:47 -07001686 /* Native register to use if the interested value is vA */
1687 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
1688 /* Native register to use if source is not from Dalvik registers */
1689 int regvNone = selectFirstRegister(cUnit, vNone, false);
1690 /* Similar to regvA but for 64-bit values */
1691 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
1692 /* Similar to regvNone but for 64-bit values */
1693 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
1694
Ben Chengba4fc8b2009-06-01 13:00:29 -07001695 switch (mir->dalvikInsn.opCode) {
1696 /*
1697 * TODO: Verify that we can ignore the resolution check here because
1698 * it will have already successfully been interpreted once
1699 */
1700 case OP_CONST_STRING_JUMBO:
1701 case OP_CONST_STRING: {
1702 void *strPtr = (void*)
1703 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1704 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001705 loadConstant(cUnit, regvNone, (int) strPtr );
1706 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001707 break;
1708 }
1709 /*
1710 * TODO: Verify that we can ignore the resolution check here because
1711 * it will have already successfully been interpreted once
1712 */
1713 case OP_CONST_CLASS: {
1714 void *classPtr = (void*)
1715 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1716 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001717 loadConstant(cUnit, regvNone, (int) classPtr );
1718 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001719 break;
1720 }
1721 case OP_SGET_OBJECT:
1722 case OP_SGET_BOOLEAN:
1723 case OP_SGET_CHAR:
1724 case OP_SGET_BYTE:
1725 case OP_SGET_SHORT:
1726 case OP_SGET: {
1727 int valOffset = (int)&((struct StaticField*)NULL)->value;
1728 void *fieldPtr = (void*)
1729 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1730 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001731 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
1732 newLIR3(cUnit, ARMV5TE_LDR_RRI5, regvNone, regvNone, 0);
1733 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001734 break;
1735 }
1736 case OP_SGET_WIDE: {
1737 int valOffset = (int)&((struct StaticField*)NULL)->value;
1738 void *fieldPtr = (void*)
1739 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001740 int reg0, reg1, reg2;
1741
Ben Chengba4fc8b2009-06-01 13:00:29 -07001742 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001743 reg0 = regvNoneWide;
1744 reg1 = NEXT_REG(reg0);
1745 reg2 = NEXT_REG(reg1);
1746 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
1747 newLIR2(cUnit, ARMV5TE_LDMIA, reg2, (1<<reg0 | 1<<reg1));
1748 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001749 break;
1750 }
1751 case OP_SPUT_OBJECT:
1752 case OP_SPUT_BOOLEAN:
1753 case OP_SPUT_CHAR:
1754 case OP_SPUT_BYTE:
1755 case OP_SPUT_SHORT:
1756 case OP_SPUT: {
1757 int valOffset = (int)&((struct StaticField*)NULL)->value;
1758 void *fieldPtr = (void*)
1759 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001760
Ben Chengba4fc8b2009-06-01 13:00:29 -07001761 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001762 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
1763 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
1764 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
1765 newLIR3(cUnit, ARMV5TE_STR_RRI5, regvA, NEXT_REG(regvA), 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001766 break;
1767 }
1768 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001769 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001770 int valOffset = (int)&((struct StaticField*)NULL)->value;
1771 void *fieldPtr = (void*)
1772 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001773
Ben Chengba4fc8b2009-06-01 13:00:29 -07001774 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001775 reg0 = regvAWide;
1776 reg1 = NEXT_REG(reg0);
1777 reg2 = NEXT_REG(reg1);
1778 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
1779 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
1780 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
1781 newLIR2(cUnit, ARMV5TE_STMIA, reg2, (1<<reg0 | 1<<reg1));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001782 break;
1783 }
1784 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001785 /*
1786 * Obey the calling convention and don't mess with the register
1787 * usage.
1788 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001789 ClassObject *classPtr = (void*)
1790 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1791 assert(classPtr != NULL);
1792 assert(classPtr->status & CLASS_INITIALIZED);
1793 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
1794 /* It's going to throw, just let the interp. deal with it. */
1795 genInterpSingleStep(cUnit, mir);
1796 return false;
1797 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001798 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07001799 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001800 genExportPC(cUnit, mir, r2, r3 );
1801 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
1802 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
1803 /*
1804 * TODO: As coded, we'll bail and reinterpret on alloc failure.
1805 * Need a general mechanism to bail to thrown exception code.
1806 */
Ben Chenge9695e52009-06-16 16:11:47 -07001807 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001808 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1809 break;
1810 }
1811 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07001812 /*
1813 * Obey the calling convention and don't mess with the register
1814 * usage.
1815 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001816 ClassObject *classPtr =
1817 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1818 loadConstant(cUnit, r1, (int) classPtr );
1819 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
1820 /*
1821 * TODO - in theory classPtr should be resoved by the time this
1822 * instruction made into a trace, but we are seeing NULL at runtime
1823 * so this check is temporarily used as a workaround.
1824 */
Ben Chenge9695e52009-06-16 16:11:47 -07001825 Armv5teLIR * pcrLabel = genZeroCheck(cUnit, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001826 newLIR2(cUnit, ARMV5TE_CMP_RI8, r0, 0); /* Null? */
1827 Armv5teLIR *branch1 =
1828 newLIR2(cUnit, ARMV5TE_B_COND, 4, ARM_COND_EQ);
1829 /* r0 now contains object->clazz */
1830 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
1831 offsetof(Object, clazz) >> 2);
1832 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
1833 newLIR2(cUnit, ARMV5TE_CMP_RR, r0, r1);
1834 Armv5teLIR *branch2 =
1835 newLIR2(cUnit, ARMV5TE_B_COND, 2, ARM_COND_EQ);
1836 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
1837 /* check cast failed - punt to the interpreter */
Ben Chenge9695e52009-06-16 16:11:47 -07001838 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001839 /* check cast passed - branch target here */
1840 Armv5teLIR *target = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
1841 branch1->generic.target = (LIR *)target;
1842 branch2->generic.target = (LIR *)target;
1843 break;
1844 }
1845 default:
1846 return true;
1847 }
1848 return false;
1849}
1850
1851static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1852{
1853 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1854 switch (dalvikOpCode) {
1855 case OP_MOVE_EXCEPTION: {
1856 int offset = offsetof(InterpState, self);
1857 int exOffset = offsetof(Thread, exception);
Ben Chenge9695e52009-06-16 16:11:47 -07001858 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE, offset >> 2);
1859 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r1, exOffset >> 2);
1860 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001861 break;
1862 }
1863 case OP_MOVE_RESULT:
1864 case OP_MOVE_RESULT_OBJECT: {
1865 int offset = offsetof(InterpState, retval);
1866 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
1867 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1868 break;
1869 }
1870 case OP_MOVE_RESULT_WIDE: {
1871 int offset = offsetof(InterpState, retval);
1872 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
1873 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE, (offset >> 2)+1);
1874 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1875 break;
1876 }
1877 case OP_RETURN_WIDE: {
1878 loadValuePair(cUnit, mir->dalvikInsn.vA, r0, r1);
1879 int offset = offsetof(InterpState, retval);
1880 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
1881 newLIR3(cUnit, ARMV5TE_STR_RRI5, r1, rGLUE, (offset >> 2)+1);
1882 genReturnCommon(cUnit,mir);
1883 break;
1884 }
1885 case OP_RETURN:
1886 case OP_RETURN_OBJECT: {
1887 loadValue(cUnit, mir->dalvikInsn.vA, r0);
1888 int offset = offsetof(InterpState, retval);
1889 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
1890 genReturnCommon(cUnit,mir);
1891 break;
1892 }
1893 /*
1894 * TODO-VERIFY: May be playing a bit fast and loose here. As coded,
1895 * a failure on lock/unlock will cause us to revert to the interpeter
1896 * to try again. This means we essentially ignore the first failure on
1897 * the assumption that the interpreter will correctly handle the 2nd.
1898 */
1899 case OP_MONITOR_ENTER:
1900 case OP_MONITOR_EXIT: {
1901 int offset = offsetof(InterpState, self);
1902 loadValue(cUnit, mir->dalvikInsn.vA, r1);
1903 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
1904 if (dalvikOpCode == OP_MONITOR_ENTER) {
1905 loadConstant(cUnit, r2, (int)dvmLockObject);
1906 } else {
1907 loadConstant(cUnit, r2, (int)dvmUnlockObject);
1908 }
1909 /*
1910 * TODO-VERIFY: Note that we're not doing an EXPORT_PC, as
1911 * Lock/unlock won't throw, and this code does not support
1912 * DEADLOCK_PREDICTION or MONITOR_TRACKING. Should it?
1913 */
Ben Chenge9695e52009-06-16 16:11:47 -07001914 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001915 /* Do the call */
1916 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1917 break;
1918 }
1919 case OP_THROW: {
1920 genInterpSingleStep(cUnit, mir);
1921 break;
1922 }
1923 default:
1924 return true;
1925 }
1926 return false;
1927}
1928
Bill Buzbeed45ba372009-06-15 17:00:57 -07001929bool dvmCompilerGenConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001930{
1931 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001932
Ben Chengba4fc8b2009-06-01 13:00:29 -07001933 float __aeabi_i2f( int op1 );
1934 int __aeabi_f2iz( float op1 );
1935 float __aeabi_d2f( double op1 );
1936 double __aeabi_f2d( float op1 );
1937 double __aeabi_i2d( int op1 );
1938 int __aeabi_d2iz( double op1 );
1939 long __aeabi_f2lz( float op1 );
1940 float __aeabi_l2f( long op1 );
1941 long __aeabi_d2lz( double op1 );
1942 double __aeabi_l2d( long op1 );
1943
Bill Buzbeed45ba372009-06-15 17:00:57 -07001944 switch (opCode) {
1945 case OP_INT_TO_FLOAT:
1946 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
1947 case OP_FLOAT_TO_INT:
1948 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
1949 case OP_DOUBLE_TO_FLOAT:
1950 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
1951 case OP_FLOAT_TO_DOUBLE:
1952 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
1953 case OP_INT_TO_DOUBLE:
1954 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
1955 case OP_DOUBLE_TO_INT:
1956 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
1957 case OP_FLOAT_TO_LONG:
1958 return genConversionCall(cUnit, mir, (void*)__aeabi_f2lz, 1, 2);
1959 case OP_LONG_TO_FLOAT:
1960 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
1961 case OP_DOUBLE_TO_LONG:
1962 return genConversionCall(cUnit, mir, (void*)__aeabi_d2lz, 2, 2);
1963 case OP_LONG_TO_DOUBLE:
1964 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
1965 default:
1966 return true;
1967 }
1968 return false;
1969}
1970
1971static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1972{
1973 OpCode opCode = mir->dalvikInsn.opCode;
1974 int vSrc1Dest = mir->dalvikInsn.vA;
1975 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07001976 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07001977
1978 /* TODO - find the proper include file to declare these */
1979
Ben Chengba4fc8b2009-06-01 13:00:29 -07001980 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1981 return genArithOp( cUnit, mir );
1982 }
1983
Ben Chenge9695e52009-06-16 16:11:47 -07001984 /*
1985 * If data type is 64-bit, re-calculate the register numbers in the
1986 * corresponding cases.
1987 */
1988 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1989 reg1 = NEXT_REG(reg0);
1990 reg2 = NEXT_REG(reg1);
1991
Ben Chengba4fc8b2009-06-01 13:00:29 -07001992 switch (opCode) {
1993 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001994 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001995 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001996 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001997 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001998 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001999 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002000 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002001 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002002 case OP_LONG_TO_DOUBLE:
Bill Buzbeed45ba372009-06-15 17:00:57 -07002003 return dvmCompilerGenConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002004 case OP_NEG_INT:
2005 case OP_NOT_INT:
2006 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2007 case OP_NEG_LONG:
2008 case OP_NOT_LONG:
2009 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
2010 case OP_NEG_FLOAT:
Bill Buzbeed45ba372009-06-15 17:00:57 -07002011 return dvmCompilerGenArithOpFloat(cUnit, mir, vSrc1Dest,
2012 vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002013 case OP_NEG_DOUBLE:
Bill Buzbeed45ba372009-06-15 17:00:57 -07002014 return dvmCompilerGenArithOpDouble(cUnit, mir, vSrc1Dest,
2015 vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07002016 case OP_MOVE_WIDE: {
2017 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2018 reg1 = NEXT_REG(reg0);
2019 reg2 = NEXT_REG(reg1);
2020
2021 loadValuePair(cUnit, vSrc2, reg0, reg1);
2022 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002023 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002024 }
2025 case OP_INT_TO_LONG: {
2026 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2027 reg1 = NEXT_REG(reg0);
2028 reg2 = NEXT_REG(reg1);
2029
2030 loadValue(cUnit, mir->dalvikInsn.vB, reg0);
2031 newLIR3(cUnit, ARMV5TE_ASR, reg1, reg0, 31);
2032 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002033 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002034 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002035 case OP_MOVE:
2036 case OP_MOVE_OBJECT:
2037 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002038 loadValue(cUnit, vSrc2, reg0);
2039 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002040 break;
2041 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07002042 loadValue(cUnit, vSrc2, reg0);
2043 newLIR3(cUnit, ARMV5TE_LSL, reg0, reg0, 24);
2044 newLIR3(cUnit, ARMV5TE_ASR, reg0, reg0, 24);
2045 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002046 break;
2047 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07002048 loadValue(cUnit, vSrc2, reg0);
2049 newLIR3(cUnit, ARMV5TE_LSL, reg0, reg0, 16);
2050 newLIR3(cUnit, ARMV5TE_ASR, reg0, reg0, 16);
2051 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002052 break;
2053 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07002054 loadValue(cUnit, vSrc2, reg0);
2055 newLIR3(cUnit, ARMV5TE_LSL, reg0, reg0, 16);
2056 newLIR3(cUnit, ARMV5TE_LSR, reg0, reg0, 16);
2057 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002058 break;
2059 case OP_ARRAY_LENGTH: {
2060 int lenOffset = offsetof(ArrayObject, length);
Ben Chenge9695e52009-06-16 16:11:47 -07002061 loadValue(cUnit, vSrc2, reg0);
2062 genNullCheck(cUnit, vSrc2, reg0, mir->offset, NULL);
2063 newLIR3(cUnit, ARMV5TE_LDR_RRI5, reg0, reg0, lenOffset >> 2);
2064 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002065 break;
2066 }
2067 default:
2068 return true;
2069 }
2070 return false;
2071}
2072
2073static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2074{
2075 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07002076 int reg0, reg1, reg2;
2077
Ben Chengba4fc8b2009-06-01 13:00:29 -07002078 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
2079 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002080 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002081 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002082
2083 reg0 = selectFirstRegister(cUnit, vNone, true);
2084 reg1 = NEXT_REG(reg0);
2085 reg2 = NEXT_REG(reg1);
2086
2087 loadConstant(cUnit, reg0, BBBB);
2088 loadConstant(cUnit, reg1, 0);
2089 if (BBBB < 0) {
2090 newLIR2(cUnit, ARMV5TE_SUB_RI8, reg1, -1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002091 }
2092
2093 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07002094 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002095 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002096 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002097 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002098
Ben Chenge9695e52009-06-16 16:11:47 -07002099 reg0 = selectFirstRegister(cUnit, vNone, false);
2100 reg1 = NEXT_REG(reg0);
2101
2102 loadConstant(cUnit, reg0, BBBB);
2103 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002104 } else {
2105 return true;
2106 }
2107 return false;
2108}
2109
2110/* Compare agaist zero */
2111static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2112 Armv5teLIR *labelList)
2113{
2114 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2115 Armv5teConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002116 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002117
Ben Chenge9695e52009-06-16 16:11:47 -07002118 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2119 newLIR2(cUnit, ARMV5TE_CMP_RI8, reg0, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002120
2121 switch (dalvikOpCode) {
2122 case OP_IF_EQZ:
2123 cond = ARM_COND_EQ;
2124 break;
2125 case OP_IF_NEZ:
2126 cond = ARM_COND_NE;
2127 break;
2128 case OP_IF_LTZ:
2129 cond = ARM_COND_LT;
2130 break;
2131 case OP_IF_GEZ:
2132 cond = ARM_COND_GE;
2133 break;
2134 case OP_IF_GTZ:
2135 cond = ARM_COND_GT;
2136 break;
2137 case OP_IF_LEZ:
2138 cond = ARM_COND_LE;
2139 break;
2140 default:
2141 cond = 0;
2142 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2143 dvmAbort();
2144 }
2145 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2146 /* This mostly likely will be optimized away in a later phase */
2147 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2148 return false;
2149}
2150
2151static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2152{
2153 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2154 int vSrc = mir->dalvikInsn.vB;
2155 int vDest = mir->dalvikInsn.vA;
2156 int lit = mir->dalvikInsn.vC;
2157 int armOp;
Ben Chenge9695e52009-06-16 16:11:47 -07002158 int reg0, reg1, regDest;
2159
2160 reg0 = selectFirstRegister(cUnit, vSrc, false);
2161 reg1 = NEXT_REG(reg0);
2162 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002163
2164 /* TODO: find the proper .h file to declare these */
2165 int __aeabi_idivmod(int op1, int op2);
2166 int __aeabi_idiv(int op1, int op2);
2167
2168 switch (dalvikOpCode) {
2169 case OP_ADD_INT_LIT8:
2170 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002171 loadValue(cUnit, vSrc, reg0);
2172 if (lit <= 7 && lit >= 0) {
2173 newLIR3(cUnit, ARMV5TE_ADD_RRI3, regDest, reg0, lit);
2174 storeValue(cUnit, regDest, vDest, reg1);
2175 } else if (lit <= 255 && lit >= 0) {
2176 newLIR2(cUnit, ARMV5TE_ADD_RI8, reg0, lit);
2177 storeValue(cUnit, reg0, vDest, reg1);
2178 } else if (lit >= -7 && lit <= 0) {
2179 /* Convert to a small constant subtraction */
2180 newLIR3(cUnit, ARMV5TE_SUB_RRI3, regDest, reg0, -lit);
2181 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002182 } else if (lit >= -255 && lit <= 0) {
2183 /* Convert to a small constant subtraction */
Ben Chenge9695e52009-06-16 16:11:47 -07002184 newLIR2(cUnit, ARMV5TE_SUB_RI8, reg0, -lit);
2185 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002186 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07002187 loadConstant(cUnit, reg1, lit);
2188 genBinaryOp(cUnit, vDest, ARMV5TE_ADD_RRR, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002189 }
2190 break;
2191
2192 case OP_RSUB_INT_LIT8:
2193 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002194 loadValue(cUnit, vSrc, reg1);
2195 loadConstant(cUnit, reg0, lit);
2196 genBinaryOp(cUnit, vDest, ARMV5TE_SUB_RRR, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002197 break;
2198
2199 case OP_MUL_INT_LIT8:
2200 case OP_MUL_INT_LIT16:
2201 case OP_AND_INT_LIT8:
2202 case OP_AND_INT_LIT16:
2203 case OP_OR_INT_LIT8:
2204 case OP_OR_INT_LIT16:
2205 case OP_XOR_INT_LIT8:
2206 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002207 loadValue(cUnit, vSrc, reg0);
2208 loadConstant(cUnit, reg1, lit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002209 switch (dalvikOpCode) {
2210 case OP_MUL_INT_LIT8:
2211 case OP_MUL_INT_LIT16:
2212 armOp = ARMV5TE_MUL;
2213 break;
2214 case OP_AND_INT_LIT8:
2215 case OP_AND_INT_LIT16:
2216 armOp = ARMV5TE_AND_RR;
2217 break;
2218 case OP_OR_INT_LIT8:
2219 case OP_OR_INT_LIT16:
2220 armOp = ARMV5TE_ORR;
2221 break;
2222 case OP_XOR_INT_LIT8:
2223 case OP_XOR_INT_LIT16:
2224 armOp = ARMV5TE_EOR;
2225 break;
2226 default:
2227 dvmAbort();
2228 }
Ben Chenge9695e52009-06-16 16:11:47 -07002229 genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002230 break;
2231
2232 case OP_SHL_INT_LIT8:
2233 case OP_SHR_INT_LIT8:
2234 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002235 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002236 switch (dalvikOpCode) {
2237 case OP_SHL_INT_LIT8:
2238 armOp = ARMV5TE_LSL;
2239 break;
2240 case OP_SHR_INT_LIT8:
2241 armOp = ARMV5TE_ASR;
2242 break;
2243 case OP_USHR_INT_LIT8:
2244 armOp = ARMV5TE_LSR;
2245 break;
2246 default: dvmAbort();
2247 }
Ben Chenge9695e52009-06-16 16:11:47 -07002248 newLIR3(cUnit, armOp, reg0, reg0, lit);
2249 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002250 break;
2251
2252 case OP_DIV_INT_LIT8:
2253 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002254 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002255 if (lit == 0) {
2256 /* Let the interpreter deal with div by 0 */
2257 genInterpSingleStep(cUnit, mir);
2258 return false;
2259 }
2260 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2261 loadConstant(cUnit, r1, lit);
2262 loadValue(cUnit, vSrc, r0);
2263 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
2264 storeValue(cUnit, r0, vDest, r2);
2265 break;
2266
2267 case OP_REM_INT_LIT8:
2268 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002269 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002270 if (lit == 0) {
2271 /* Let the interpreter deal with div by 0 */
2272 genInterpSingleStep(cUnit, mir);
2273 return false;
2274 }
2275 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2276 loadConstant(cUnit, r1, lit);
2277 loadValue(cUnit, vSrc, r0);
2278 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
2279 storeValue(cUnit, r1, vDest, r2);
2280 break;
2281 default:
2282 return true;
2283 }
2284 return false;
2285}
2286
2287static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2288{
2289 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2290 int fieldOffset;
2291
2292 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2293 InstField *pInstField = (InstField *)
2294 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2295 int fieldOffset;
2296
2297 assert(pInstField != NULL);
2298 fieldOffset = pInstField->byteOffset;
2299 } else {
2300 /* To make the compiler happy */
2301 fieldOffset = 0;
2302 }
2303 switch (dalvikOpCode) {
2304 /*
2305 * TODO: I may be assuming too much here.
2306 * Verify what is known at JIT time.
2307 */
2308 case OP_NEW_ARRAY: {
2309 void *classPtr = (void*)
2310 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2311 assert(classPtr != NULL);
2312 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2313 loadConstant(cUnit, r0, (int) classPtr );
2314 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
2315 Armv5teLIR *pcrLabel =
2316 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2317 genExportPC(cUnit, mir, r2, r3 );
2318 newLIR2(cUnit, ARMV5TE_MOV_IMM,r2,ALLOC_DONT_TRACK);
2319 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
2320 /*
2321 * TODO: As coded, we'll bail and reinterpret on alloc failure.
2322 * Need a general mechanism to bail to thrown exception code.
2323 */
Ben Chenge9695e52009-06-16 16:11:47 -07002324 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002325 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2326 break;
2327 }
2328 /*
2329 * TODO: I may be assuming too much here.
2330 * Verify what is known at JIT time.
2331 */
2332 case OP_INSTANCE_OF: {
2333 ClassObject *classPtr =
2334 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2335 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002336 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002337 loadConstant(cUnit, r2, (int) classPtr );
Ben Cheng752c7942009-06-22 10:50:07 -07002338 newLIR2(cUnit, ARMV5TE_CMP_RI8, r0, 0); /* Null? */
2339 /* When taken r0 has NULL which can be used for store directly */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002340 Armv5teLIR *branch1 = newLIR2(cUnit, ARMV5TE_B_COND, 4,
2341 ARM_COND_EQ);
2342 /* r1 now contains object->clazz */
Ben Cheng752c7942009-06-22 10:50:07 -07002343 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, r0,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002344 offsetof(Object, clazz) >> 2);
2345 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002346 loadConstant(cUnit, r0, 1); /* Assume true */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002347 newLIR2(cUnit, ARMV5TE_CMP_RR, r1, r2);
2348 Armv5teLIR *branch2 = newLIR2(cUnit, ARMV5TE_B_COND, 2,
2349 ARM_COND_EQ);
2350 newLIR2(cUnit, ARMV5TE_MOV_RR, r0, r1);
2351 newLIR2(cUnit, ARMV5TE_MOV_RR, r1, r2);
2352 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
2353 /* branch target here */
2354 Armv5teLIR *target = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
2355 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2356 branch1->generic.target = (LIR *)target;
2357 branch2->generic.target = (LIR *)target;
2358 break;
2359 }
2360 case OP_IGET_WIDE:
2361 genIGetWide(cUnit, mir, fieldOffset);
2362 break;
2363 case OP_IGET:
2364 case OP_IGET_OBJECT:
2365 genIGet(cUnit, mir, ARMV5TE_LDR_RRR, fieldOffset);
2366 break;
2367 case OP_IGET_BOOLEAN:
2368 genIGet(cUnit, mir, ARMV5TE_LDRB_RRR, fieldOffset);
2369 break;
2370 case OP_IGET_BYTE:
2371 genIGet(cUnit, mir, ARMV5TE_LDRSB_RRR, fieldOffset);
2372 break;
2373 case OP_IGET_CHAR:
2374 genIGet(cUnit, mir, ARMV5TE_LDRH_RRR, fieldOffset);
2375 break;
2376 case OP_IGET_SHORT:
2377 genIGet(cUnit, mir, ARMV5TE_LDRSH_RRR, fieldOffset);
2378 break;
2379 case OP_IPUT_WIDE:
2380 genIPutWide(cUnit, mir, fieldOffset);
2381 break;
2382 case OP_IPUT:
2383 case OP_IPUT_OBJECT:
2384 genIPut(cUnit, mir, ARMV5TE_STR_RRR, fieldOffset);
2385 break;
2386 case OP_IPUT_SHORT:
2387 case OP_IPUT_CHAR:
2388 genIPut(cUnit, mir, ARMV5TE_STRH_RRR, fieldOffset);
2389 break;
2390 case OP_IPUT_BYTE:
2391 case OP_IPUT_BOOLEAN:
2392 genIPut(cUnit, mir, ARMV5TE_STRB_RRR, fieldOffset);
2393 break;
2394 default:
2395 return true;
2396 }
2397 return false;
2398}
2399
2400static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2401{
2402 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2403 int fieldOffset = mir->dalvikInsn.vC;
2404 switch (dalvikOpCode) {
2405 case OP_IGET_QUICK:
2406 case OP_IGET_OBJECT_QUICK:
2407 genIGet(cUnit, mir, ARMV5TE_LDR_RRR, fieldOffset);
2408 break;
2409 case OP_IPUT_QUICK:
2410 case OP_IPUT_OBJECT_QUICK:
2411 genIPut(cUnit, mir, ARMV5TE_STR_RRR, fieldOffset);
2412 break;
2413 case OP_IGET_WIDE_QUICK:
2414 genIGetWide(cUnit, mir, fieldOffset);
2415 break;
2416 case OP_IPUT_WIDE_QUICK:
2417 genIPutWide(cUnit, mir, fieldOffset);
2418 break;
2419 default:
2420 return true;
2421 }
2422 return false;
2423
2424}
2425
2426/* Compare agaist zero */
2427static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2428 Armv5teLIR *labelList)
2429{
2430 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2431 Armv5teConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002432 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002433
Ben Chenge9695e52009-06-16 16:11:47 -07002434 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2435 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2436 reg1 = NEXT_REG(reg0);
2437 /* Load vB first since vA can be fetched via a move */
2438 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2439 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2440 } else {
2441 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2442 reg1 = NEXT_REG(reg0);
2443 /* Load vA first since vB can be fetched via a move */
2444 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2445 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2446 }
2447 newLIR2(cUnit, ARMV5TE_CMP_RR, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002448
2449 switch (dalvikOpCode) {
2450 case OP_IF_EQ:
2451 cond = ARM_COND_EQ;
2452 break;
2453 case OP_IF_NE:
2454 cond = ARM_COND_NE;
2455 break;
2456 case OP_IF_LT:
2457 cond = ARM_COND_LT;
2458 break;
2459 case OP_IF_GE:
2460 cond = ARM_COND_GE;
2461 break;
2462 case OP_IF_GT:
2463 cond = ARM_COND_GT;
2464 break;
2465 case OP_IF_LE:
2466 cond = ARM_COND_LE;
2467 break;
2468 default:
2469 cond = 0;
2470 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2471 dvmAbort();
2472 }
2473 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2474 /* This mostly likely will be optimized away in a later phase */
2475 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2476 return false;
2477}
2478
2479static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2480{
2481 OpCode opCode = mir->dalvikInsn.opCode;
2482 int vSrc1Dest = mir->dalvikInsn.vA;
2483 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002484 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002485
2486 switch (opCode) {
2487 case OP_MOVE_16:
2488 case OP_MOVE_OBJECT_16:
2489 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002490 case OP_MOVE_OBJECT_FROM16: {
2491 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2492 reg1 = NEXT_REG(reg0);
2493 loadValue(cUnit, vSrc2, reg0);
2494 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002495 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002496 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002497 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002498 case OP_MOVE_WIDE_FROM16: {
2499 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2500 reg1 = NEXT_REG(reg0);
2501 reg2 = NEXT_REG(reg1);
2502 loadValuePair(cUnit, vSrc2, reg0, reg1);
2503 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002504 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002505 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002506 default:
2507 return true;
2508 }
2509 return false;
2510}
2511
2512static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2513{
2514 OpCode opCode = mir->dalvikInsn.opCode;
2515 int vA = mir->dalvikInsn.vA;
2516 int vB = mir->dalvikInsn.vB;
2517 int vC = mir->dalvikInsn.vC;
2518
Ben Chenge9695e52009-06-16 16:11:47 -07002519 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002520 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2521 return genArithOp( cUnit, mir );
2522 }
2523
2524 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002525 case OP_CMPL_FLOAT:
2526 case OP_CMPG_FLOAT:
2527 case OP_CMPL_DOUBLE:
2528 case OP_CMPG_DOUBLE:
2529 return dvmCompilerGenCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002530 case OP_CMP_LONG:
2531 loadValuePair(cUnit,vB, r0, r1);
2532 loadValuePair(cUnit, vC, r2, r3);
2533 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
2534 storeValue(cUnit, r0, vA, r1);
2535 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002536 case OP_AGET_WIDE:
2537 genArrayGet(cUnit, mir, ARMV5TE_LDR_RRR, vB, vC, vA, 3);
2538 break;
2539 case OP_AGET:
2540 case OP_AGET_OBJECT:
2541 genArrayGet(cUnit, mir, ARMV5TE_LDR_RRR, vB, vC, vA, 2);
2542 break;
2543 case OP_AGET_BOOLEAN:
2544 genArrayGet(cUnit, mir, ARMV5TE_LDRB_RRR, vB, vC, vA, 0);
2545 break;
2546 case OP_AGET_BYTE:
2547 genArrayGet(cUnit, mir, ARMV5TE_LDRSB_RRR, vB, vC, vA, 0);
2548 break;
2549 case OP_AGET_CHAR:
2550 genArrayGet(cUnit, mir, ARMV5TE_LDRH_RRR, vB, vC, vA, 1);
2551 break;
2552 case OP_AGET_SHORT:
2553 genArrayGet(cUnit, mir, ARMV5TE_LDRSH_RRR, vB, vC, vA, 1);
2554 break;
2555 case OP_APUT_WIDE:
2556 genArrayPut(cUnit, mir, ARMV5TE_STR_RRR, vB, vC, vA, 3);
2557 break;
2558 case OP_APUT:
2559 case OP_APUT_OBJECT:
2560 genArrayPut(cUnit, mir, ARMV5TE_STR_RRR, vB, vC, vA, 2);
2561 break;
2562 case OP_APUT_SHORT:
2563 case OP_APUT_CHAR:
2564 genArrayPut(cUnit, mir, ARMV5TE_STRH_RRR, vB, vC, vA, 1);
2565 break;
2566 case OP_APUT_BYTE:
2567 case OP_APUT_BOOLEAN:
2568 genArrayPut(cUnit, mir, ARMV5TE_STRB_RRR, vB, vC, vA, 0);
2569 break;
2570 default:
2571 return true;
2572 }
2573 return false;
2574}
2575
2576static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2577{
2578 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2579 switch (dalvikOpCode) {
2580 case OP_FILL_ARRAY_DATA: {
2581 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2582 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2583 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2584 (int) (cUnit->method->insns + mir->offset));
2585 genExportPC(cUnit, mir, r2, r3 );
2586 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002587 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002588 break;
2589 }
2590 /*
2591 * TODO
2592 * - Add a 1 to 3-entry per-location cache here to completely
2593 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2594 * - Use out-of-line handlers for both of these
2595 */
2596 case OP_PACKED_SWITCH:
2597 case OP_SPARSE_SWITCH: {
2598 if (dalvikOpCode == OP_PACKED_SWITCH) {
2599 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2600 } else {
2601 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2602 }
2603 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2604 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2605 (int) (cUnit->method->insns + mir->offset));
2606 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
2607 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
2608 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r2, rGLUE,
2609 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNoChain)
2610 >> 2);
2611 newLIR3(cUnit, ARMV5TE_ADD_RRR, r0, r0, r0);
2612 newLIR3(cUnit, ARMV5TE_ADD_RRR, r4PC, r0, r1);
2613 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
2614 break;
2615 }
2616 default:
2617 return true;
2618 }
2619 return false;
2620}
2621
2622static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2623 Armv5teLIR *labelList)
2624{
2625 Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
2626 Armv5teLIR *pcrLabel = NULL;
2627
2628 DecodedInstruction *dInsn = &mir->dalvikInsn;
2629 switch (mir->dalvikInsn.opCode) {
2630 /*
2631 * calleeMethod = this->clazz->vtable[
2632 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2633 * ]
2634 */
2635 case OP_INVOKE_VIRTUAL:
2636 case OP_INVOKE_VIRTUAL_RANGE: {
Ben Cheng38329f52009-07-07 14:19:20 -07002637 Armv5teLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002638 int methodIndex =
2639 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2640 methodIndex;
2641
2642 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2643 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2644 else
2645 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2646
Ben Cheng38329f52009-07-07 14:19:20 -07002647 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2648 retChainingCell,
2649 predChainingCell,
2650 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002651 break;
2652 }
2653 /*
2654 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2655 * ->pResMethods[BBBB]->methodIndex]
2656 */
2657 /* TODO - not excersized in RunPerf.jar */
2658 case OP_INVOKE_SUPER:
2659 case OP_INVOKE_SUPER_RANGE: {
2660 int mIndex = cUnit->method->clazz->pDvmDex->
2661 pResMethods[dInsn->vB]->methodIndex;
2662 const Method *calleeMethod =
2663 cUnit->method->clazz->super->vtable[mIndex];
2664
2665 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2666 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2667 else
2668 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2669
2670 /* r0 = calleeMethod */
2671 loadConstant(cUnit, r0, (int) calleeMethod);
2672
Ben Cheng38329f52009-07-07 14:19:20 -07002673 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2674 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002675 break;
2676 }
2677 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2678 case OP_INVOKE_DIRECT:
2679 case OP_INVOKE_DIRECT_RANGE: {
2680 const Method *calleeMethod =
2681 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2682
2683 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2684 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2685 else
2686 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2687
2688 /* r0 = calleeMethod */
2689 loadConstant(cUnit, r0, (int) calleeMethod);
2690
Ben Cheng38329f52009-07-07 14:19:20 -07002691 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2692 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002693 break;
2694 }
2695 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2696 case OP_INVOKE_STATIC:
2697 case OP_INVOKE_STATIC_RANGE: {
2698 const Method *calleeMethod =
2699 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2700
2701 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2702 genProcessArgsNoRange(cUnit, mir, dInsn,
2703 NULL /* no null check */);
2704 else
2705 genProcessArgsRange(cUnit, mir, dInsn,
2706 NULL /* no null check */);
2707
2708 /* r0 = calleeMethod */
2709 loadConstant(cUnit, r0, (int) calleeMethod);
2710
Ben Cheng38329f52009-07-07 14:19:20 -07002711 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2712 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002713 break;
2714 }
2715 /*
2716 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2717 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07002718 *
2719 * Given "invoke-interface {v0}", the following is the generated code:
2720 *
2721 * 0x426a9abe : ldr r0, [r5, #0] --+
2722 * 0x426a9ac0 : mov r7, r5 |
2723 * 0x426a9ac2 : sub r7, #24 |
2724 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
2725 * 0x426a9ac6 : beq 0x426a9afe |
2726 * 0x426a9ac8 : stmia r7, <r0> --+
2727 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2728 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
2729 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
2730 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
2731 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
2732 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
2733 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
2734 * 0x426a9ad8 : mov r9, r1 --+
2735 * 0x426a9ada : mov r10, r2 |
2736 * 0x426a9adc : mov r12, r3 |
2737 * 0x426a9ade : mov r0, r3 |
2738 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
2739 * 0x426a9ae2 : ldr r2, [pc, #76] |
2740 * 0x426a9ae4 : ldr r3, [pc, #68] |
2741 * 0x426a9ae6 : ldr r7, [pc, #64] |
2742 * 0x426a9ae8 : blx r7 --+
2743 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
2744 * 0x426a9aec : cmp r1, #0 --> compare against 0
2745 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
2746 * 0x426a9af0 : ldr r7, [r6, #96] --+
2747 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
2748 * 0x426a9af4 : mov r3, r12 |
2749 * 0x426a9af6 : blx r7 --+
2750 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
2751 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2752 * 0x426a9afc : blx_2 see above --+
2753 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
2754 * 0x426a9afe (0042): ldr r0, [pc, #52]
2755 * Exception_Handling:
2756 * 0x426a9b00 (0044): ldr r1, [r6, #84]
2757 * 0x426a9b02 (0046): blx r1
2758 * 0x426a9b04 (0048): .align4
2759 * -------- chaining cell (hot): 0x0021
2760 * 0x426a9b04 (0048): ldr r0, [r6, #92]
2761 * 0x426a9b06 (004a): blx r0
2762 * 0x426a9b08 (004c): data 0x7872(30834)
2763 * 0x426a9b0a (004e): data 0x428b(17035)
2764 * 0x426a9b0c (0050): .align4
2765 * -------- chaining cell (predicted)
2766 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
2767 * 0x426a9b0e (0052): data 0x0000(0)
2768 * 0x426a9b10 (0054): data 0x0000(0) --> class
2769 * 0x426a9b12 (0056): data 0x0000(0)
2770 * 0x426a9b14 (0058): data 0x0000(0) --> method
2771 * 0x426a9b16 (005a): data 0x0000(0)
2772 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
2773 * 0x426a9b1a (005e): data 0x0000(0)
2774 * 0x426a9b28 (006c): .word (0xad0392a5)
2775 * 0x426a9b2c (0070): .word (0x6e750)
2776 * 0x426a9b30 (0074): .word (0x4109a618)
2777 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002778 */
2779 case OP_INVOKE_INTERFACE:
2780 case OP_INVOKE_INTERFACE_RANGE: {
Ben Cheng38329f52009-07-07 14:19:20 -07002781 Armv5teLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002782 int methodIndex = dInsn->vB;
2783
2784 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2785 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2786 else
2787 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2788
Ben Cheng38329f52009-07-07 14:19:20 -07002789 /* "this" is already left in r0 by genProcessArgs* */
2790
2791 /* r4PC = dalvikCallsite */
2792 loadConstant(cUnit, r4PC,
2793 (int) (cUnit->method->insns + mir->offset));
2794
2795 /* r1 = &retChainingCell */
2796 Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
2797 r1, 0);
2798 addrRetChain->generic.target = (LIR *) retChainingCell;
2799
2800 /* r2 = &predictedChainingCell */
2801 Armv5teLIR *predictedChainingCell =
2802 newLIR2(cUnit, ARMV5TE_ADD_PC_REL, r2, 0);
2803 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2804
2805 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2806
2807 /* return through lr - jump to the chaining cell */
2808 genUnconditionalBranch(cUnit, predChainingCell);
2809
2810 /*
2811 * null-check on "this" may have been eliminated, but we still need
2812 * a PC-reconstruction label for stack overflow bailout.
2813 */
2814 if (pcrLabel == NULL) {
2815 int dPC = (int) (cUnit->method->insns + mir->offset);
2816 pcrLabel = dvmCompilerNew(sizeof(Armv5teLIR), true);
2817 pcrLabel->opCode = ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL;
2818 pcrLabel->operands[0] = dPC;
2819 pcrLabel->operands[1] = mir->offset;
2820 /* Insert the place holder to the growable list */
2821 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2822 }
2823
2824 /* return through lr+2 - punt to the interpreter */
2825 genUnconditionalBranch(cUnit, pcrLabel);
2826
2827 /*
2828 * return through lr+4 - fully resolve the callee method.
2829 * r1 <- count
2830 * r2 <- &predictedChainCell
2831 * r3 <- this->class
2832 * r4 <- dPC
2833 * r7 <- this->class->vtable
2834 */
2835
2836 /* Save count, &predictedChainCell, and class to high regs first */
2837 newLIR2(cUnit, ARMV5TE_MOV_RR_L2H, r9 & THUMB_REG_MASK, r1);
2838 newLIR2(cUnit, ARMV5TE_MOV_RR_L2H, r10 & THUMB_REG_MASK, r2);
2839 newLIR2(cUnit, ARMV5TE_MOV_RR_L2H, r12 & THUMB_REG_MASK, r3);
2840
Ben Chengba4fc8b2009-06-01 13:00:29 -07002841 /* r0 now contains this->clazz */
Ben Cheng38329f52009-07-07 14:19:20 -07002842 newLIR2(cUnit, ARMV5TE_MOV_RR, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002843
2844 /* r1 = BBBB */
2845 loadConstant(cUnit, r1, dInsn->vB);
2846
2847 /* r2 = method (caller) */
2848 loadConstant(cUnit, r2, (int) cUnit->method);
2849
2850 /* r3 = pDvmDex */
2851 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
2852
2853 loadConstant(cUnit, r7,
2854 (intptr_t) dvmFindInterfaceMethodInCache);
2855 newLIR1(cUnit, ARMV5TE_BLX_R, r7);
2856
2857 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
2858
Ben Cheng38329f52009-07-07 14:19:20 -07002859 newLIR2(cUnit, ARMV5TE_MOV_RR_H2L, r1, r9 & THUMB_REG_MASK);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002860
Ben Cheng38329f52009-07-07 14:19:20 -07002861 /* Check if rechain limit is reached */
2862 newLIR2(cUnit, ARMV5TE_CMP_RI8, r1, 0);
2863
2864 Armv5teLIR *bypassRechaining =
2865 newLIR2(cUnit, ARMV5TE_B_COND, 0, ARM_COND_GT);
2866
2867 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r7, rGLUE,
2868 offsetof(InterpState,
2869 jitToInterpEntries.dvmJitToPatchPredictedChain)
2870 >> 2);
2871
2872 newLIR2(cUnit, ARMV5TE_MOV_RR_H2L, r2, r10 & THUMB_REG_MASK);
2873 newLIR2(cUnit, ARMV5TE_MOV_RR_H2L, r3, r12 & THUMB_REG_MASK);
2874
2875 /*
2876 * r0 = calleeMethod
2877 * r2 = &predictedChainingCell
2878 * r3 = class
2879 *
2880 * &returnChainingCell has been loaded into r1 but is not needed
2881 * when patching the chaining cell and will be clobbered upon
2882 * returning so it will be reconstructed again.
2883 */
2884 newLIR1(cUnit, ARMV5TE_BLX_R, r7);
2885
2886 /* r1 = &retChainingCell */
2887 addrRetChain = newLIR3(cUnit, ARMV5TE_ADD_PC_REL,
2888 r1, 0, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002889 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07002890
2891 bypassRechaining->generic.target = (LIR *) addrRetChain;
2892
Ben Chengba4fc8b2009-06-01 13:00:29 -07002893 /*
2894 * r0 = this, r1 = calleeMethod,
2895 * r1 = &ChainingCell,
2896 * r4PC = callsiteDPC,
2897 */
2898 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2899#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07002900 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002901#endif
2902 /* Handle exceptions using the interpreter */
2903 genTrap(cUnit, mir->offset, pcrLabel);
2904 break;
2905 }
2906 /* NOP */
2907 case OP_INVOKE_DIRECT_EMPTY: {
2908 return false;
2909 }
2910 case OP_FILLED_NEW_ARRAY:
2911 case OP_FILLED_NEW_ARRAY_RANGE: {
2912 /* Just let the interpreter deal with these */
2913 genInterpSingleStep(cUnit, mir);
2914 break;
2915 }
2916 default:
2917 return true;
2918 }
2919 return false;
2920}
2921
2922static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
2923 BasicBlock *bb, Armv5teLIR *labelList)
2924{
2925 Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Cheng38329f52009-07-07 14:19:20 -07002926 Armv5teLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002927 Armv5teLIR *pcrLabel = NULL;
2928
2929 DecodedInstruction *dInsn = &mir->dalvikInsn;
2930 switch (mir->dalvikInsn.opCode) {
2931 /* calleeMethod = this->clazz->vtable[BBBB] */
2932 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
2933 case OP_INVOKE_VIRTUAL_QUICK: {
2934 int methodIndex = dInsn->vB;
2935 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
2936 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2937 else
2938 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2939
Ben Cheng38329f52009-07-07 14:19:20 -07002940 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2941 retChainingCell,
2942 predChainingCell,
2943 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002944 break;
2945 }
2946 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2947 case OP_INVOKE_SUPER_QUICK:
2948 case OP_INVOKE_SUPER_QUICK_RANGE: {
2949 const Method *calleeMethod =
2950 cUnit->method->clazz->super->vtable[dInsn->vB];
2951
2952 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
2953 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2954 else
2955 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2956
2957 /* r0 = calleeMethod */
2958 loadConstant(cUnit, r0, (int) calleeMethod);
2959
Ben Cheng38329f52009-07-07 14:19:20 -07002960 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2961 calleeMethod);
2962 /* Handle exceptions using the interpreter */
2963 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002964 break;
2965 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002966 default:
2967 return true;
2968 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002969 return false;
2970}
2971
2972/*
2973 * NOTE: We assume here that the special native inline routines
2974 * are side-effect free. By making this assumption, we can safely
2975 * re-execute the routine from the interpreter if it decides it
2976 * wants to throw an exception. We still need to EXPORT_PC(), though.
2977 */
2978static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
2979{
2980 DecodedInstruction *dInsn = &mir->dalvikInsn;
2981 switch( mir->dalvikInsn.opCode) {
2982 case OP_EXECUTE_INLINE: {
2983 unsigned int i;
2984 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
2985 int offset = (int) &((InterpState *) NULL)->retval;
2986 int operation = dInsn->vB;
2987
2988 if (!strcmp(inLineTable[operation].classDescriptor,
2989 "Ljava/lang/String;") &&
2990 !strcmp(inLineTable[operation].methodName,
2991 "length") &&
2992 !strcmp(inLineTable[operation].methodSignature,
2993 "()I")) {
2994 return genInlinedStringLength(cUnit,mir);
2995 }
2996
2997 /* Materialize pointer to retval & push */
2998 newLIR2(cUnit, ARMV5TE_MOV_RR, r4PC, rGLUE);
2999 newLIR2(cUnit, ARMV5TE_ADD_RI8, r4PC, offset);
3000 /* Push r4 and (just to take up space) r5) */
3001 newLIR1(cUnit, ARMV5TE_PUSH, (1<<r4PC | 1<<rFP));
3002
3003 /* Get code pointer to inline routine */
3004 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3005
3006 /* Export PC */
3007 genExportPC(cUnit, mir, r0, r1 );
3008
3009 /* Load arguments to r0 through r3 as applicable */
3010 for (i=0; i < dInsn->vA; i++) {
3011 loadValue(cUnit, dInsn->arg[i], i);
3012 }
3013 /* Call inline routine */
3014 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
3015
3016 /* Strip frame */
3017 newLIR1(cUnit, ARMV5TE_ADD_SPI7, 2);
3018
3019 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07003020 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003021
Ben Chenge9695e52009-06-16 16:11:47 -07003022 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003023 break;
3024 }
3025 default:
3026 return true;
3027 }
3028 return false;
3029}
3030
3031static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3032{
3033 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3034 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3035 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
3036 return false;
3037}
3038
3039/*****************************************************************************/
3040/*
3041 * The following are special processing routines that handle transfer of
3042 * controls between compiled code and the interpreter. Certain VM states like
3043 * Dalvik PC and special-purpose registers are reconstructed here.
3044 */
3045
Ben Cheng1efc9c52009-06-08 18:25:27 -07003046/* Chaining cell for code that may need warmup. */
3047static void handleNormalChainingCell(CompilationUnit *cUnit,
3048 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003049{
3050 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
3051 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3052 newLIR1(cUnit, ARMV5TE_BLX_R, r0);
3053 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3054}
3055
3056/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003057 * Chaining cell for instructions that immediately following already translated
3058 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003059 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003060static void handleHotChainingCell(CompilationUnit *cUnit,
3061 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003062{
3063 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
3064 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
3065 newLIR1(cUnit, ARMV5TE_BLX_R, r0);
3066 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3067}
3068
3069/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003070static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3071 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003072{
3073 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
3074 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
3075 newLIR1(cUnit, ARMV5TE_BLX_R, r0);
3076 addWordData(cUnit, (int) (callee->insns), true);
3077}
3078
Ben Cheng38329f52009-07-07 14:19:20 -07003079/* Chaining cell for monomorphic method invocations. */
3080static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3081{
3082
3083 /* Should not be executed in the initial state */
3084 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3085 /* To be filled: class */
3086 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3087 /* To be filled: method */
3088 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3089 /*
3090 * Rechain count. The initial value of 0 here will trigger chaining upon
3091 * the first invocation of this callsite.
3092 */
3093 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3094}
3095
Ben Chengba4fc8b2009-06-01 13:00:29 -07003096/* Load the Dalvik PC into r0 and jump to the specified target */
3097static void handlePCReconstruction(CompilationUnit *cUnit,
3098 Armv5teLIR *targetLabel)
3099{
3100 Armv5teLIR **pcrLabel =
3101 (Armv5teLIR **) cUnit->pcReconstructionList.elemList;
3102 int numElems = cUnit->pcReconstructionList.numUsed;
3103 int i;
3104 for (i = 0; i < numElems; i++) {
3105 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3106 /* r0 = dalvik PC */
3107 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3108 genUnconditionalBranch(cUnit, targetLabel);
3109 }
3110}
3111
3112/* Entry function to invoke the backend of the JIT compiler */
3113void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3114{
3115 /* Used to hold the labels of each block */
3116 Armv5teLIR *labelList =
3117 dvmCompilerNew(sizeof(Armv5teLIR) * cUnit->numBlocks, true);
3118 GrowableList chainingListByType[CHAINING_CELL_LAST];
3119 int i;
3120
3121 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003122 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003123 */
3124 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3125 dvmInitGrowableList(&chainingListByType[i], 2);
3126 }
3127
3128 BasicBlock **blockList = cUnit->blockList;
3129
Bill Buzbee6e963e12009-06-17 16:56:19 -07003130 if (cUnit->executionCount) {
3131 /*
3132 * Reserve 6 bytes at the beginning of the trace
3133 * +----------------------------+
3134 * | execution count (4 bytes) |
3135 * +----------------------------+
3136 * | chain cell offset (2 bytes)|
3137 * +----------------------------+
3138 * ...and then code to increment the execution
3139 * count:
3140 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3141 * sub r0, #10 @ back up to addr of executionCount
3142 * ldr r1, [r0]
3143 * add r1, #1
3144 * str r1, [r0]
3145 */
3146 newLIR1(cUnit, ARMV5TE_16BIT_DATA, 0);
3147 newLIR1(cUnit, ARMV5TE_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003148 cUnit->chainCellOffsetLIR =
3149 (LIR *) newLIR1(cUnit, ARMV5TE_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003150 cUnit->headerSize = 6;
Ben Cheng38329f52009-07-07 14:19:20 -07003151 newLIR2(cUnit, ARMV5TE_MOV_RR_H2L, r0, rpc & THUMB_REG_MASK);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003152 newLIR2(cUnit, ARMV5TE_SUB_RI8, r0, 10);
3153 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, r0, 0);
3154 newLIR2(cUnit, ARMV5TE_ADD_RI8, r1, 1);
3155 newLIR3(cUnit, ARMV5TE_STR_RRI5, r1, r0, 0);
3156 } else {
3157 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003158 cUnit->chainCellOffsetLIR =
3159 (LIR *) newLIR1(cUnit, ARMV5TE_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003160 cUnit->headerSize = 2;
3161 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003162
Ben Chengba4fc8b2009-06-01 13:00:29 -07003163 /* Handle the content in each basic block */
3164 for (i = 0; i < cUnit->numBlocks; i++) {
3165 blockList[i]->visited = true;
3166 MIR *mir;
3167
3168 labelList[i].operands[0] = blockList[i]->startOffset;
3169
3170 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3171 /*
3172 * Append the label pseudo LIR first. Chaining cells will be handled
3173 * separately afterwards.
3174 */
3175 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3176 }
3177
3178 if (blockList[i]->blockType == DALVIK_BYTECODE) {
3179 labelList[i].opCode = ARMV5TE_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003180 /* Reset the register state */
3181 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003182 } else {
3183 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003184 case CHAINING_CELL_NORMAL:
3185 labelList[i].opCode = ARMV5TE_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003186 /* handle the codegen later */
3187 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003188 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003189 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003190 case CHAINING_CELL_INVOKE_SINGLETON:
3191 labelList[i].opCode =
3192 ARMV5TE_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003193 labelList[i].operands[0] =
3194 (int) blockList[i]->containingMethod;
3195 /* handle the codegen later */
3196 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003197 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3198 (void *) i);
3199 break;
3200 case CHAINING_CELL_INVOKE_PREDICTED:
3201 labelList[i].opCode =
3202 ARMV5TE_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
3203 /* handle the codegen later */
3204 dvmInsertGrowableList(
3205 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3206 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003207 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003208 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003209 labelList[i].opCode =
Ben Cheng1efc9c52009-06-08 18:25:27 -07003210 ARMV5TE_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003211 /* handle the codegen later */
3212 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003213 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003214 (void *) i);
3215 break;
3216 case PC_RECONSTRUCTION:
3217 /* Make sure exception handling block is next */
3218 labelList[i].opCode =
3219 ARMV5TE_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
3220 assert (i == cUnit->numBlocks - 2);
3221 handlePCReconstruction(cUnit, &labelList[i+1]);
3222 break;
3223 case EXCEPTION_HANDLING:
3224 labelList[i].opCode = ARMV5TE_PSEUDO_EH_BLOCK_LABEL;
3225 if (cUnit->pcReconstructionList.numUsed) {
3226 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE,
3227 offsetof(InterpState,
3228 jitToInterpEntries.dvmJitToInterpPunt)
3229 >> 2);
3230 newLIR1(cUnit, ARMV5TE_BLX_R, r1);
3231 }
3232 break;
3233 default:
3234 break;
3235 }
3236 continue;
3237 }
Ben Chenge9695e52009-06-16 16:11:47 -07003238
3239 Armv5teLIR *headLIR = NULL;
3240
Ben Chengba4fc8b2009-06-01 13:00:29 -07003241 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
3242 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3243 InstructionFormat dalvikFormat =
3244 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Ben Chenge9695e52009-06-16 16:11:47 -07003245 Armv5teLIR *boundaryLIR =
3246 newLIR2(cUnit, ARMV5TE_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
3247 mir->offset,dalvikOpCode);
3248 /* Remember the first LIR for this block */
3249 if (headLIR == NULL) {
3250 headLIR = boundaryLIR;
3251 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003252 bool notHandled;
3253 /*
3254 * Debugging: screen the opcode first to see if it is in the
3255 * do[-not]-compile list
3256 */
3257 bool singleStepMe =
3258 gDvmJit.includeSelectedOp !=
3259 ((gDvmJit.opList[dalvikOpCode >> 3] &
3260 (1 << (dalvikOpCode & 0x7))) !=
3261 0);
3262 if (singleStepMe || cUnit->allSingleStep) {
3263 notHandled = false;
3264 genInterpSingleStep(cUnit, mir);
3265 } else {
3266 opcodeCoverage[dalvikOpCode]++;
3267 switch (dalvikFormat) {
3268 case kFmt10t:
3269 case kFmt20t:
3270 case kFmt30t:
3271 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3272 mir, blockList[i], labelList);
3273 break;
3274 case kFmt10x:
3275 notHandled = handleFmt10x(cUnit, mir);
3276 break;
3277 case kFmt11n:
3278 case kFmt31i:
3279 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3280 break;
3281 case kFmt11x:
3282 notHandled = handleFmt11x(cUnit, mir);
3283 break;
3284 case kFmt12x:
3285 notHandled = handleFmt12x(cUnit, mir);
3286 break;
3287 case kFmt20bc:
3288 notHandled = handleFmt20bc(cUnit, mir);
3289 break;
3290 case kFmt21c:
3291 case kFmt31c:
3292 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3293 break;
3294 case kFmt21h:
3295 notHandled = handleFmt21h(cUnit, mir);
3296 break;
3297 case kFmt21s:
3298 notHandled = handleFmt21s(cUnit, mir);
3299 break;
3300 case kFmt21t:
3301 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3302 labelList);
3303 break;
3304 case kFmt22b:
3305 case kFmt22s:
3306 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3307 break;
3308 case kFmt22c:
3309 notHandled = handleFmt22c(cUnit, mir);
3310 break;
3311 case kFmt22cs:
3312 notHandled = handleFmt22cs(cUnit, mir);
3313 break;
3314 case kFmt22t:
3315 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3316 labelList);
3317 break;
3318 case kFmt22x:
3319 case kFmt32x:
3320 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3321 break;
3322 case kFmt23x:
3323 notHandled = handleFmt23x(cUnit, mir);
3324 break;
3325 case kFmt31t:
3326 notHandled = handleFmt31t(cUnit, mir);
3327 break;
3328 case kFmt3rc:
3329 case kFmt35c:
3330 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3331 labelList);
3332 break;
3333 case kFmt3rms:
3334 case kFmt35ms:
3335 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3336 labelList);
3337 break;
3338 case kFmt3inline:
3339 notHandled = handleFmt3inline(cUnit, mir);
3340 break;
3341 case kFmt51l:
3342 notHandled = handleFmt51l(cUnit, mir);
3343 break;
3344 default:
3345 notHandled = true;
3346 break;
3347 }
3348 }
3349 if (notHandled) {
3350 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3351 mir->offset,
3352 dalvikOpCode, getOpcodeName(dalvikOpCode),
3353 dalvikFormat);
3354 dvmAbort();
3355 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003356 }
3357 }
Ben Chenge9695e52009-06-16 16:11:47 -07003358
3359 /* Eliminate redundant loads/stores and delay stores into later slots */
3360 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3361 cUnit->lastLIRInsn);
Ben Cheng1efc9c52009-06-08 18:25:27 -07003362 /*
3363 * Check if the block is terminated due to trace length constraint -
3364 * insert an unconditional branch to the chaining cell.
3365 */
3366 if (blockList[i]->needFallThroughBranch) {
3367 genUnconditionalBranch(cUnit,
3368 &labelList[blockList[i]->fallThrough->id]);
3369 }
3370
Ben Chengba4fc8b2009-06-01 13:00:29 -07003371 }
3372
Ben Chenge9695e52009-06-16 16:11:47 -07003373 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003374 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3375 size_t j;
3376 int *blockIdList = (int *) chainingListByType[i].elemList;
3377
3378 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3379
3380 /* No chaining cells of this type */
3381 if (cUnit->numChainingCells[i] == 0)
3382 continue;
3383
3384 /* Record the first LIR for a new type of chaining cell */
3385 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3386
3387 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3388 int blockId = blockIdList[j];
3389
3390 /* Align this chaining cell first */
3391 newLIR0(cUnit, ARMV5TE_PSEUDO_ALIGN4);
3392
3393 /* Insert the pseudo chaining instruction */
3394 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3395
3396
3397 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003398 case CHAINING_CELL_NORMAL:
3399 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003400 blockList[blockId]->startOffset);
3401 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003402 case CHAINING_CELL_INVOKE_SINGLETON:
3403 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003404 blockList[blockId]->containingMethod);
3405 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003406 case CHAINING_CELL_INVOKE_PREDICTED:
3407 handleInvokePredictedChainingCell(cUnit);
3408 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003409 case CHAINING_CELL_HOT:
3410 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003411 blockList[blockId]->startOffset);
3412 break;
3413 default:
3414 dvmAbort();
3415 break;
3416 }
3417 }
3418 }
Ben Chenge9695e52009-06-16 16:11:47 -07003419
3420 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003421}
3422
3423/* Accept the work and start compiling */
3424void *dvmCompilerDoWork(CompilerWorkOrder *work)
3425{
3426 void *res;
3427
3428 if (gDvmJit.codeCacheFull) {
3429 return NULL;
3430 }
3431
3432 switch (work->kind) {
3433 case kWorkOrderMethod:
3434 res = dvmCompileMethod(work->info);
3435 break;
3436 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003437 /* Start compilation with maximally allowed trace length */
3438 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003439 break;
3440 default:
3441 res = NULL;
3442 dvmAbort();
3443 }
3444 return res;
3445}
3446
3447/* Architecture-specific initializations and checks go here */
3448bool dvmCompilerArchInit(void)
3449{
3450 /* First, declare dvmCompiler_TEMPLATE_XXX for each template */
3451#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
3452#include "../../template/armv5te/TemplateOpList.h"
3453#undef JIT_TEMPLATE
3454
3455 int i = 0;
3456 extern void dvmCompilerTemplateStart(void);
3457
3458 /*
3459 * Then, populate the templateEntryOffsets array with the offsets from the
3460 * the dvmCompilerTemplateStart symbol for each template.
3461 */
3462#define JIT_TEMPLATE(X) templateEntryOffsets[i++] = \
3463 (intptr_t) dvmCompiler_TEMPLATE_##X - (intptr_t) dvmCompilerTemplateStart;
3464#include "../../template/armv5te/TemplateOpList.h"
3465#undef JIT_TEMPLATE
3466
3467 /* Codegen-specific assumptions */
3468 assert(offsetof(ClassObject, vtable) < 128 &&
3469 (offsetof(ClassObject, vtable) & 0x3) == 0);
3470 assert(offsetof(ArrayObject, length) < 128 &&
3471 (offsetof(ArrayObject, length) & 0x3) == 0);
3472 assert(offsetof(ArrayObject, contents) < 256);
3473
3474 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
3475 assert(sizeof(StackSaveArea) < 236);
3476
3477 /*
3478 * EA is calculated by doing "Rn + imm5 << 2", and there are 5 entry points
3479 * that codegen may access, make sure that the offset from the top of the
3480 * struct is less than 108.
3481 */
3482 assert(offsetof(InterpState, jitToInterpEntries) < 108);
3483 return true;
3484}
3485
3486/* Architectural-specific debugging helpers go here */
3487void dvmCompilerArchDump(void)
3488{
3489 /* Print compiled opcode in this VM instance */
3490 int i, start, streak;
3491 char buf[1024];
3492
3493 streak = i = 0;
3494 buf[0] = 0;
3495 while (opcodeCoverage[i] == 0 && i < 256) {
3496 i++;
3497 }
3498 if (i == 256) {
3499 return;
3500 }
3501 for (start = i++, streak = 1; i < 256; i++) {
3502 if (opcodeCoverage[i]) {
3503 streak++;
3504 } else {
3505 if (streak == 1) {
3506 sprintf(buf+strlen(buf), "%x,", start);
3507 } else {
3508 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3509 }
3510 streak = 0;
3511 while (opcodeCoverage[i] == 0 && i < 256) {
3512 i++;
3513 }
3514 if (i < 256) {
3515 streak = 1;
3516 start = i;
3517 }
3518 }
3519 }
3520 if (streak) {
3521 if (streak == 1) {
3522 sprintf(buf+strlen(buf), "%x", start);
3523 } else {
3524 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3525 }
3526 }
3527 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07003528 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003529 }
3530}
Bill Buzbeed45ba372009-06-15 17:00:57 -07003531
3532/*
3533 * Exported version of loadValueAddress
3534 * TODO: revisit source file structure
3535 */
3536void dvmCompilerLoadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
3537{
3538 loadValueAddress(cUnit, vSrc, rDest);
3539}
3540
3541/*
3542 * Exported version of genDispatchToHandler
3543 * TODO: revisit source file structure
3544 */
Ben Chenge9695e52009-06-16 16:11:47 -07003545void dvmCompilerGenDispatchToHandler(CompilationUnit *cUnit,
Bill Buzbeed45ba372009-06-15 17:00:57 -07003546 TemplateOpCode opCode)
3547{
3548 genDispatchToHandler(cUnit, opCode);
3549}
3550
3551/*
3552 * Exported version of loadValue
3553 * TODO: revisit source file structure
3554 */
3555void dvmCompilerLoadValue(CompilationUnit *cUnit, int vSrc, int rDest)
3556{
3557 loadValue(cUnit, vSrc, rDest);
3558}
3559
3560/*
3561 * Exported version of storeValue
3562 * TODO: revisit source file structure
3563 */
3564void dvmCompilerStoreValue(CompilationUnit *cUnit, int rSrc, int vDest,
3565 int rScratch)
3566{
3567 storeValue(cUnit, rSrc, vDest, rScratch);
3568}