blob: 448a539ac2f0a0e0c05255eecc6dc686e9fcbc75 [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
32/*****************************************************************************/
33
34/*
35 * The following are building blocks to construct low-level IRs with 0 - 3
36 * operands.
37 */
38static Armv5teLIR *newLIR0(CompilationUnit *cUnit, Armv5teOpCode opCode)
39{
40 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
41 assert(isPseudoOpCode(opCode) || EncodingMap[opCode].operands == 0);
42 insn->opCode = opCode;
43 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
44 return insn;
45}
46
47static Armv5teLIR *newLIR1(CompilationUnit *cUnit, Armv5teOpCode opCode,
48 int dest)
49{
50 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
51 assert(isPseudoOpCode(opCode) || EncodingMap[opCode].operands == 1);
52 insn->opCode = opCode;
53 insn->operands[0] = dest;
54 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
55 return insn;
56}
57
58static Armv5teLIR *newLIR2(CompilationUnit *cUnit, Armv5teOpCode opCode,
59 int dest, int src1)
60{
61 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
62 assert(isPseudoOpCode(opCode) || EncodingMap[opCode].operands == 2);
63 insn->opCode = opCode;
64 insn->operands[0] = dest;
65 insn->operands[1] = src1;
66 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
67 return insn;
68}
69
70static Armv5teLIR *newLIR3(CompilationUnit *cUnit, Armv5teOpCode opCode,
71 int dest, int src1, int src2)
72{
73 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
74 assert(isPseudoOpCode(opCode) || EncodingMap[opCode].operands == 3);
75 insn->opCode = opCode;
76 insn->operands[0] = dest;
77 insn->operands[1] = src1;
78 insn->operands[2] = src2;
79 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
80 return insn;
81}
82
83static Armv5teLIR *newLIR23(CompilationUnit *cUnit, Armv5teOpCode opCode,
84 int srcdest, int src2)
85{
86 assert(!isPseudoOpCode(opCode));
87 if (EncodingMap[opCode].operands==2)
88 return newLIR2(cUnit, opCode, srcdest, src2);
89 else
90 return newLIR3(cUnit, opCode, srcdest, srcdest, src2);
91}
92
93/*****************************************************************************/
94
95/*
96 * The following are building blocks to insert constants into the pool or
97 * instruction streams.
98 */
99
100/* Add a 32-bit constant either in the constant pool or mixed with code */
101static Armv5teLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
102{
103 /* Add the constant to the literal pool */
104 if (!inPlace) {
105 Armv5teLIR *newValue = dvmCompilerNew(sizeof(Armv5teLIR), true);
106 newValue->operands[0] = value;
107 newValue->generic.next = cUnit->wordList;
108 cUnit->wordList = (LIR *) newValue;
109 return newValue;
110 } else {
111 /* Add the constant in the middle of code stream */
112 newLIR1(cUnit, ARMV5TE_16BIT_DATA, (value & 0xffff));
113 newLIR1(cUnit, ARMV5TE_16BIT_DATA, (value >> 16));
114 }
115 return NULL;
116}
117
118/*
119 * Search the existing constants in the literal pool for an exact or close match
120 * within specified delta (greater or equal to 0).
121 */
122static Armv5teLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
123 unsigned int delta)
124{
125 LIR *dataTarget = cUnit->wordList;
126 while (dataTarget) {
127 if (((unsigned) (value - ((Armv5teLIR *) dataTarget)->operands[0])) <=
128 delta)
129 return (Armv5teLIR *) dataTarget;
130 dataTarget = dataTarget->next;
131 }
132 return NULL;
133}
134
135/*
136 * Load a immediate using a shortcut if possible; otherwise
137 * grab from the per-translation literal pool
138 */
139void loadConstant(CompilationUnit *cUnit, int rDest, int value)
140{
141 /* See if the value can be constructed cheaply */
142 if ((value >= 0) && (value <= 255)) {
143 newLIR2(cUnit, ARMV5TE_MOV_IMM, rDest, value);
144 return;
145 } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
146 newLIR2(cUnit, ARMV5TE_MOV_IMM, rDest, ~value);
147 newLIR2(cUnit, ARMV5TE_MVN, rDest, rDest);
148 return;
149 }
150 /* No shortcut - go ahead and use literal pool */
151 Armv5teLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
152 if (dataTarget == NULL) {
153 dataTarget = addWordData(cUnit, value, false);
154 }
155 Armv5teLIR *loadPcRel = dvmCompilerNew(sizeof(Armv5teLIR), true);
156 loadPcRel->opCode = ARMV5TE_LDR_PC_REL;
157 loadPcRel->generic.target = (LIR *) dataTarget;
158 loadPcRel->operands[0] = rDest;
159 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
160
161 /*
162 * To save space in the constant pool, we use the ADD_RRI8 instruction to
163 * add up to 255 to an existing constant value.
164 */
165 if (dataTarget->operands[0] != value) {
166 newLIR2(cUnit, ARMV5TE_ADD_RI8, rDest, value - dataTarget->operands[0]);
167 }
168}
169
170/* Export the Dalvik PC assicated with an instruction to the StackSave area */
171static void genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC, int rAddr)
172{
173 int offset = offsetof(StackSaveArea, xtra.currentPc);
174 loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
175 newLIR2(cUnit, ARMV5TE_MOV_RR, rAddr, rFP);
176 newLIR2(cUnit, ARMV5TE_SUB_RI8, rAddr, sizeof(StackSaveArea) - offset);
177 newLIR3(cUnit, ARMV5TE_STR_RRI5, rDPC, rAddr, 0);
178}
179
180/* Generate conditional branch instructions */
181static void genConditionalBranch(CompilationUnit *cUnit,
182 Armv5teConditionCode cond,
183 Armv5teLIR *target)
184{
185 Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
186 branch->generic.target = (LIR *) target;
187}
188
189/* Generate unconditional branch instructions */
190static void genUnconditionalBranch(CompilationUnit *cUnit, Armv5teLIR *target)
191{
192 Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
193 branch->generic.target = (LIR *) target;
194}
195
196#define USE_IN_CACHE_HANDLER 1
197
198/*
199 * Jump to the out-of-line handler in ARM mode to finish executing the
200 * remaining of more complex instructions.
201 */
202static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
203{
204#if USE_IN_CACHE_HANDLER
205 /*
206 * NOTE - In practice BLX only needs one operand, but since the assembler
207 * may abort itself and retry due to other out-of-range conditions we
208 * cannot really use operand[0] to store the absolute target address since
209 * it may get clobbered by the final relative offset. Therefore,
210 * we fake BLX_1 is a two operand instruction and the absolute target
211 * address is stored in operand[1].
212 */
213 newLIR2(cUnit, ARMV5TE_BLX_1,
214 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
215 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
216 newLIR2(cUnit, ARMV5TE_BLX_2,
217 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
218 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
219#else
220 /*
221 * In case we want to access the statically compiled handlers for
222 * debugging purposes, define USE_IN_CACHE_HANDLER to 0
223 */
224 void *templatePtr;
225
226#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
227#include "../../template/armv5te/TemplateOpList.h"
228#undef JIT_TEMPLATE
229 switch (opCode) {
230#define JIT_TEMPLATE(X) \
231 case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; }
232#include "../../template/armv5te/TemplateOpList.h"
233#undef JIT_TEMPLATE
234 default: templatePtr = NULL;
235 }
236 loadConstant(cUnit, r7, (int) templatePtr);
237 newLIR1(cUnit, ARMV5TE_BLX_R, r7);
238#endif
239}
240
241/* Perform the actual operation for OP_RETURN_* */
242static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
243{
244 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
245#if defined(INVOKE_STATS)
246 gDvmJit.jitReturn++;
247#endif
248 int dPC = (int) (cUnit->method->insns + mir->offset);
249 Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
250 /* Set up the place holder to reconstruct this Dalvik PC */
251 Armv5teLIR *pcrLabel = dvmCompilerNew(sizeof(Armv5teLIR), true);
252 pcrLabel->opCode = ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL;
253 pcrLabel->operands[0] = dPC;
254 pcrLabel->operands[1] = mir->offset;
255 /* Insert the place holder to the growable list */
256 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
257 /* Branch to the PC reconstruction code */
258 branch->generic.target = (LIR *) pcrLabel;
259}
260
261/*
262 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
263 * rDestHi
264 */
265static void loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
266 int rDestHi)
267{
268 /* Use reg + imm5*4 to load the values if possible */
269 if (vSrc <= 30) {
270 newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDestLo, rFP, vSrc);
271 newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDestHi, rFP, vSrc+1);
272 } else {
273 if (vSrc <= 64) {
274 /* Sneak 4 into the base address first */
275 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDestLo, rFP, 4);
276 newLIR2(cUnit, ARMV5TE_ADD_RI8, rDestHi, (vSrc-1)*4);
277 } else {
278 /* Offset too far from rFP */
279 loadConstant(cUnit, rDestLo, vSrc*4);
280 newLIR3(cUnit, ARMV5TE_ADD_RRR, rDestLo, rFP, rDestLo);
281 }
282 assert(rDestLo != rDestHi);
283 newLIR2(cUnit, ARMV5TE_LDMIA, rDestLo, (1<<rDestLo) | (1<<(rDestHi)));
284 }
285}
286
287/*
288 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
289 * vDest+1
290 */
291static void storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
292 int vDest, int rScratch)
293{
294 /* Use reg + imm5*4 to store the values if possible */
295 if (vDest <= 30) {
296 newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrcLo, rFP, vDest);
297 newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrcHi, rFP, vDest+1);
298 } else {
299 if (vDest <= 64) {
300 /* Sneak 4 into the base address first */
301 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rScratch, rFP, 4);
302 newLIR2(cUnit, ARMV5TE_ADD_RI8, rScratch, (vDest-1)*4);
303 } else {
304 /* Offset too far from rFP */
305 loadConstant(cUnit, rScratch, vDest*4);
306 newLIR3(cUnit, ARMV5TE_ADD_RRR, rScratch, rFP, rScratch);
307 }
308 assert(rSrcLo != rSrcHi);
309 newLIR2(cUnit, ARMV5TE_STMIA, rScratch, (1<<rSrcLo) | (1 << (rSrcHi)));
310 }
311}
312
313/* Load the address of a Dalvik register on the frame */
314static void loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
315{
316 /* RRI3 can add up to 7 */
317 if (vSrc <= 1) {
318 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDest, rFP, vSrc*4);
319 } else if (vSrc <= 64) {
320 /* Sneak 4 into the base address first */
321 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDest, rFP, 4);
322 newLIR2(cUnit, ARMV5TE_ADD_RI8, rDest, (vSrc-1)*4);
323 } else {
324 loadConstant(cUnit, rDest, vSrc*4);
325 newLIR3(cUnit, ARMV5TE_ADD_RRR, rDest, rFP, rDest);
326 }
327}
328
Ben Chengba4fc8b2009-06-01 13:00:29 -0700329/* Load a single value from rFP[src] and store them into rDest */
330static void loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
331{
332 /* Use reg + imm5*4 to load the value if possible */
333 if (vSrc <= 31) {
334 newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDest, rFP, vSrc);
335 } else {
336 loadConstant(cUnit, rDest, vSrc*4);
337 newLIR3(cUnit, ARMV5TE_LDR_RRR, rDest, rFP, rDest);
338 }
339}
340
341/* Store a value from rSrc to vDest */
342static void storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
343 int rScratch)
344{
345 /* Use reg + imm5*4 to store the value if possible */
346 if (vDest <= 31) {
347 newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrc, rFP, vDest);
348 } else {
349 loadConstant(cUnit, rScratch, vDest*4);
350 newLIR3(cUnit, ARMV5TE_STR_RRR, rSrc, rFP, rScratch);
351 }
352}
353
354/* Calculate the address of rFP+vSrc*4 */
355static void calculateValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
356{
357 /* Use add rd, rs, imm_3 */
358 if (vSrc <= 1) {
359 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDest, rFP, vSrc*4);
360 } else if (vSrc <= 64) {
361 /* Use add rd, imm_8 */
362 /* Sneak in 4 above rFP to cover one more register offset (ie v64) */
363 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDest, rFP, 4);
364 newLIR2(cUnit, ARMV5TE_ADD_RI8, rDest, (vSrc-1)*4);
365 } else {
366 /* Load offset from the constant pool */
367 loadConstant(cUnit, rDest, vSrc*4);
368 newLIR3(cUnit, ARMV5TE_ADD_RRR, rDest, rFP, rDest);
369 }
370}
371
372/*
373 * Perform a binary operation on 64-bit operands and leave the results in the
374 * r0/r1 pair.
375 */
376static void genBinaryOpWide(CompilationUnit *cUnit, int vDest,
377 Armv5teOpCode preinst, Armv5teOpCode inst)
378{
379 newLIR23(cUnit, preinst, r0, r2);
380 newLIR23(cUnit, inst, r1, r3);
381 storeValuePair(cUnit, r0, r1, vDest, r2);
382}
383
384/* Perform a binary operation on 32-bit operands and leave the results in r0. */
385static void genBinaryOp(CompilationUnit *cUnit, int vDest, Armv5teOpCode inst)
386{
387 newLIR23(cUnit, inst, r0, r1);
388 storeValue(cUnit, r0, vDest, r1);
389}
390
391/* Create the PC reconstruction slot if not already done */
392static inline Armv5teLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
393 Armv5teLIR *branch,
394 Armv5teLIR *pcrLabel)
395{
396 /* Set up the place holder to reconstruct this Dalvik PC */
397 if (pcrLabel == NULL) {
398 int dPC = (int) (cUnit->method->insns + dOffset);
399 pcrLabel = dvmCompilerNew(sizeof(Armv5teLIR), true);
400 pcrLabel->opCode = ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL;
401 pcrLabel->operands[0] = dPC;
402 pcrLabel->operands[1] = dOffset;
403 /* Insert the place holder to the growable list */
404 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
405 }
406 /* Branch to the PC reconstruction code */
407 branch->generic.target = (LIR *) pcrLabel;
408 return pcrLabel;
409}
410
411/*
412 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
413 * satisfies.
414 */
415static inline Armv5teLIR *genRegImmCheck(CompilationUnit *cUnit,
416 Armv5teConditionCode cond, int reg,
417 int checkValue, int dOffset,
418 Armv5teLIR *pcrLabel)
419{
420 newLIR2(cUnit, ARMV5TE_CMP_RI8, reg, checkValue);
421 Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
422 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
423}
424
425/*
426 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
427 * satisfies.
428 */
429static inline Armv5teLIR *inertRegRegCheck(CompilationUnit *cUnit,
430 Armv5teConditionCode cond,
431 int reg1, int reg2, int dOffset,
432 Armv5teLIR *pcrLabel)
433{
434 newLIR2(cUnit, ARMV5TE_CMP_RR, reg1, reg2);
435 Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
436 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
437}
438
439/* Perform null-check on a register */
440static Armv5teLIR *genNullCheck(CompilationUnit *cUnit, int reg, int dOffset,
441 Armv5teLIR *pcrLabel)
442{
443 return genRegImmCheck(cUnit, ARM_COND_EQ, reg, 0, dOffset, pcrLabel);
444}
445
446/* Perform bound check on two registers */
447static Armv5teLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
448 int rBound, int dOffset, Armv5teLIR *pcrLabel)
449{
450 return inertRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
451 pcrLabel);
452}
453
454/* Generate a unconditional branch to go to the interpreter */
455static inline Armv5teLIR *genTrap(CompilationUnit *cUnit, int dOffset,
456 Armv5teLIR *pcrLabel)
457{
458 Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
459 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
460}
461
462/* Load a wide field from an object instance */
463static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
464{
465 DecodedInstruction *dInsn = &mir->dalvikInsn;
466
467 loadValue(cUnit, dInsn->vB, r2);
468 loadConstant(cUnit, r3, fieldOffset);
469 genNullCheck(cUnit, r2, mir->offset, NULL); /* null object? */
470 newLIR3(cUnit, ARMV5TE_ADD_RRR, r2, r2, r3);
471 newLIR2(cUnit, ARMV5TE_LDMIA, r2, (1<<r0 | 1<<r1));
472 storeValuePair(cUnit, r0, r1, dInsn->vA, r3);
473}
474
475/* Store a wide field to an object instance */
476static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
477{
478 DecodedInstruction *dInsn = &mir->dalvikInsn;
479
480 loadValue(cUnit, dInsn->vB, r2);
481 loadValuePair(cUnit, dInsn->vA, r0, r1);
482 loadConstant(cUnit, r3, fieldOffset);
483 genNullCheck(cUnit, r2, mir->offset, NULL); /* null object? */
484 newLIR3(cUnit, ARMV5TE_ADD_RRR, r2, r2, r3);
485 newLIR2(cUnit, ARMV5TE_STMIA, r2, (1<<r0 | 1<<r1));
486}
487
488/*
489 * Load a field from an object instance
490 *
491 * Inst should be one of:
492 * ARMV5TE_LDR_RRR
493 * ARMV5TE_LDRB_RRR
494 * ARMV5TE_LDRH_RRR
495 * ARMV5TE_LDRSB_RRR
496 * ARMV5TE_LDRSH_RRR
497 */
498static void genIGet(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
499 int fieldOffset)
500{
501 DecodedInstruction *dInsn = &mir->dalvikInsn;
502
503 /* TUNING: write a utility routine to load via base + constant offset */
504 loadValue(cUnit, dInsn->vB, r0);
505 loadConstant(cUnit, r1, fieldOffset);
506 genNullCheck(cUnit, r0, mir->offset, NULL); /* null object? */
507 newLIR3(cUnit, inst, r0, r0, r1);
508 storeValue(cUnit, r0, dInsn->vA, r1);
509}
510
511/*
512 * Store a field to an object instance
513 *
514 * Inst should be one of:
515 * ARMV5TE_STR_RRR
516 * ARMV5TE_STRB_RRR
517 * ARMV5TE_STRH_RRR
518 */
519static void genIPut(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
520 int fieldOffset)
521{
522 DecodedInstruction *dInsn = &mir->dalvikInsn;
523
524 /* TUNING: write a utility routine to load via base + constant offset */
525 loadValue(cUnit, dInsn->vB, r2);
526 loadConstant(cUnit, r1, fieldOffset);
527 loadValue(cUnit, dInsn->vA, r0);
528 genNullCheck(cUnit, r2, mir->offset, NULL); /* null object? */
529 newLIR3(cUnit, inst, r0, r2, r1);
530}
531
532
533/* TODO: This should probably be done as an out-of-line instruction handler. */
534
535/*
536 * Generate array load
537 *
538 * Inst should be one of:
539 * ARMV5TE_LDR_RRR
540 * ARMV5TE_LDRB_RRR
541 * ARMV5TE_LDRH_RRR
542 * ARMV5TE_LDRSB_RRR
543 * ARMV5TE_LDRSH_RRR
544 */
545static void genArrayGet(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
546 int vArray, int vIndex, int vDest, int scale)
547{
548 int lenOffset = offsetof(ArrayObject, length);
549 int dataOffset = offsetof(ArrayObject, contents);
550
551 loadValue(cUnit, vArray, r2);
552 loadValue(cUnit, vIndex, r3);
553
554 /* null object? */
555 Armv5teLIR * pcrLabel = genNullCheck(cUnit, r2, mir->offset, NULL);
556 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r2, lenOffset >> 2); /* Get len */
557 newLIR2(cUnit, ARMV5TE_ADD_RI8, r2, dataOffset); /* r2 -> array data */
558 genBoundsCheck(cUnit, r3, r0, mir->offset, pcrLabel);
559 if (scale) {
560 newLIR3(cUnit, ARMV5TE_LSL, r3, r3, scale);
561 }
562 if (scale==3) {
563 newLIR3(cUnit, inst, r0, r2, r3);
564 newLIR2(cUnit, ARMV5TE_ADD_RI8, r2, 4);
565 newLIR3(cUnit, inst, r1, r2, r3);
566 storeValuePair(cUnit, r0, r1, vDest, r3);
567 } else {
568 newLIR3(cUnit, inst, r0, r2, r3);
569 storeValue(cUnit, r0, vDest, r3);
570 }
571}
572
573/* TODO: This should probably be done as an out-of-line instruction handler. */
574
575/*
576 * Generate array store
577 *
578 * Inst should be one of:
579 * ARMV5TE_STR_RRR
580 * ARMV5TE_STRB_RRR
581 * ARMV5TE_STRH_RRR
582 */
583static void genArrayPut(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
584 int vArray, int vIndex, int vSrc, int scale)
585{
586 int lenOffset = offsetof(ArrayObject, length);
587 int dataOffset = offsetof(ArrayObject, contents);
588
589 loadValue(cUnit, vArray, r2);
590 loadValue(cUnit, vIndex, r3);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700591 /* null object? */
592 Armv5teLIR * pcrLabel = genNullCheck(cUnit, r2, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700593 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r2, lenOffset >> 2); /* Get len */
594 newLIR2(cUnit, ARMV5TE_ADD_RI8, r2, dataOffset); /* r2 -> array data */
Ben Cheng1efc9c52009-06-08 18:25:27 -0700595 genBoundsCheck(cUnit, r3, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700596 /* at this point, r2 points to array, r3 is unscaled index */
597 if (scale==3) {
598 loadValuePair(cUnit, vSrc, r0, r1);
599 } else {
600 loadValue(cUnit, vSrc, r0);
601 }
602 if (scale) {
603 newLIR3(cUnit, ARMV5TE_LSL, r3, r3, scale);
604 }
605 /*
606 * at this point, r2 points to array, r3 is scaled index, and r0[r1] is
607 * data
608 */
609 if (scale==3) {
610 newLIR3(cUnit, inst, r0, r2, r3);
611 newLIR2(cUnit, ARMV5TE_ADD_RI8, r2, 4);
612 newLIR3(cUnit, inst, r1, r2, r3);
613 } else {
614 newLIR3(cUnit, inst, r0, r2, r3);
615 }
616}
617
618static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
619 int vSrc1, int vShift)
620{
621 loadValuePair(cUnit, vSrc1, r0, r1);
622 loadValue(cUnit, vShift, r2);
623 switch( mir->dalvikInsn.opCode) {
624 case OP_SHL_LONG:
625 case OP_SHL_LONG_2ADDR:
626 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
627 break;
628 case OP_SHR_LONG:
629 case OP_SHR_LONG_2ADDR:
630 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
631 break;
632 case OP_USHR_LONG:
633 case OP_USHR_LONG_2ADDR:
634 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
635 break;
636 default:
637 return true;
638 }
639 storeValuePair(cUnit, r0, r1, vDest, r2);
640 return false;
641}
Bill Buzbeed45ba372009-06-15 17:00:57 -0700642bool dvmCompilerGenArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
643 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700644{
645 void* funct;
646 /* TODO: use a proper include file to define these */
647 float __aeabi_fadd(float a, float b);
648 float __aeabi_fsub(float a, float b);
649 float __aeabi_fdiv(float a, float b);
650 float __aeabi_fmul(float a, float b);
651 float fmodf(float a, float b);
652
653 switch (mir->dalvikInsn.opCode) {
654 case OP_ADD_FLOAT_2ADDR:
655 case OP_ADD_FLOAT:
656 funct = (void*) __aeabi_fadd;
657 break;
658 case OP_SUB_FLOAT_2ADDR:
659 case OP_SUB_FLOAT:
660 funct = (void*) __aeabi_fsub;
661 break;
662 case OP_DIV_FLOAT_2ADDR:
663 case OP_DIV_FLOAT:
664 funct = (void*) __aeabi_fdiv;
665 break;
666 case OP_MUL_FLOAT_2ADDR:
667 case OP_MUL_FLOAT:
668 funct = (void*) __aeabi_fmul;
669 break;
670 case OP_REM_FLOAT_2ADDR:
671 case OP_REM_FLOAT:
672 funct = (void*) fmodf;
673 break;
674 case OP_NEG_FLOAT: {
675 loadValue(cUnit, vSrc2, r0);
676 loadConstant(cUnit, r1, 0x80000000);
677 newLIR3(cUnit, ARMV5TE_ADD_RRR, r0, r0, r1);
678 storeValue(cUnit, r0, vDest, r1);
679 return false;
680 }
681 default:
682 return true;
683 }
684 loadConstant(cUnit, r2, (int)funct);
685 loadValue(cUnit, vSrc1, r0);
686 loadValue(cUnit, vSrc2, r1);
687 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
688 storeValue(cUnit, r0, vDest, r1);
689 return false;
690}
691
Bill Buzbeed45ba372009-06-15 17:00:57 -0700692bool dvmCompilerGenArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
693 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700694{
695 void* funct;
696 /* TODO: use a proper include file to define these */
697 double __aeabi_dadd(double a, double b);
698 double __aeabi_dsub(double a, double b);
699 double __aeabi_ddiv(double a, double b);
700 double __aeabi_dmul(double a, double b);
701 double fmod(double a, double b);
702
703 switch (mir->dalvikInsn.opCode) {
704 case OP_ADD_DOUBLE_2ADDR:
705 case OP_ADD_DOUBLE:
706 funct = (void*) __aeabi_dadd;
707 break;
708 case OP_SUB_DOUBLE_2ADDR:
709 case OP_SUB_DOUBLE:
710 funct = (void*) __aeabi_dsub;
711 break;
712 case OP_DIV_DOUBLE_2ADDR:
713 case OP_DIV_DOUBLE:
714 funct = (void*) __aeabi_ddiv;
715 break;
716 case OP_MUL_DOUBLE_2ADDR:
717 case OP_MUL_DOUBLE:
718 funct = (void*) __aeabi_dmul;
719 break;
720 case OP_REM_DOUBLE_2ADDR:
721 case OP_REM_DOUBLE:
722 funct = (void*) fmod;
723 break;
724 case OP_NEG_DOUBLE: {
725 loadValuePair(cUnit, vSrc2, r0, r1);
726 loadConstant(cUnit, r2, 0x80000000);
727 newLIR3(cUnit, ARMV5TE_ADD_RRR, r1, r1, r2);
728 storeValuePair(cUnit, r0, r1, vDest, r2);
729 return false;
730 }
731 default:
732 return true;
733 }
734 loadConstant(cUnit, r4PC, (int)funct);
735 loadValuePair(cUnit, vSrc1, r0, r1);
736 loadValuePair(cUnit, vSrc2, r2, r3);
737 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
738 storeValuePair(cUnit, r0, r1, vDest, r2);
739 return false;
740}
741
742static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
743 int vSrc1, int vSrc2)
744{
745 int firstOp = ARMV5TE_BKPT;
746 int secondOp = ARMV5TE_BKPT;
747 bool callOut = false;
748 void *callTgt;
749 int retReg = r0;
750 /* TODO - find proper .h file to declare these */
751 long long __aeabi_ldivmod(long long op1, long long op2);
752
753 switch (mir->dalvikInsn.opCode) {
754 case OP_NOT_LONG:
755 firstOp = ARMV5TE_MVN;
756 secondOp = ARMV5TE_MVN;
757 break;
758 case OP_ADD_LONG:
759 case OP_ADD_LONG_2ADDR:
760 firstOp = ARMV5TE_ADD_RRR;
761 secondOp = ARMV5TE_ADC;
762 break;
763 case OP_SUB_LONG:
764 case OP_SUB_LONG_2ADDR:
765 firstOp = ARMV5TE_SUB_RRR;
766 secondOp = ARMV5TE_SBC;
767 break;
768 case OP_MUL_LONG:
769 case OP_MUL_LONG_2ADDR:
770 loadValuePair(cUnit, vSrc1, r0, r1);
771 loadValuePair(cUnit, vSrc2, r2, r3);
772 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
773 storeValuePair(cUnit, r0, r1, vDest, r2);
774 return false;
775 break;
776 case OP_DIV_LONG:
777 case OP_DIV_LONG_2ADDR:
778 callOut = true;
779 retReg = r0;
780 callTgt = (void*)__aeabi_ldivmod;
781 break;
782 /* NOTE - result is in r2/r3 instead of r0/r1 */
783 case OP_REM_LONG:
784 case OP_REM_LONG_2ADDR:
785 callOut = true;
786 callTgt = (void*)__aeabi_ldivmod;
787 retReg = r2;
788 break;
789 case OP_AND_LONG:
790 case OP_AND_LONG_2ADDR:
791 firstOp = ARMV5TE_AND_RR;
792 secondOp = ARMV5TE_AND_RR;
793 break;
794 case OP_OR_LONG:
795 case OP_OR_LONG_2ADDR:
796 firstOp = ARMV5TE_ORR;
797 secondOp = ARMV5TE_ORR;
798 break;
799 case OP_XOR_LONG:
800 case OP_XOR_LONG_2ADDR:
801 firstOp = ARMV5TE_EOR;
802 secondOp = ARMV5TE_EOR;
803 break;
804 case OP_NEG_LONG:
805 loadValuePair(cUnit, vSrc2, r2, r3);
806 loadConstant(cUnit, r1, 0);
807 newLIR3(cUnit, ARMV5TE_SUB_RRR, r0, r1, r2);
808 newLIR2(cUnit, ARMV5TE_SBC, r1, r3);
809 storeValuePair(cUnit, r0, r1, vDest, r2);
810 return false;
811 default:
812 LOGE("Invalid long arith op");
813 dvmAbort();
814 }
815 if (!callOut) {
816 loadValuePair(cUnit, vSrc1, r0, r1);
817 loadValuePair(cUnit, vSrc2, r2, r3);
818 genBinaryOpWide(cUnit, vDest, firstOp, secondOp);
819 } else {
820 loadValuePair(cUnit, vSrc2, r2, r3);
821 loadConstant(cUnit, r4PC, (int) callTgt);
822 loadValuePair(cUnit, vSrc1, r0, r1);
823 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
824 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
825 }
826 return false;
827}
828
829static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
830 int vSrc1, int vSrc2)
831{
832 int armOp = ARMV5TE_BKPT;
833 bool callOut = false;
834 bool checkZero = false;
835 int retReg = r0;
836 void *callTgt;
837
838 /* TODO - find proper .h file to declare these */
839 int __aeabi_idivmod(int op1, int op2);
840 int __aeabi_idiv(int op1, int op2);
841
842 switch (mir->dalvikInsn.opCode) {
843 case OP_NEG_INT:
844 armOp = ARMV5TE_NEG;
845 break;
846 case OP_NOT_INT:
847 armOp = ARMV5TE_MVN;
848 break;
849 case OP_ADD_INT:
850 case OP_ADD_INT_2ADDR:
851 armOp = ARMV5TE_ADD_RRR;
852 break;
853 case OP_SUB_INT:
854 case OP_SUB_INT_2ADDR:
855 armOp = ARMV5TE_SUB_RRR;
856 break;
857 case OP_MUL_INT:
858 case OP_MUL_INT_2ADDR:
859 armOp = ARMV5TE_MUL;
860 break;
861 case OP_DIV_INT:
862 case OP_DIV_INT_2ADDR:
863 callOut = true;
864 checkZero = true;
865 callTgt = __aeabi_idiv;
866 retReg = r0;
867 break;
868 /* NOTE: returns in r1 */
869 case OP_REM_INT:
870 case OP_REM_INT_2ADDR:
871 callOut = true;
872 checkZero = true;
873 callTgt = __aeabi_idivmod;
874 retReg = r1;
875 break;
876 case OP_AND_INT:
877 case OP_AND_INT_2ADDR:
878 armOp = ARMV5TE_AND_RR;
879 break;
880 case OP_OR_INT:
881 case OP_OR_INT_2ADDR:
882 armOp = ARMV5TE_ORR;
883 break;
884 case OP_XOR_INT:
885 case OP_XOR_INT_2ADDR:
886 armOp = ARMV5TE_EOR;
887 break;
888 case OP_SHL_INT:
889 case OP_SHL_INT_2ADDR:
890 armOp = ARMV5TE_LSLV;
891 break;
892 case OP_SHR_INT:
893 case OP_SHR_INT_2ADDR:
894 armOp = ARMV5TE_ASRV;
895 break;
896 case OP_USHR_INT:
897 case OP_USHR_INT_2ADDR:
898 armOp = ARMV5TE_LSRV;
899 break;
900 default:
901 LOGE("Invalid word arith op: 0x%x(%d)",
902 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
903 dvmAbort();
904 }
905 if (!callOut) {
906 loadValue(cUnit, vSrc1, r0);
907 loadValue(cUnit, vSrc2, r1);
908 genBinaryOp(cUnit, vDest, armOp);
909 } else {
910 loadValue(cUnit, vSrc2, r1);
911 loadConstant(cUnit, r2, (int) callTgt);
912 loadValue(cUnit, vSrc1, r0);
913 if (checkZero) {
914 genNullCheck(cUnit, r1, mir->offset, NULL);
915 }
916 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
917 storeValue(cUnit, retReg, vDest, r2);
918 }
919 return false;
920}
921
922static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
923{
924 OpCode opCode = mir->dalvikInsn.opCode;
925 int vA = mir->dalvikInsn.vA;
926 int vB = mir->dalvikInsn.vB;
927 int vC = mir->dalvikInsn.vC;
928
929 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
930 return genArithOpLong(cUnit,mir, vA, vA, vB);
931 }
932 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
933 return genArithOpLong(cUnit,mir, vA, vB, vC);
934 }
935 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
936 return genShiftOpLong(cUnit,mir, vA, vA, vB);
937 }
938 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
939 return genShiftOpLong(cUnit,mir, vA, vB, vC);
940 }
941 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
942 return genArithOpInt(cUnit,mir, vA, vA, vB);
943 }
944 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
945 return genArithOpInt(cUnit,mir, vA, vB, vC);
946 }
947 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -0700948 return dvmCompilerGenArithOpFloat(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700949 }
950 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -0700951 return dvmCompilerGenArithOpFloat(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700952 }
953 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -0700954 return dvmCompilerGenArithOpDouble(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700955 }
956 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -0700957 return dvmCompilerGenArithOpDouble(cUnit,mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700958 }
959 return true;
960}
961
Bill Buzbeed45ba372009-06-15 17:00:57 -0700962static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
963 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700964{
965 loadConstant(cUnit, r2, (int)funct);
966 if (srcSize == 1) {
967 loadValue(cUnit, mir->dalvikInsn.vB, r0);
968 } else {
969 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
970 }
971 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
972 if (tgtSize == 1) {
973 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
974 } else {
975 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
976 }
977 return false;
978}
979
980/* Experimental example of completely inlining a native replacement */
981static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
982{
983 int offset = (int) &((InterpState *) NULL)->retval;
984 DecodedInstruction *dInsn = &mir->dalvikInsn;
985 assert(dInsn->vA == 1);
986 loadValue(cUnit, dInsn->arg[0], r0);
987 loadConstant(cUnit, r1, gDvm.offJavaLangString_count);
988 genNullCheck(cUnit, r0, mir->offset, NULL);
989 newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r0, r1);
990 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
991 return false;
992}
993
994static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
995 DecodedInstruction *dInsn,
996 Armv5teLIR **pcrLabel)
997{
998 unsigned int i;
999 unsigned int regMask = 0;
1000
1001 /* Load arguments to r0..r4 */
1002 for (i = 0; i < dInsn->vA; i++) {
1003 regMask |= 1 << i;
1004 loadValue(cUnit, dInsn->arg[i], i);
1005 }
1006 if (regMask) {
1007 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
1008 newLIR2(cUnit, ARMV5TE_MOV_RR, r7, rFP);
1009 newLIR2(cUnit, ARMV5TE_SUB_RI8, r7,
1010 sizeof(StackSaveArea) + (dInsn->vA << 2));
1011 /* generate null check */
1012 if (pcrLabel) {
1013 *pcrLabel = genNullCheck(cUnit, r0, mir->offset, NULL);
1014 }
1015 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1016 }
1017}
1018
1019static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1020 DecodedInstruction *dInsn,
1021 Armv5teLIR **pcrLabel)
1022{
1023 int srcOffset = dInsn->vC << 2;
1024 int numArgs = dInsn->vA;
1025 int regMask;
1026 /*
1027 * r4PC : &rFP[vC]
1028 * r7: &newFP[0]
1029 */
1030 if (srcOffset < 8) {
1031 newLIR3(cUnit, ARMV5TE_ADD_RRI3, r4PC, rFP, srcOffset);
1032 } else {
1033 loadConstant(cUnit, r4PC, srcOffset);
1034 newLIR3(cUnit, ARMV5TE_ADD_RRR, r4PC, rFP, r4PC);
1035 }
1036 /* load [r0 .. min(numArgs,4)] */
1037 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
1038 newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
1039
1040 if (sizeof(StackSaveArea) + (numArgs << 2) < 256) {
1041 newLIR2(cUnit, ARMV5TE_MOV_RR, r7, rFP);
1042 newLIR2(cUnit, ARMV5TE_SUB_RI8, r7,
1043 sizeof(StackSaveArea) + (numArgs << 2));
1044 } else {
1045 loadConstant(cUnit, r7, sizeof(StackSaveArea) + (numArgs << 2));
1046 newLIR3(cUnit, ARMV5TE_SUB_RRR, r7, rFP, r7);
1047 }
1048
1049 /* generate null check */
1050 if (pcrLabel) {
1051 *pcrLabel = genNullCheck(cUnit, r0, mir->offset, NULL);
1052 }
1053
1054 /*
1055 * Handle remaining 4n arguments:
1056 * store previously loaded 4 values and load the next 4 values
1057 */
1058 if (numArgs >= 8) {
1059 Armv5teLIR *loopLabel = NULL;
1060 /*
1061 * r0 contains "this" and it will be used later, so push it to the stack
1062 * first. Pushing r5 is just for stack alignment purposes.
1063 */
1064 newLIR1(cUnit, ARMV5TE_PUSH, 1 << r0 | 1 << 5);
1065 /* No need to generate the loop structure if numArgs <= 11 */
1066 if (numArgs > 11) {
1067 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
1068 loopLabel = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
1069 }
1070 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1071 newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
1072 /* No need to generate the loop structure if numArgs <= 11 */
1073 if (numArgs > 11) {
1074 newLIR2(cUnit, ARMV5TE_SUB_RI8, 5, 4);
1075 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1076 }
1077 }
1078
1079 /* Save the last batch of loaded values */
1080 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1081
1082 /* Generate the loop epilogue - don't use r0 */
1083 if ((numArgs > 4) && (numArgs % 4)) {
1084 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
1085 newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
1086 }
1087 if (numArgs >= 8)
1088 newLIR1(cUnit, ARMV5TE_POP, 1 << r0 | 1 << 5);
1089
1090 /* Save the modulo 4 arguments */
1091 if ((numArgs > 4) && (numArgs % 4)) {
1092 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1093 }
1094}
1095
1096static void genInvokeCommon(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
1097 Armv5teLIR *labelList, Armv5teLIR *pcrLabel,
1098 const Method *calleeMethod)
1099{
1100 Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
1101
1102 /* r1 = &retChainingCell */
1103 Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
1104 r1, 0);
1105 /* r4PC = dalvikCallsite */
1106 loadConstant(cUnit, r4PC,
1107 (int) (cUnit->method->insns + mir->offset));
1108 addrRetChain->generic.target = (LIR *) retChainingCell;
1109 /*
1110 * r0 = calleeMethod (loaded upon calling genInvokeCommon)
1111 * r1 = &ChainingCell
1112 * r4PC = callsiteDPC
1113 */
1114 if (dvmIsNativeMethod(calleeMethod)) {
1115 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1116#if defined(INVOKE_STATS)
1117 gDvmJit.invokeNoOpt++;
1118#endif
1119 } else {
1120 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1121#if defined(INVOKE_STATS)
1122 gDvmJit.invokeChain++;
1123#endif
1124 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1125 }
1126 /* Handle exceptions using the interpreter */
1127 genTrap(cUnit, mir->offset, pcrLabel);
1128}
1129
1130/* Geneate a branch to go back to the interpreter */
1131static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1132{
1133 /* r0 = dalvik pc */
1134 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
1135 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE,
1136 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpPunt) >> 2);
1137 newLIR1(cUnit, ARMV5TE_BLX_R, r1);
1138}
1139
1140/*
1141 * Attempt to single step one instruction using the interpreter and return
1142 * to the compiled code for the next Dalvik instruction
1143 */
1144static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1145{
1146 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1147 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1148 kInstrCanThrow;
1149 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1150 genPuntToInterp(cUnit, mir->offset);
1151 return;
1152 }
1153 int entryAddr = offsetof(InterpState,
1154 jitToInterpEntries.dvmJitToInterpSingleStep);
1155 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r2, rGLUE, entryAddr >> 2);
1156 /* r0 = dalvik pc */
1157 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1158 /* r1 = dalvik pc of following instruction */
1159 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
1160 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1161}
1162
1163
1164/*****************************************************************************/
1165/*
1166 * The following are the first-level codegen routines that analyze the format
1167 * of each bytecode then either dispatch special purpose codegen routines
1168 * or produce corresponding Thumb instructions directly.
1169 */
1170
1171static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
1172 BasicBlock *bb, Armv5teLIR *labelList)
1173{
1174 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1175 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1176 return false;
1177}
1178
1179static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1180{
1181 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1182 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1183 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
1184 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1185 return true;
1186 }
1187 switch (dalvikOpCode) {
1188 case OP_RETURN_VOID:
1189 genReturnCommon(cUnit,mir);
1190 break;
1191 case OP_UNUSED_73:
1192 case OP_UNUSED_79:
1193 case OP_UNUSED_7A:
1194 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1195 return true;
1196 case OP_NOP:
1197 break;
1198 default:
1199 return true;
1200 }
1201 return false;
1202}
1203
1204static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1205{
1206 switch (mir->dalvikInsn.opCode) {
1207 case OP_CONST:
1208 case OP_CONST_4:
1209 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
1210 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1211 break;
1212 case OP_CONST_WIDE_32:
1213 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
1214 newLIR3(cUnit, ARMV5TE_ASR, r1, r0, 31);
1215 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1216 break;
1217 default:
1218 return true;
1219 }
1220 return false;
1221}
1222
1223static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1224{
1225 switch (mir->dalvikInsn.opCode) {
1226 case OP_CONST_HIGH16:
1227 loadConstant(cUnit, r0, mir->dalvikInsn.vB << 16);
1228 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1229 break;
1230 case OP_CONST_WIDE_HIGH16:
1231 loadConstant(cUnit, r1, mir->dalvikInsn.vB << 16);
1232 loadConstant(cUnit, r0, 0);
1233 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1234 break;
1235 default:
1236 return true;
1237 }
1238 return false;
1239}
1240
1241static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1242{
1243 /* For OP_THROW_VERIFICATION_ERROR */
1244 genInterpSingleStep(cUnit, mir);
1245 return false;
1246}
1247
1248static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1249{
1250 switch (mir->dalvikInsn.opCode) {
1251 /*
1252 * TODO: Verify that we can ignore the resolution check here because
1253 * it will have already successfully been interpreted once
1254 */
1255 case OP_CONST_STRING_JUMBO:
1256 case OP_CONST_STRING: {
1257 void *strPtr = (void*)
1258 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1259 assert(strPtr != NULL);
1260 loadConstant(cUnit, r0, (int) strPtr );
1261 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1262 break;
1263 }
1264 /*
1265 * TODO: Verify that we can ignore the resolution check here because
1266 * it will have already successfully been interpreted once
1267 */
1268 case OP_CONST_CLASS: {
1269 void *classPtr = (void*)
1270 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1271 assert(classPtr != NULL);
1272 loadConstant(cUnit, r0, (int) classPtr );
1273 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1274 break;
1275 }
1276 case OP_SGET_OBJECT:
1277 case OP_SGET_BOOLEAN:
1278 case OP_SGET_CHAR:
1279 case OP_SGET_BYTE:
1280 case OP_SGET_SHORT:
1281 case OP_SGET: {
1282 int valOffset = (int)&((struct StaticField*)NULL)->value;
1283 void *fieldPtr = (void*)
1284 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1285 assert(fieldPtr != NULL);
1286 loadConstant(cUnit, r0, (int) fieldPtr + valOffset);
1287 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0, 0);
1288 storeValue(cUnit, r0, mir->dalvikInsn.vA, r2);
1289 break;
1290 }
1291 case OP_SGET_WIDE: {
1292 int valOffset = (int)&((struct StaticField*)NULL)->value;
1293 void *fieldPtr = (void*)
1294 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1295 assert(fieldPtr != NULL);
1296 loadConstant(cUnit, r2, (int) fieldPtr + valOffset);
1297 newLIR2(cUnit, ARMV5TE_LDMIA, r2, (1<<r0 | 1<<r1));
1298 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1299 break;
1300 }
1301 case OP_SPUT_OBJECT:
1302 case OP_SPUT_BOOLEAN:
1303 case OP_SPUT_CHAR:
1304 case OP_SPUT_BYTE:
1305 case OP_SPUT_SHORT:
1306 case OP_SPUT: {
1307 int valOffset = (int)&((struct StaticField*)NULL)->value;
1308 void *fieldPtr = (void*)
1309 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1310 assert(fieldPtr != NULL);
1311 loadValue(cUnit, mir->dalvikInsn.vA, r0);
1312 loadConstant(cUnit, r1, (int) fieldPtr + valOffset);
1313 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, r1, 0);
1314 break;
1315 }
1316 case OP_SPUT_WIDE: {
1317 int valOffset = (int)&((struct StaticField*)NULL)->value;
1318 void *fieldPtr = (void*)
1319 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1320 assert(fieldPtr != NULL);
1321 loadValuePair(cUnit, mir->dalvikInsn.vA, r0, r1);
1322 loadConstant(cUnit, r2, (int) fieldPtr + valOffset);
1323 newLIR2(cUnit, ARMV5TE_STMIA, r2, (1<<r0 | 1<<r1));
1324 break;
1325 }
1326 case OP_NEW_INSTANCE: {
1327 ClassObject *classPtr = (void*)
1328 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1329 assert(classPtr != NULL);
1330 assert(classPtr->status & CLASS_INITIALIZED);
1331 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
1332 /* It's going to throw, just let the interp. deal with it. */
1333 genInterpSingleStep(cUnit, mir);
1334 return false;
1335 }
1336 loadConstant(cUnit, r0, (int) classPtr);
1337 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
1338 genExportPC(cUnit, mir, r2, r3 );
1339 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
1340 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
1341 /*
1342 * TODO: As coded, we'll bail and reinterpret on alloc failure.
1343 * Need a general mechanism to bail to thrown exception code.
1344 */
1345 genNullCheck(cUnit, r0, mir->offset, NULL);
1346 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1347 break;
1348 }
1349 case OP_CHECK_CAST: {
1350 ClassObject *classPtr =
1351 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1352 loadConstant(cUnit, r1, (int) classPtr );
1353 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
1354 /*
1355 * TODO - in theory classPtr should be resoved by the time this
1356 * instruction made into a trace, but we are seeing NULL at runtime
1357 * so this check is temporarily used as a workaround.
1358 */
1359 Armv5teLIR * pcrLabel = genNullCheck(cUnit, r1, mir->offset, NULL);
1360 newLIR2(cUnit, ARMV5TE_CMP_RI8, r0, 0); /* Null? */
1361 Armv5teLIR *branch1 =
1362 newLIR2(cUnit, ARMV5TE_B_COND, 4, ARM_COND_EQ);
1363 /* r0 now contains object->clazz */
1364 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
1365 offsetof(Object, clazz) >> 2);
1366 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
1367 newLIR2(cUnit, ARMV5TE_CMP_RR, r0, r1);
1368 Armv5teLIR *branch2 =
1369 newLIR2(cUnit, ARMV5TE_B_COND, 2, ARM_COND_EQ);
1370 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
1371 /* check cast failed - punt to the interpreter */
1372 genNullCheck(cUnit, r0, mir->offset, pcrLabel);
1373 /* check cast passed - branch target here */
1374 Armv5teLIR *target = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
1375 branch1->generic.target = (LIR *)target;
1376 branch2->generic.target = (LIR *)target;
1377 break;
1378 }
1379 default:
1380 return true;
1381 }
1382 return false;
1383}
1384
1385static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1386{
1387 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1388 switch (dalvikOpCode) {
1389 case OP_MOVE_EXCEPTION: {
1390 int offset = offsetof(InterpState, self);
1391 int exOffset = offsetof(Thread, exception);
1392 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
1393 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, r0, exOffset >> 2);
1394 storeValue(cUnit, r1, mir->dalvikInsn.vA, r0);
1395 break;
1396 }
1397 case OP_MOVE_RESULT:
1398 case OP_MOVE_RESULT_OBJECT: {
1399 int offset = offsetof(InterpState, retval);
1400 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
1401 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1402 break;
1403 }
1404 case OP_MOVE_RESULT_WIDE: {
1405 int offset = offsetof(InterpState, retval);
1406 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
1407 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE, (offset >> 2)+1);
1408 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1409 break;
1410 }
1411 case OP_RETURN_WIDE: {
1412 loadValuePair(cUnit, mir->dalvikInsn.vA, r0, r1);
1413 int offset = offsetof(InterpState, retval);
1414 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
1415 newLIR3(cUnit, ARMV5TE_STR_RRI5, r1, rGLUE, (offset >> 2)+1);
1416 genReturnCommon(cUnit,mir);
1417 break;
1418 }
1419 case OP_RETURN:
1420 case OP_RETURN_OBJECT: {
1421 loadValue(cUnit, mir->dalvikInsn.vA, r0);
1422 int offset = offsetof(InterpState, retval);
1423 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
1424 genReturnCommon(cUnit,mir);
1425 break;
1426 }
1427 /*
1428 * TODO-VERIFY: May be playing a bit fast and loose here. As coded,
1429 * a failure on lock/unlock will cause us to revert to the interpeter
1430 * to try again. This means we essentially ignore the first failure on
1431 * the assumption that the interpreter will correctly handle the 2nd.
1432 */
1433 case OP_MONITOR_ENTER:
1434 case OP_MONITOR_EXIT: {
1435 int offset = offsetof(InterpState, self);
1436 loadValue(cUnit, mir->dalvikInsn.vA, r1);
1437 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
1438 if (dalvikOpCode == OP_MONITOR_ENTER) {
1439 loadConstant(cUnit, r2, (int)dvmLockObject);
1440 } else {
1441 loadConstant(cUnit, r2, (int)dvmUnlockObject);
1442 }
1443 /*
1444 * TODO-VERIFY: Note that we're not doing an EXPORT_PC, as
1445 * Lock/unlock won't throw, and this code does not support
1446 * DEADLOCK_PREDICTION or MONITOR_TRACKING. Should it?
1447 */
1448 genNullCheck(cUnit, r1, mir->offset, NULL);
1449 /* Do the call */
1450 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1451 break;
1452 }
1453 case OP_THROW: {
1454 genInterpSingleStep(cUnit, mir);
1455 break;
1456 }
1457 default:
1458 return true;
1459 }
1460 return false;
1461}
1462
Bill Buzbeed45ba372009-06-15 17:00:57 -07001463bool dvmCompilerGenConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001464{
1465 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001466
Ben Chengba4fc8b2009-06-01 13:00:29 -07001467 float __aeabi_i2f( int op1 );
1468 int __aeabi_f2iz( float op1 );
1469 float __aeabi_d2f( double op1 );
1470 double __aeabi_f2d( float op1 );
1471 double __aeabi_i2d( int op1 );
1472 int __aeabi_d2iz( double op1 );
1473 long __aeabi_f2lz( float op1 );
1474 float __aeabi_l2f( long op1 );
1475 long __aeabi_d2lz( double op1 );
1476 double __aeabi_l2d( long op1 );
1477
Bill Buzbeed45ba372009-06-15 17:00:57 -07001478 switch (opCode) {
1479 case OP_INT_TO_FLOAT:
1480 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
1481 case OP_FLOAT_TO_INT:
1482 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
1483 case OP_DOUBLE_TO_FLOAT:
1484 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
1485 case OP_FLOAT_TO_DOUBLE:
1486 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
1487 case OP_INT_TO_DOUBLE:
1488 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
1489 case OP_DOUBLE_TO_INT:
1490 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
1491 case OP_FLOAT_TO_LONG:
1492 return genConversionCall(cUnit, mir, (void*)__aeabi_f2lz, 1, 2);
1493 case OP_LONG_TO_FLOAT:
1494 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
1495 case OP_DOUBLE_TO_LONG:
1496 return genConversionCall(cUnit, mir, (void*)__aeabi_d2lz, 2, 2);
1497 case OP_LONG_TO_DOUBLE:
1498 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
1499 default:
1500 return true;
1501 }
1502 return false;
1503}
1504
1505static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1506{
1507 OpCode opCode = mir->dalvikInsn.opCode;
1508 int vSrc1Dest = mir->dalvikInsn.vA;
1509 int vSrc2 = mir->dalvikInsn.vB;
1510
1511 /* TODO - find the proper include file to declare these */
1512
Ben Chengba4fc8b2009-06-01 13:00:29 -07001513 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1514 return genArithOp( cUnit, mir );
1515 }
1516
1517 switch (opCode) {
1518 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001519 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001520 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001521 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001522 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001523 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001524 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001525 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001526 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001527 case OP_LONG_TO_DOUBLE:
Bill Buzbeed45ba372009-06-15 17:00:57 -07001528 return dvmCompilerGenConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001529 case OP_NEG_INT:
1530 case OP_NOT_INT:
1531 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
1532 case OP_NEG_LONG:
1533 case OP_NOT_LONG:
1534 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
1535 case OP_NEG_FLOAT:
Bill Buzbeed45ba372009-06-15 17:00:57 -07001536 return dvmCompilerGenArithOpFloat(cUnit, mir, vSrc1Dest,
1537 vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001538 case OP_NEG_DOUBLE:
Bill Buzbeed45ba372009-06-15 17:00:57 -07001539 return dvmCompilerGenArithOpDouble(cUnit, mir, vSrc1Dest,
1540 vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001541 case OP_MOVE_WIDE:
1542 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
1543 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1544 break;
1545 case OP_INT_TO_LONG:
1546 loadValue(cUnit, mir->dalvikInsn.vB, r0);
1547 newLIR3(cUnit, ARMV5TE_ASR, r1, r0, 31);
1548 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1549 break;
1550 case OP_MOVE:
1551 case OP_MOVE_OBJECT:
1552 case OP_LONG_TO_INT:
1553 loadValue(cUnit, vSrc2, r0);
1554 storeValue(cUnit, r0, vSrc1Dest, r1);
1555 break;
1556 case OP_INT_TO_BYTE:
1557 loadValue(cUnit, vSrc2, r0);
1558 newLIR3(cUnit, ARMV5TE_LSL, r0, r0, 24);
1559 newLIR3(cUnit, ARMV5TE_ASR, r0, r0, 24);
1560 storeValue(cUnit, r0, vSrc1Dest, r1);
1561 break;
1562 case OP_INT_TO_SHORT:
1563 loadValue(cUnit, vSrc2, r0);
1564 newLIR3(cUnit, ARMV5TE_LSL, r0, r0, 16);
1565 newLIR3(cUnit, ARMV5TE_ASR, r0, r0, 16);
1566 storeValue(cUnit, r0, vSrc1Dest, r1);
1567 break;
1568 case OP_INT_TO_CHAR:
1569 loadValue(cUnit, vSrc2, r0);
1570 newLIR3(cUnit, ARMV5TE_LSL, r0, r0, 16);
1571 newLIR3(cUnit, ARMV5TE_LSR, r0, r0, 16);
1572 storeValue(cUnit, r0, vSrc1Dest, r1);
1573 break;
1574 case OP_ARRAY_LENGTH: {
1575 int lenOffset = offsetof(ArrayObject, length);
1576 loadValue(cUnit, vSrc2, r0);
1577 genNullCheck(cUnit, r0, mir->offset, NULL);
1578 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0, lenOffset >> 2);
1579 storeValue(cUnit, r0, vSrc1Dest, r1);
1580 break;
1581 }
1582 default:
1583 return true;
1584 }
1585 return false;
1586}
1587
1588static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
1589{
1590 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1591 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
1592 if (dalvikOpCode == OP_CONST_WIDE_16) {
1593 int rDest = mir->dalvikInsn.vA;
1594 int BBBB = mir->dalvikInsn.vB;
1595 int rLow = r0, rHigh = r1;
1596 if (BBBB == 0) {
1597 newLIR2(cUnit, ARMV5TE_MOV_IMM, rLow, 0);
1598 rHigh = rLow;
1599 } else if (BBBB > 0 && BBBB <= 255) {
1600 /* rLow = ssssBBBB */
1601 newLIR2(cUnit, ARMV5TE_MOV_IMM, rLow, BBBB);
1602 /* rHigh = 0 */
1603 newLIR2(cUnit, ARMV5TE_MOV_IMM, rHigh, 0);
1604 } else {
1605 loadConstant(cUnit, rLow, BBBB);
1606 /*
1607 * arithmetic-shift-right 32 bits to get the high half of long
1608 * [63..32]
1609 */
1610 newLIR3(cUnit, ARMV5TE_ASR, rHigh, rLow, 0);
1611 }
1612
1613 /* Save the long values to the specified Dalvik register pair */
1614 /*
1615 * If rDest is no greater than 30, use two "str rd, [rFP + immed_5]"
1616 * instructions to store the results. Effective address is
1617 * rFP + immed_5 << 2.
1618 */
1619 if (rDest < 31) {
1620 newLIR3(cUnit, ARMV5TE_STR_RRI5, rLow, rFP, rDest);
1621 newLIR3(cUnit, ARMV5TE_STR_RRI5, rHigh, rFP, rDest+1);
1622 } else {
1623 /*
1624 * Otherwise just load the frame offset from the constant pool and add
1625 * it to rFP. Then use stmia to store the results to the specified
1626 * register pair.
1627 */
1628 /* Need to replicate the content in r0 to r1 */
1629 if (rLow == rHigh) {
1630 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rLow+1, rLow, 0);
1631 }
1632 /* load the rFP offset into r2 */
1633 loadConstant(cUnit, r2, rDest*4);
1634 newLIR3(cUnit, ARMV5TE_ADD_RRR, r2, rFP, r2);
1635 newLIR2(cUnit, ARMV5TE_STMIA, r2, (1<<r0 | 1 << r1));
1636 }
1637 } else if (dalvikOpCode == OP_CONST_16) {
1638 int rDest = mir->dalvikInsn.vA;
1639 int BBBB = mir->dalvikInsn.vB;
1640 if (BBBB >= 0 && BBBB <= 255) {
1641 /* r0 = BBBB */
1642 newLIR2(cUnit, ARMV5TE_MOV_IMM, r0, BBBB);
1643 } else {
1644 loadConstant(cUnit, r0, BBBB);
1645 }
1646
1647 /* Save the constant to the specified Dalvik register */
1648 /*
1649 * If rDest is no greater than 31, effective address is
1650 * rFP + immed_5 << 2.
1651 */
1652 if (rDest < 32) {
1653 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rFP, rDest);
1654 } else {
1655 /*
1656 * Otherwise just load the frame offset from the constant pool and add
1657 * it to rFP. Then use stmia to store the results to the specified
1658 * register pair.
1659 */
1660 /* load the rFP offset into r2 */
1661 loadConstant(cUnit, r2, rDest*4);
1662 newLIR3(cUnit, ARMV5TE_ADD_RRR, r2, rFP, r2);
1663 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, r2, 0);
1664 }
1665 } else {
1666 return true;
1667 }
1668 return false;
1669}
1670
1671/* Compare agaist zero */
1672static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
1673 Armv5teLIR *labelList)
1674{
1675 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1676 Armv5teConditionCode cond;
1677
1678 loadValue(cUnit, mir->dalvikInsn.vA, r0);
1679 newLIR2(cUnit, ARMV5TE_CMP_RI8, r0, 0);
1680
1681 switch (dalvikOpCode) {
1682 case OP_IF_EQZ:
1683 cond = ARM_COND_EQ;
1684 break;
1685 case OP_IF_NEZ:
1686 cond = ARM_COND_NE;
1687 break;
1688 case OP_IF_LTZ:
1689 cond = ARM_COND_LT;
1690 break;
1691 case OP_IF_GEZ:
1692 cond = ARM_COND_GE;
1693 break;
1694 case OP_IF_GTZ:
1695 cond = ARM_COND_GT;
1696 break;
1697 case OP_IF_LEZ:
1698 cond = ARM_COND_LE;
1699 break;
1700 default:
1701 cond = 0;
1702 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
1703 dvmAbort();
1704 }
1705 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1706 /* This mostly likely will be optimized away in a later phase */
1707 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1708 return false;
1709}
1710
1711static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
1712{
1713 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1714 int vSrc = mir->dalvikInsn.vB;
1715 int vDest = mir->dalvikInsn.vA;
1716 int lit = mir->dalvikInsn.vC;
1717 int armOp;
1718
1719 /* TODO: find the proper .h file to declare these */
1720 int __aeabi_idivmod(int op1, int op2);
1721 int __aeabi_idiv(int op1, int op2);
1722
1723 switch (dalvikOpCode) {
1724 case OP_ADD_INT_LIT8:
1725 case OP_ADD_INT_LIT16:
1726 loadValue(cUnit, vSrc, r0);
1727 if (lit <= 255 && lit >= 0) {
1728 newLIR2(cUnit, ARMV5TE_ADD_RI8, r0, lit);
1729 storeValue(cUnit, r0, vDest, r1);
1730 } else if (lit >= -255 && lit <= 0) {
1731 /* Convert to a small constant subtraction */
1732 newLIR2(cUnit, ARMV5TE_SUB_RI8, r0, -lit);
1733 storeValue(cUnit, r0, vDest, r1);
1734 } else {
1735 loadConstant(cUnit, r1, lit);
1736 genBinaryOp(cUnit, vDest, ARMV5TE_ADD_RRR);
1737 }
1738 break;
1739
1740 case OP_RSUB_INT_LIT8:
1741 case OP_RSUB_INT:
1742 loadValue(cUnit, vSrc, r1);
1743 loadConstant(cUnit, r0, lit);
1744 genBinaryOp(cUnit, vDest, ARMV5TE_SUB_RRR);
1745 break;
1746
1747 case OP_MUL_INT_LIT8:
1748 case OP_MUL_INT_LIT16:
1749 case OP_AND_INT_LIT8:
1750 case OP_AND_INT_LIT16:
1751 case OP_OR_INT_LIT8:
1752 case OP_OR_INT_LIT16:
1753 case OP_XOR_INT_LIT8:
1754 case OP_XOR_INT_LIT16:
1755 loadValue(cUnit, vSrc, r0);
1756 loadConstant(cUnit, r1, lit);
1757 switch (dalvikOpCode) {
1758 case OP_MUL_INT_LIT8:
1759 case OP_MUL_INT_LIT16:
1760 armOp = ARMV5TE_MUL;
1761 break;
1762 case OP_AND_INT_LIT8:
1763 case OP_AND_INT_LIT16:
1764 armOp = ARMV5TE_AND_RR;
1765 break;
1766 case OP_OR_INT_LIT8:
1767 case OP_OR_INT_LIT16:
1768 armOp = ARMV5TE_ORR;
1769 break;
1770 case OP_XOR_INT_LIT8:
1771 case OP_XOR_INT_LIT16:
1772 armOp = ARMV5TE_EOR;
1773 break;
1774 default:
1775 dvmAbort();
1776 }
1777 genBinaryOp(cUnit, vDest, armOp);
1778 break;
1779
1780 case OP_SHL_INT_LIT8:
1781 case OP_SHR_INT_LIT8:
1782 case OP_USHR_INT_LIT8:
1783 loadValue(cUnit, vSrc, r0);
1784 switch (dalvikOpCode) {
1785 case OP_SHL_INT_LIT8:
1786 armOp = ARMV5TE_LSL;
1787 break;
1788 case OP_SHR_INT_LIT8:
1789 armOp = ARMV5TE_ASR;
1790 break;
1791 case OP_USHR_INT_LIT8:
1792 armOp = ARMV5TE_LSR;
1793 break;
1794 default: dvmAbort();
1795 }
1796 newLIR3(cUnit, armOp, r0, r0, lit);
1797 storeValue(cUnit, r0, vDest, r1);
1798 break;
1799
1800 case OP_DIV_INT_LIT8:
1801 case OP_DIV_INT_LIT16:
1802 if (lit == 0) {
1803 /* Let the interpreter deal with div by 0 */
1804 genInterpSingleStep(cUnit, mir);
1805 return false;
1806 }
1807 loadConstant(cUnit, r2, (int)__aeabi_idiv);
1808 loadConstant(cUnit, r1, lit);
1809 loadValue(cUnit, vSrc, r0);
1810 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1811 storeValue(cUnit, r0, vDest, r2);
1812 break;
1813
1814 case OP_REM_INT_LIT8:
1815 case OP_REM_INT_LIT16:
1816 if (lit == 0) {
1817 /* Let the interpreter deal with div by 0 */
1818 genInterpSingleStep(cUnit, mir);
1819 return false;
1820 }
1821 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
1822 loadConstant(cUnit, r1, lit);
1823 loadValue(cUnit, vSrc, r0);
1824 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1825 storeValue(cUnit, r1, vDest, r2);
1826 break;
1827 default:
1828 return true;
1829 }
1830 return false;
1831}
1832
1833static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
1834{
1835 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1836 int fieldOffset;
1837
1838 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
1839 InstField *pInstField = (InstField *)
1840 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
1841 int fieldOffset;
1842
1843 assert(pInstField != NULL);
1844 fieldOffset = pInstField->byteOffset;
1845 } else {
1846 /* To make the compiler happy */
1847 fieldOffset = 0;
1848 }
1849 switch (dalvikOpCode) {
1850 /*
1851 * TODO: I may be assuming too much here.
1852 * Verify what is known at JIT time.
1853 */
1854 case OP_NEW_ARRAY: {
1855 void *classPtr = (void*)
1856 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
1857 assert(classPtr != NULL);
1858 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
1859 loadConstant(cUnit, r0, (int) classPtr );
1860 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
1861 Armv5teLIR *pcrLabel =
1862 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
1863 genExportPC(cUnit, mir, r2, r3 );
1864 newLIR2(cUnit, ARMV5TE_MOV_IMM,r2,ALLOC_DONT_TRACK);
1865 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
1866 /*
1867 * TODO: As coded, we'll bail and reinterpret on alloc failure.
1868 * Need a general mechanism to bail to thrown exception code.
1869 */
1870 genNullCheck(cUnit, r0, mir->offset, pcrLabel);
1871 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1872 break;
1873 }
1874 /*
1875 * TODO: I may be assuming too much here.
1876 * Verify what is known at JIT time.
1877 */
1878 case OP_INSTANCE_OF: {
1879 ClassObject *classPtr =
1880 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
1881 assert(classPtr != NULL);
1882 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Ref */
1883 loadConstant(cUnit, r2, (int) classPtr );
1884 loadConstant(cUnit, r0, 1); /* Assume true */
1885 newLIR2(cUnit, ARMV5TE_CMP_RI8, r1, 0); /* Null? */
1886 Armv5teLIR *branch1 = newLIR2(cUnit, ARMV5TE_B_COND, 4,
1887 ARM_COND_EQ);
1888 /* r1 now contains object->clazz */
1889 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, r1,
1890 offsetof(Object, clazz) >> 2);
1891 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
1892 newLIR2(cUnit, ARMV5TE_CMP_RR, r1, r2);
1893 Armv5teLIR *branch2 = newLIR2(cUnit, ARMV5TE_B_COND, 2,
1894 ARM_COND_EQ);
1895 newLIR2(cUnit, ARMV5TE_MOV_RR, r0, r1);
1896 newLIR2(cUnit, ARMV5TE_MOV_RR, r1, r2);
1897 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
1898 /* branch target here */
1899 Armv5teLIR *target = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
1900 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1901 branch1->generic.target = (LIR *)target;
1902 branch2->generic.target = (LIR *)target;
1903 break;
1904 }
1905 case OP_IGET_WIDE:
1906 genIGetWide(cUnit, mir, fieldOffset);
1907 break;
1908 case OP_IGET:
1909 case OP_IGET_OBJECT:
1910 genIGet(cUnit, mir, ARMV5TE_LDR_RRR, fieldOffset);
1911 break;
1912 case OP_IGET_BOOLEAN:
1913 genIGet(cUnit, mir, ARMV5TE_LDRB_RRR, fieldOffset);
1914 break;
1915 case OP_IGET_BYTE:
1916 genIGet(cUnit, mir, ARMV5TE_LDRSB_RRR, fieldOffset);
1917 break;
1918 case OP_IGET_CHAR:
1919 genIGet(cUnit, mir, ARMV5TE_LDRH_RRR, fieldOffset);
1920 break;
1921 case OP_IGET_SHORT:
1922 genIGet(cUnit, mir, ARMV5TE_LDRSH_RRR, fieldOffset);
1923 break;
1924 case OP_IPUT_WIDE:
1925 genIPutWide(cUnit, mir, fieldOffset);
1926 break;
1927 case OP_IPUT:
1928 case OP_IPUT_OBJECT:
1929 genIPut(cUnit, mir, ARMV5TE_STR_RRR, fieldOffset);
1930 break;
1931 case OP_IPUT_SHORT:
1932 case OP_IPUT_CHAR:
1933 genIPut(cUnit, mir, ARMV5TE_STRH_RRR, fieldOffset);
1934 break;
1935 case OP_IPUT_BYTE:
1936 case OP_IPUT_BOOLEAN:
1937 genIPut(cUnit, mir, ARMV5TE_STRB_RRR, fieldOffset);
1938 break;
1939 default:
1940 return true;
1941 }
1942 return false;
1943}
1944
1945static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
1946{
1947 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1948 int fieldOffset = mir->dalvikInsn.vC;
1949 switch (dalvikOpCode) {
1950 case OP_IGET_QUICK:
1951 case OP_IGET_OBJECT_QUICK:
1952 genIGet(cUnit, mir, ARMV5TE_LDR_RRR, fieldOffset);
1953 break;
1954 case OP_IPUT_QUICK:
1955 case OP_IPUT_OBJECT_QUICK:
1956 genIPut(cUnit, mir, ARMV5TE_STR_RRR, fieldOffset);
1957 break;
1958 case OP_IGET_WIDE_QUICK:
1959 genIGetWide(cUnit, mir, fieldOffset);
1960 break;
1961 case OP_IPUT_WIDE_QUICK:
1962 genIPutWide(cUnit, mir, fieldOffset);
1963 break;
1964 default:
1965 return true;
1966 }
1967 return false;
1968
1969}
1970
1971/* Compare agaist zero */
1972static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
1973 Armv5teLIR *labelList)
1974{
1975 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1976 Armv5teConditionCode cond;
1977
1978 loadValue(cUnit, mir->dalvikInsn.vA, r0);
1979 loadValue(cUnit, mir->dalvikInsn.vB, r1);
1980 newLIR2(cUnit, ARMV5TE_CMP_RR, r0, r1);
1981
1982 switch (dalvikOpCode) {
1983 case OP_IF_EQ:
1984 cond = ARM_COND_EQ;
1985 break;
1986 case OP_IF_NE:
1987 cond = ARM_COND_NE;
1988 break;
1989 case OP_IF_LT:
1990 cond = ARM_COND_LT;
1991 break;
1992 case OP_IF_GE:
1993 cond = ARM_COND_GE;
1994 break;
1995 case OP_IF_GT:
1996 cond = ARM_COND_GT;
1997 break;
1998 case OP_IF_LE:
1999 cond = ARM_COND_LE;
2000 break;
2001 default:
2002 cond = 0;
2003 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2004 dvmAbort();
2005 }
2006 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2007 /* This mostly likely will be optimized away in a later phase */
2008 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2009 return false;
2010}
2011
2012static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2013{
2014 OpCode opCode = mir->dalvikInsn.opCode;
2015 int vSrc1Dest = mir->dalvikInsn.vA;
2016 int vSrc2 = mir->dalvikInsn.vB;
2017
2018 switch (opCode) {
2019 case OP_MOVE_16:
2020 case OP_MOVE_OBJECT_16:
2021 case OP_MOVE_FROM16:
2022 case OP_MOVE_OBJECT_FROM16:
2023 loadValue(cUnit, vSrc2, r0);
2024 storeValue(cUnit, r0, vSrc1Dest, r1);
2025 break;
2026 case OP_MOVE_WIDE_16:
2027 case OP_MOVE_WIDE_FROM16:
2028 loadValuePair(cUnit, vSrc2, r0, r1);
2029 storeValuePair(cUnit, r0, r1, vSrc1Dest, r2);
2030 break;
2031 default:
2032 return true;
2033 }
2034 return false;
2035}
2036
2037static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2038{
2039 OpCode opCode = mir->dalvikInsn.opCode;
2040 int vA = mir->dalvikInsn.vA;
2041 int vB = mir->dalvikInsn.vB;
2042 int vC = mir->dalvikInsn.vC;
2043
2044 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2045 return genArithOp( cUnit, mir );
2046 }
2047
2048 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002049 case OP_CMPL_FLOAT:
2050 case OP_CMPG_FLOAT:
2051 case OP_CMPL_DOUBLE:
2052 case OP_CMPG_DOUBLE:
2053 return dvmCompilerGenCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002054 case OP_CMP_LONG:
2055 loadValuePair(cUnit,vB, r0, r1);
2056 loadValuePair(cUnit, vC, r2, r3);
2057 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
2058 storeValue(cUnit, r0, vA, r1);
2059 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002060 case OP_AGET_WIDE:
2061 genArrayGet(cUnit, mir, ARMV5TE_LDR_RRR, vB, vC, vA, 3);
2062 break;
2063 case OP_AGET:
2064 case OP_AGET_OBJECT:
2065 genArrayGet(cUnit, mir, ARMV5TE_LDR_RRR, vB, vC, vA, 2);
2066 break;
2067 case OP_AGET_BOOLEAN:
2068 genArrayGet(cUnit, mir, ARMV5TE_LDRB_RRR, vB, vC, vA, 0);
2069 break;
2070 case OP_AGET_BYTE:
2071 genArrayGet(cUnit, mir, ARMV5TE_LDRSB_RRR, vB, vC, vA, 0);
2072 break;
2073 case OP_AGET_CHAR:
2074 genArrayGet(cUnit, mir, ARMV5TE_LDRH_RRR, vB, vC, vA, 1);
2075 break;
2076 case OP_AGET_SHORT:
2077 genArrayGet(cUnit, mir, ARMV5TE_LDRSH_RRR, vB, vC, vA, 1);
2078 break;
2079 case OP_APUT_WIDE:
2080 genArrayPut(cUnit, mir, ARMV5TE_STR_RRR, vB, vC, vA, 3);
2081 break;
2082 case OP_APUT:
2083 case OP_APUT_OBJECT:
2084 genArrayPut(cUnit, mir, ARMV5TE_STR_RRR, vB, vC, vA, 2);
2085 break;
2086 case OP_APUT_SHORT:
2087 case OP_APUT_CHAR:
2088 genArrayPut(cUnit, mir, ARMV5TE_STRH_RRR, vB, vC, vA, 1);
2089 break;
2090 case OP_APUT_BYTE:
2091 case OP_APUT_BOOLEAN:
2092 genArrayPut(cUnit, mir, ARMV5TE_STRB_RRR, vB, vC, vA, 0);
2093 break;
2094 default:
2095 return true;
2096 }
2097 return false;
2098}
2099
2100static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2101{
2102 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2103 switch (dalvikOpCode) {
2104 case OP_FILL_ARRAY_DATA: {
2105 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2106 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2107 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2108 (int) (cUnit->method->insns + mir->offset));
2109 genExportPC(cUnit, mir, r2, r3 );
2110 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
2111 genNullCheck(cUnit, r0, mir->offset, NULL);
2112 break;
2113 }
2114 /*
2115 * TODO
2116 * - Add a 1 to 3-entry per-location cache here to completely
2117 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2118 * - Use out-of-line handlers for both of these
2119 */
2120 case OP_PACKED_SWITCH:
2121 case OP_SPARSE_SWITCH: {
2122 if (dalvikOpCode == OP_PACKED_SWITCH) {
2123 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2124 } else {
2125 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2126 }
2127 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2128 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2129 (int) (cUnit->method->insns + mir->offset));
2130 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
2131 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
2132 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r2, rGLUE,
2133 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNoChain)
2134 >> 2);
2135 newLIR3(cUnit, ARMV5TE_ADD_RRR, r0, r0, r0);
2136 newLIR3(cUnit, ARMV5TE_ADD_RRR, r4PC, r0, r1);
2137 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
2138 break;
2139 }
2140 default:
2141 return true;
2142 }
2143 return false;
2144}
2145
2146static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2147 Armv5teLIR *labelList)
2148{
2149 Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
2150 Armv5teLIR *pcrLabel = NULL;
2151
2152 DecodedInstruction *dInsn = &mir->dalvikInsn;
2153 switch (mir->dalvikInsn.opCode) {
2154 /*
2155 * calleeMethod = this->clazz->vtable[
2156 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2157 * ]
2158 */
2159 case OP_INVOKE_VIRTUAL:
2160 case OP_INVOKE_VIRTUAL_RANGE: {
2161 int methodIndex =
2162 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2163 methodIndex;
2164
2165 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2166 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2167 else
2168 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2169
2170 /* r0 now contains this->clazz */
2171 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
2172 offsetof(Object, clazz) >> 2);
2173 /* r1 = &retChainingCell */
2174 Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
2175 r1, 0);
2176 /* r4PC = dalvikCallsite */
2177 loadConstant(cUnit, r4PC,
2178 (int) (cUnit->method->insns + mir->offset));
2179
2180 /* r0 now contains this->clazz->vtable */
2181 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
2182 offsetof(ClassObject, vtable) >> 2);
2183 addrRetChain->generic.target = (LIR *) retChainingCell;
2184
2185 if (methodIndex < 32) {
2186 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0, methodIndex);
2187 } else {
2188 loadConstant(cUnit, r7, methodIndex<<2);
2189 newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r0, r7);
2190 }
2191
2192 /*
2193 * r0 = calleeMethod,
2194 * r1 = &ChainingCell,
2195 * r4PC = callsiteDPC,
2196 */
2197 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2198#if defined(INVOKE_STATS)
2199 gDvmJit.invokeNoOpt++;
2200#endif
2201 /* Handle exceptions using the interpreter */
2202 genTrap(cUnit, mir->offset, pcrLabel);
2203 break;
2204 }
2205 /*
2206 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2207 * ->pResMethods[BBBB]->methodIndex]
2208 */
2209 /* TODO - not excersized in RunPerf.jar */
2210 case OP_INVOKE_SUPER:
2211 case OP_INVOKE_SUPER_RANGE: {
2212 int mIndex = cUnit->method->clazz->pDvmDex->
2213 pResMethods[dInsn->vB]->methodIndex;
2214 const Method *calleeMethod =
2215 cUnit->method->clazz->super->vtable[mIndex];
2216
2217 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2218 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2219 else
2220 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2221
2222 /* r0 = calleeMethod */
2223 loadConstant(cUnit, r0, (int) calleeMethod);
2224
2225 genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
2226 calleeMethod);
2227 break;
2228 }
2229 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2230 case OP_INVOKE_DIRECT:
2231 case OP_INVOKE_DIRECT_RANGE: {
2232 const Method *calleeMethod =
2233 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2234
2235 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2236 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2237 else
2238 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2239
2240 /* r0 = calleeMethod */
2241 loadConstant(cUnit, r0, (int) calleeMethod);
2242
2243 genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
2244 calleeMethod);
2245 break;
2246 }
2247 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2248 case OP_INVOKE_STATIC:
2249 case OP_INVOKE_STATIC_RANGE: {
2250 const Method *calleeMethod =
2251 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2252
2253 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2254 genProcessArgsNoRange(cUnit, mir, dInsn,
2255 NULL /* no null check */);
2256 else
2257 genProcessArgsRange(cUnit, mir, dInsn,
2258 NULL /* no null check */);
2259
2260 /* r0 = calleeMethod */
2261 loadConstant(cUnit, r0, (int) calleeMethod);
2262
2263 genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
2264 calleeMethod);
2265 break;
2266 }
2267 /*
2268 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2269 * BBBB, method, method->clazz->pDvmDex)
2270 */
2271 case OP_INVOKE_INTERFACE:
2272 case OP_INVOKE_INTERFACE_RANGE: {
2273 int methodIndex = dInsn->vB;
2274
2275 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2276 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2277 else
2278 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2279
2280 /* r0 now contains this->clazz */
2281 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
2282 offsetof(Object, clazz) >> 2);
2283
2284 /* r1 = BBBB */
2285 loadConstant(cUnit, r1, dInsn->vB);
2286
2287 /* r2 = method (caller) */
2288 loadConstant(cUnit, r2, (int) cUnit->method);
2289
2290 /* r3 = pDvmDex */
2291 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
2292
2293 loadConstant(cUnit, r7,
2294 (intptr_t) dvmFindInterfaceMethodInCache);
2295 newLIR1(cUnit, ARMV5TE_BLX_R, r7);
2296
2297 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
2298
2299 /* r1 = &retChainingCell */
2300 Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
2301 r1, 0);
2302 /* r4PC = dalvikCallsite */
2303 loadConstant(cUnit, r4PC,
2304 (int) (cUnit->method->insns + mir->offset));
2305
2306 addrRetChain->generic.target = (LIR *) retChainingCell;
2307 /*
2308 * r0 = this, r1 = calleeMethod,
2309 * r1 = &ChainingCell,
2310 * r4PC = callsiteDPC,
2311 */
2312 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2313#if defined(INVOKE_STATS)
2314 gDvmJit.invokeNoOpt++;
2315#endif
2316 /* Handle exceptions using the interpreter */
2317 genTrap(cUnit, mir->offset, pcrLabel);
2318 break;
2319 }
2320 /* NOP */
2321 case OP_INVOKE_DIRECT_EMPTY: {
2322 return false;
2323 }
2324 case OP_FILLED_NEW_ARRAY:
2325 case OP_FILLED_NEW_ARRAY_RANGE: {
2326 /* Just let the interpreter deal with these */
2327 genInterpSingleStep(cUnit, mir);
2328 break;
2329 }
2330 default:
2331 return true;
2332 }
2333 return false;
2334}
2335
2336static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
2337 BasicBlock *bb, Armv5teLIR *labelList)
2338{
2339 Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
2340 Armv5teLIR *pcrLabel = NULL;
2341
2342 DecodedInstruction *dInsn = &mir->dalvikInsn;
2343 switch (mir->dalvikInsn.opCode) {
2344 /* calleeMethod = this->clazz->vtable[BBBB] */
2345 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
2346 case OP_INVOKE_VIRTUAL_QUICK: {
2347 int methodIndex = dInsn->vB;
2348 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
2349 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2350 else
2351 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2352
2353 /* r0 now contains this->clazz */
2354 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
2355 offsetof(Object, clazz) >> 2);
2356 /* r1 = &retChainingCell */
2357 Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
2358 r1, 0);
2359 /* r4PC = dalvikCallsite */
2360 loadConstant(cUnit, r4PC,
2361 (int) (cUnit->method->insns + mir->offset));
2362
2363 /* r0 now contains this->clazz->vtable */
2364 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
2365 offsetof(ClassObject, vtable) >> 2);
2366 addrRetChain->generic.target = (LIR *) retChainingCell;
2367
2368 if (methodIndex < 32) {
2369 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0, methodIndex);
2370 } else {
2371 loadConstant(cUnit, r7, methodIndex<<2);
2372 newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r0, r7);
2373 }
2374
2375 /*
2376 * r0 = calleeMethod,
2377 * r1 = &ChainingCell,
2378 * r4PC = callsiteDPC,
2379 */
2380 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2381#if defined(INVOKE_STATS)
2382 gDvmJit.invokeNoOpt++;
2383#endif
2384 break;
2385 }
2386 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2387 case OP_INVOKE_SUPER_QUICK:
2388 case OP_INVOKE_SUPER_QUICK_RANGE: {
2389 const Method *calleeMethod =
2390 cUnit->method->clazz->super->vtable[dInsn->vB];
2391
2392 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
2393 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2394 else
2395 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2396
2397 /* r0 = calleeMethod */
2398 loadConstant(cUnit, r0, (int) calleeMethod);
2399
2400 genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
2401 calleeMethod);
2402 break;
2403 }
2404 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2405 default:
2406 return true;
2407 }
2408 /* Handle exceptions using the interpreter */
2409 genTrap(cUnit, mir->offset, pcrLabel);
2410 return false;
2411}
2412
2413/*
2414 * NOTE: We assume here that the special native inline routines
2415 * are side-effect free. By making this assumption, we can safely
2416 * re-execute the routine from the interpreter if it decides it
2417 * wants to throw an exception. We still need to EXPORT_PC(), though.
2418 */
2419static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
2420{
2421 DecodedInstruction *dInsn = &mir->dalvikInsn;
2422 switch( mir->dalvikInsn.opCode) {
2423 case OP_EXECUTE_INLINE: {
2424 unsigned int i;
2425 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
2426 int offset = (int) &((InterpState *) NULL)->retval;
2427 int operation = dInsn->vB;
2428
2429 if (!strcmp(inLineTable[operation].classDescriptor,
2430 "Ljava/lang/String;") &&
2431 !strcmp(inLineTable[operation].methodName,
2432 "length") &&
2433 !strcmp(inLineTable[operation].methodSignature,
2434 "()I")) {
2435 return genInlinedStringLength(cUnit,mir);
2436 }
2437
2438 /* Materialize pointer to retval & push */
2439 newLIR2(cUnit, ARMV5TE_MOV_RR, r4PC, rGLUE);
2440 newLIR2(cUnit, ARMV5TE_ADD_RI8, r4PC, offset);
2441 /* Push r4 and (just to take up space) r5) */
2442 newLIR1(cUnit, ARMV5TE_PUSH, (1<<r4PC | 1<<rFP));
2443
2444 /* Get code pointer to inline routine */
2445 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
2446
2447 /* Export PC */
2448 genExportPC(cUnit, mir, r0, r1 );
2449
2450 /* Load arguments to r0 through r3 as applicable */
2451 for (i=0; i < dInsn->vA; i++) {
2452 loadValue(cUnit, dInsn->arg[i], i);
2453 }
2454 /* Call inline routine */
2455 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
2456
2457 /* Strip frame */
2458 newLIR1(cUnit, ARMV5TE_ADD_SPI7, 2);
2459
2460 /* Did we throw? If so, redo under interpreter*/
2461 genNullCheck(cUnit, r0, mir->offset, NULL);
2462
2463 break;
2464 }
2465 default:
2466 return true;
2467 }
2468 return false;
2469}
2470
2471static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
2472{
2473 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
2474 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
2475 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2476 return false;
2477}
2478
2479/*****************************************************************************/
2480/*
2481 * The following are special processing routines that handle transfer of
2482 * controls between compiled code and the interpreter. Certain VM states like
2483 * Dalvik PC and special-purpose registers are reconstructed here.
2484 */
2485
Ben Cheng1efc9c52009-06-08 18:25:27 -07002486/* Chaining cell for code that may need warmup. */
2487static void handleNormalChainingCell(CompilationUnit *cUnit,
2488 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002489{
2490 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
2491 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
2492 newLIR1(cUnit, ARMV5TE_BLX_R, r0);
2493 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
2494}
2495
2496/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07002497 * Chaining cell for instructions that immediately following already translated
2498 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07002499 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07002500static void handleHotChainingCell(CompilationUnit *cUnit,
2501 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002502{
2503 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
2504 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
2505 newLIR1(cUnit, ARMV5TE_BLX_R, r0);
2506 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
2507}
2508
2509/* Chaining cell for monomorphic method invocations. */
2510static void handleInvokeChainingCell(CompilationUnit *cUnit,
2511 const Method *callee)
2512{
2513 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
2514 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
2515 newLIR1(cUnit, ARMV5TE_BLX_R, r0);
2516 addWordData(cUnit, (int) (callee->insns), true);
2517}
2518
2519/* Load the Dalvik PC into r0 and jump to the specified target */
2520static void handlePCReconstruction(CompilationUnit *cUnit,
2521 Armv5teLIR *targetLabel)
2522{
2523 Armv5teLIR **pcrLabel =
2524 (Armv5teLIR **) cUnit->pcReconstructionList.elemList;
2525 int numElems = cUnit->pcReconstructionList.numUsed;
2526 int i;
2527 for (i = 0; i < numElems; i++) {
2528 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
2529 /* r0 = dalvik PC */
2530 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
2531 genUnconditionalBranch(cUnit, targetLabel);
2532 }
2533}
2534
2535/* Entry function to invoke the backend of the JIT compiler */
2536void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
2537{
2538 /* Used to hold the labels of each block */
2539 Armv5teLIR *labelList =
2540 dvmCompilerNew(sizeof(Armv5teLIR) * cUnit->numBlocks, true);
2541 GrowableList chainingListByType[CHAINING_CELL_LAST];
2542 int i;
2543
2544 /*
2545 * Initialize the three chaining lists for generic, post-invoke, and invoke
2546 * chains.
2547 */
2548 for (i = 0; i < CHAINING_CELL_LAST; i++) {
2549 dvmInitGrowableList(&chainingListByType[i], 2);
2550 }
2551
2552 BasicBlock **blockList = cUnit->blockList;
2553
Ben Cheng1efc9c52009-06-08 18:25:27 -07002554 /*
2555 * Reserve space at the beginning of each translation with fillers
2556 * + Chain cell count (2 bytes)
2557 */
2558 newLIR1(cUnit, ARMV5TE_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
2559
Ben Chengba4fc8b2009-06-01 13:00:29 -07002560 /* Handle the content in each basic block */
2561 for (i = 0; i < cUnit->numBlocks; i++) {
2562 blockList[i]->visited = true;
2563 MIR *mir;
2564
2565 labelList[i].operands[0] = blockList[i]->startOffset;
2566
2567 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
2568 /*
2569 * Append the label pseudo LIR first. Chaining cells will be handled
2570 * separately afterwards.
2571 */
2572 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
2573 }
2574
2575 if (blockList[i]->blockType == DALVIK_BYTECODE) {
2576 labelList[i].opCode = ARMV5TE_PSEUDO_NORMAL_BLOCK_LABEL;
2577 } else {
2578 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07002579 case CHAINING_CELL_NORMAL:
2580 labelList[i].opCode = ARMV5TE_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002581 /* handle the codegen later */
2582 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07002583 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002584 break;
2585 case CHAINING_CELL_INVOKE:
2586 labelList[i].opCode = ARMV5TE_PSEUDO_CHAINING_CELL_INVOKE;
2587 labelList[i].operands[0] =
2588 (int) blockList[i]->containingMethod;
2589 /* handle the codegen later */
2590 dvmInsertGrowableList(
2591 &chainingListByType[CHAINING_CELL_INVOKE], (void *) i);
2592 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07002593 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002594 labelList[i].opCode =
Ben Cheng1efc9c52009-06-08 18:25:27 -07002595 ARMV5TE_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002596 /* handle the codegen later */
2597 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07002598 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07002599 (void *) i);
2600 break;
2601 case PC_RECONSTRUCTION:
2602 /* Make sure exception handling block is next */
2603 labelList[i].opCode =
2604 ARMV5TE_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
2605 assert (i == cUnit->numBlocks - 2);
2606 handlePCReconstruction(cUnit, &labelList[i+1]);
2607 break;
2608 case EXCEPTION_HANDLING:
2609 labelList[i].opCode = ARMV5TE_PSEUDO_EH_BLOCK_LABEL;
2610 if (cUnit->pcReconstructionList.numUsed) {
2611 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE,
2612 offsetof(InterpState,
2613 jitToInterpEntries.dvmJitToInterpPunt)
2614 >> 2);
2615 newLIR1(cUnit, ARMV5TE_BLX_R, r1);
2616 }
2617 break;
2618 default:
2619 break;
2620 }
2621 continue;
2622 }
2623 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
2624 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2625 InstructionFormat dalvikFormat =
2626 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
2627 newLIR2(cUnit, ARMV5TE_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
2628 mir->offset,dalvikOpCode);
2629 bool notHandled;
2630 /*
2631 * Debugging: screen the opcode first to see if it is in the
2632 * do[-not]-compile list
2633 */
2634 bool singleStepMe =
2635 gDvmJit.includeSelectedOp !=
2636 ((gDvmJit.opList[dalvikOpCode >> 3] &
2637 (1 << (dalvikOpCode & 0x7))) !=
2638 0);
2639 if (singleStepMe || cUnit->allSingleStep) {
2640 notHandled = false;
2641 genInterpSingleStep(cUnit, mir);
2642 } else {
2643 opcodeCoverage[dalvikOpCode]++;
2644 switch (dalvikFormat) {
2645 case kFmt10t:
2646 case kFmt20t:
2647 case kFmt30t:
2648 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
2649 mir, blockList[i], labelList);
2650 break;
2651 case kFmt10x:
2652 notHandled = handleFmt10x(cUnit, mir);
2653 break;
2654 case kFmt11n:
2655 case kFmt31i:
2656 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
2657 break;
2658 case kFmt11x:
2659 notHandled = handleFmt11x(cUnit, mir);
2660 break;
2661 case kFmt12x:
2662 notHandled = handleFmt12x(cUnit, mir);
2663 break;
2664 case kFmt20bc:
2665 notHandled = handleFmt20bc(cUnit, mir);
2666 break;
2667 case kFmt21c:
2668 case kFmt31c:
2669 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
2670 break;
2671 case kFmt21h:
2672 notHandled = handleFmt21h(cUnit, mir);
2673 break;
2674 case kFmt21s:
2675 notHandled = handleFmt21s(cUnit, mir);
2676 break;
2677 case kFmt21t:
2678 notHandled = handleFmt21t(cUnit, mir, blockList[i],
2679 labelList);
2680 break;
2681 case kFmt22b:
2682 case kFmt22s:
2683 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
2684 break;
2685 case kFmt22c:
2686 notHandled = handleFmt22c(cUnit, mir);
2687 break;
2688 case kFmt22cs:
2689 notHandled = handleFmt22cs(cUnit, mir);
2690 break;
2691 case kFmt22t:
2692 notHandled = handleFmt22t(cUnit, mir, blockList[i],
2693 labelList);
2694 break;
2695 case kFmt22x:
2696 case kFmt32x:
2697 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
2698 break;
2699 case kFmt23x:
2700 notHandled = handleFmt23x(cUnit, mir);
2701 break;
2702 case kFmt31t:
2703 notHandled = handleFmt31t(cUnit, mir);
2704 break;
2705 case kFmt3rc:
2706 case kFmt35c:
2707 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
2708 labelList);
2709 break;
2710 case kFmt3rms:
2711 case kFmt35ms:
2712 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
2713 labelList);
2714 break;
2715 case kFmt3inline:
2716 notHandled = handleFmt3inline(cUnit, mir);
2717 break;
2718 case kFmt51l:
2719 notHandled = handleFmt51l(cUnit, mir);
2720 break;
2721 default:
2722 notHandled = true;
2723 break;
2724 }
2725 }
2726 if (notHandled) {
2727 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
2728 mir->offset,
2729 dalvikOpCode, getOpcodeName(dalvikOpCode),
2730 dalvikFormat);
2731 dvmAbort();
2732 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002733 }
2734 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07002735 /*
2736 * Check if the block is terminated due to trace length constraint -
2737 * insert an unconditional branch to the chaining cell.
2738 */
2739 if (blockList[i]->needFallThroughBranch) {
2740 genUnconditionalBranch(cUnit,
2741 &labelList[blockList[i]->fallThrough->id]);
2742 }
2743
Ben Chengba4fc8b2009-06-01 13:00:29 -07002744 }
2745
2746 /* Handle the codegen in predefined order */
2747 for (i = 0; i < CHAINING_CELL_LAST; i++) {
2748 size_t j;
2749 int *blockIdList = (int *) chainingListByType[i].elemList;
2750
2751 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
2752
2753 /* No chaining cells of this type */
2754 if (cUnit->numChainingCells[i] == 0)
2755 continue;
2756
2757 /* Record the first LIR for a new type of chaining cell */
2758 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
2759
2760 for (j = 0; j < chainingListByType[i].numUsed; j++) {
2761 int blockId = blockIdList[j];
2762
2763 /* Align this chaining cell first */
2764 newLIR0(cUnit, ARMV5TE_PSEUDO_ALIGN4);
2765
2766 /* Insert the pseudo chaining instruction */
2767 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
2768
2769
2770 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07002771 case CHAINING_CELL_NORMAL:
2772 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002773 blockList[blockId]->startOffset);
2774 break;
2775 case CHAINING_CELL_INVOKE:
2776 handleInvokeChainingCell(cUnit,
2777 blockList[blockId]->containingMethod);
2778 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07002779 case CHAINING_CELL_HOT:
2780 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002781 blockList[blockId]->startOffset);
2782 break;
2783 default:
2784 dvmAbort();
2785 break;
2786 }
2787 }
2788 }
2789}
2790
2791/* Accept the work and start compiling */
2792void *dvmCompilerDoWork(CompilerWorkOrder *work)
2793{
2794 void *res;
2795
2796 if (gDvmJit.codeCacheFull) {
2797 return NULL;
2798 }
2799
2800 switch (work->kind) {
2801 case kWorkOrderMethod:
2802 res = dvmCompileMethod(work->info);
2803 break;
2804 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07002805 /* Start compilation with maximally allowed trace length */
2806 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002807 break;
2808 default:
2809 res = NULL;
2810 dvmAbort();
2811 }
2812 return res;
2813}
2814
2815/* Architecture-specific initializations and checks go here */
2816bool dvmCompilerArchInit(void)
2817{
2818 /* First, declare dvmCompiler_TEMPLATE_XXX for each template */
2819#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
2820#include "../../template/armv5te/TemplateOpList.h"
2821#undef JIT_TEMPLATE
2822
2823 int i = 0;
2824 extern void dvmCompilerTemplateStart(void);
2825
2826 /*
2827 * Then, populate the templateEntryOffsets array with the offsets from the
2828 * the dvmCompilerTemplateStart symbol for each template.
2829 */
2830#define JIT_TEMPLATE(X) templateEntryOffsets[i++] = \
2831 (intptr_t) dvmCompiler_TEMPLATE_##X - (intptr_t) dvmCompilerTemplateStart;
2832#include "../../template/armv5te/TemplateOpList.h"
2833#undef JIT_TEMPLATE
2834
2835 /* Codegen-specific assumptions */
2836 assert(offsetof(ClassObject, vtable) < 128 &&
2837 (offsetof(ClassObject, vtable) & 0x3) == 0);
2838 assert(offsetof(ArrayObject, length) < 128 &&
2839 (offsetof(ArrayObject, length) & 0x3) == 0);
2840 assert(offsetof(ArrayObject, contents) < 256);
2841
2842 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
2843 assert(sizeof(StackSaveArea) < 236);
2844
2845 /*
2846 * EA is calculated by doing "Rn + imm5 << 2", and there are 5 entry points
2847 * that codegen may access, make sure that the offset from the top of the
2848 * struct is less than 108.
2849 */
2850 assert(offsetof(InterpState, jitToInterpEntries) < 108);
2851 return true;
2852}
2853
2854/* Architectural-specific debugging helpers go here */
2855void dvmCompilerArchDump(void)
2856{
2857 /* Print compiled opcode in this VM instance */
2858 int i, start, streak;
2859 char buf[1024];
2860
2861 streak = i = 0;
2862 buf[0] = 0;
2863 while (opcodeCoverage[i] == 0 && i < 256) {
2864 i++;
2865 }
2866 if (i == 256) {
2867 return;
2868 }
2869 for (start = i++, streak = 1; i < 256; i++) {
2870 if (opcodeCoverage[i]) {
2871 streak++;
2872 } else {
2873 if (streak == 1) {
2874 sprintf(buf+strlen(buf), "%x,", start);
2875 } else {
2876 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
2877 }
2878 streak = 0;
2879 while (opcodeCoverage[i] == 0 && i < 256) {
2880 i++;
2881 }
2882 if (i < 256) {
2883 streak = 1;
2884 start = i;
2885 }
2886 }
2887 }
2888 if (streak) {
2889 if (streak == 1) {
2890 sprintf(buf+strlen(buf), "%x", start);
2891 } else {
2892 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
2893 }
2894 }
2895 if (strlen(buf)) {
2896 LOGD("dalvik.vm.jitop = %s", buf);
2897 }
2898}
Bill Buzbeed45ba372009-06-15 17:00:57 -07002899
2900/*
2901 * Exported version of loadValueAddress
2902 * TODO: revisit source file structure
2903 */
2904void dvmCompilerLoadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
2905{
2906 loadValueAddress(cUnit, vSrc, rDest);
2907}
2908
2909/*
2910 * Exported version of genDispatchToHandler
2911 * TODO: revisit source file structure
2912 */
2913void dvmCompilerGenDispatchToHandler(CompilationUnit *cUnit,
2914 TemplateOpCode opCode)
2915{
2916 genDispatchToHandler(cUnit, opCode);
2917}
2918
2919/*
2920 * Exported version of loadValue
2921 * TODO: revisit source file structure
2922 */
2923void dvmCompilerLoadValue(CompilationUnit *cUnit, int vSrc, int rDest)
2924{
2925 loadValue(cUnit, vSrc, rDest);
2926}
2927
2928/*
2929 * Exported version of storeValue
2930 * TODO: revisit source file structure
2931 */
2932void dvmCompilerStoreValue(CompilationUnit *cUnit, int rSrc, int vDest,
2933 int rScratch)
2934{
2935 storeValue(cUnit, rSrc, vDest, rScratch);
2936}