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