1 /*
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 /*
18 * This file contains codegen and support common to all supported
19 * ARM variants. It is included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
25 */
26
27
28 /* Array holding the entry offset of each template relative to the first one */
29 static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
30
31 /* Track exercised opcodes */
32 static int opcodeCoverage[256];
33
34 /*****************************************************************************/
35
36 /*
37 * The following are building blocks to construct low-level IRs with 0 - 3
38 * operands.
39 */
newLIR0(CompilationUnit * cUnit,ArmOpCode opCode)40 static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
41 {
42 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
43 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
44 insn->opCode = opCode;
45 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
46 return insn;
47 }
48
newLIR1(CompilationUnit * cUnit,ArmOpCode opCode,int dest)49 static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
50 int dest)
51 {
52 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
53 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
54 insn->opCode = opCode;
55 insn->operands[0] = dest;
56 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
57 return insn;
58 }
59
newLIR2(CompilationUnit * cUnit,ArmOpCode opCode,int dest,int src1)60 static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
61 int dest, int src1)
62 {
63 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
64 assert(isPseudoOpCode(opCode) ||
65 (EncodingMap[opCode].flags & IS_BINARY_OP));
66 insn->opCode = opCode;
67 insn->operands[0] = dest;
68 insn->operands[1] = src1;
69 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
70 return insn;
71 }
72
newLIR3(CompilationUnit * cUnit,ArmOpCode opCode,int dest,int src1,int src2)73 static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
74 int dest, int src1, int src2)
75 {
76 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
77 assert(isPseudoOpCode(opCode) ||
78 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
79 insn->opCode = opCode;
80 insn->operands[0] = dest;
81 insn->operands[1] = src1;
82 insn->operands[2] = src2;
83 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
84 return insn;
85 }
86
newLIR23(CompilationUnit * cUnit,ArmOpCode opCode,int srcdest,int src2)87 static ArmLIR *newLIR23(CompilationUnit *cUnit, ArmOpCode opCode,
88 int srcdest, int src2)
89 {
90 assert(!isPseudoOpCode(opCode));
91 if (EncodingMap[opCode].flags & IS_BINARY_OP)
92 return newLIR2(cUnit, opCode, srcdest, src2);
93 else
94 return newLIR3(cUnit, opCode, srcdest, srcdest, src2);
95 }
96
97 /*****************************************************************************/
98
99 /*
100 * The following are building blocks to insert constants into the pool or
101 * instruction streams.
102 */
103
104 /* Add a 32-bit constant either in the constant pool or mixed with code */
addWordData(CompilationUnit * cUnit,int value,bool inPlace)105 static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
106 {
107 /* Add the constant to the literal pool */
108 if (!inPlace) {
109 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
110 newValue->operands[0] = value;
111 newValue->generic.next = cUnit->wordList;
112 cUnit->wordList = (LIR *) newValue;
113 return newValue;
114 } else {
115 /* Add the constant in the middle of code stream */
116 newLIR1(cUnit, ARM_16BIT_DATA, (value & 0xffff));
117 newLIR1(cUnit, ARM_16BIT_DATA, (value >> 16));
118 }
119 return NULL;
120 }
121
122 /*
123 * Search the existing constants in the literal pool for an exact or close match
124 * within specified delta (greater or equal to 0).
125 */
scanLiteralPool(CompilationUnit * cUnit,int value,unsigned int delta)126 static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
127 unsigned int delta)
128 {
129 LIR *dataTarget = cUnit->wordList;
130 while (dataTarget) {
131 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
132 delta)
133 return (ArmLIR *) dataTarget;
134 dataTarget = dataTarget->next;
135 }
136 return NULL;
137 }
138
139 /* Perform the actual operation for OP_RETURN_* */
genReturnCommon(CompilationUnit * cUnit,MIR * mir)140 static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
141 {
142 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
143 #if defined(INVOKE_STATS)
144 gDvmJit.returnOp++;
145 #endif
146 int dPC = (int) (cUnit->method->insns + mir->offset);
147 /* Insert branch, but defer setting of target */
148 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
149 /* Set up the place holder to reconstruct this Dalvik PC */
150 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
151 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
152 pcrLabel->operands[0] = dPC;
153 pcrLabel->operands[1] = mir->offset;
154 /* Insert the place holder to the growable list */
155 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
156 /* Branch to the PC reconstruction code */
157 branch->generic.target = (LIR *) pcrLabel;
158 }
159
160 /*
161 * Perform a binary operation on 64-bit operands and leave the results in the
162 * r0/r1 pair.
163 */
genBinaryOpWide(CompilationUnit * cUnit,int vDest,ArmOpCode preinst,ArmOpCode inst,int reg0,int reg2)164 static void genBinaryOpWide(CompilationUnit *cUnit, int vDest,
165 ArmOpCode preinst, ArmOpCode inst,
166 int reg0, int reg2)
167 {
168 int reg1 = NEXT_REG(reg0);
169 int reg3 = NEXT_REG(reg2);
170 newLIR23(cUnit, preinst, reg0, reg2);
171 newLIR23(cUnit, inst, reg1, reg3);
172 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
173 }
174
175 /* Perform a binary operation on 32-bit operands and leave the results in r0. */
genBinaryOp(CompilationUnit * cUnit,int vDest,ArmOpCode inst,int reg0,int reg1,int regDest)176 static void genBinaryOp(CompilationUnit *cUnit, int vDest, ArmOpCode inst,
177 int reg0, int reg1, int regDest)
178 {
179 if (EncodingMap[inst].flags & IS_BINARY_OP) {
180 newLIR2(cUnit, inst, reg0, reg1);
181 storeValue(cUnit, reg0, vDest, reg1);
182 } else {
183 newLIR3(cUnit, inst, regDest, reg0, reg1);
184 storeValue(cUnit, regDest, vDest, reg1);
185 }
186 }
187
188 /* Create the PC reconstruction slot if not already done */
genCheckCommon(CompilationUnit * cUnit,int dOffset,ArmLIR * branch,ArmLIR * pcrLabel)189 static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
190 ArmLIR *branch,
191 ArmLIR *pcrLabel)
192 {
193 /* Set up the place holder to reconstruct this Dalvik PC */
194 if (pcrLabel == NULL) {
195 int dPC = (int) (cUnit->method->insns + dOffset);
196 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
197 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
198 pcrLabel->operands[0] = dPC;
199 pcrLabel->operands[1] = dOffset;
200 /* Insert the place holder to the growable list */
201 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
202 }
203 /* Branch to the PC reconstruction code */
204 branch->generic.target = (LIR *) pcrLabel;
205 return pcrLabel;
206 }
207
208
209 /*
210 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
211 * satisfies.
212 */
inertRegRegCheck(CompilationUnit * cUnit,ArmConditionCode cond,int reg1,int reg2,int dOffset,ArmLIR * pcrLabel)213 static inline ArmLIR *inertRegRegCheck(CompilationUnit *cUnit,
214 ArmConditionCode cond,
215 int reg1, int reg2, int dOffset,
216 ArmLIR *pcrLabel)
217 {
218 newLIR2(cUnit, THUMB_CMP_RR, reg1, reg2);
219 ArmLIR *branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
220 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
221 }
222
223 /*
224 * Perform null-check on a register. vReg is the Dalvik register being checked,
225 * and mReg is the machine register holding the actual value. If internal state
226 * indicates that vReg has been checked before the check request is ignored.
227 */
genNullCheck(CompilationUnit * cUnit,int vReg,int mReg,int dOffset,ArmLIR * pcrLabel)228 static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
229 int dOffset, ArmLIR *pcrLabel)
230 {
231 /* This particular Dalvik register has been null-checked */
232 if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
233 return pcrLabel;
234 }
235 dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
236 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
237 }
238
239 /*
240 * Perform zero-check on a register. Similar to genNullCheck but the value being
241 * checked does not have a corresponding Dalvik register.
242 */
genZeroCheck(CompilationUnit * cUnit,int mReg,int dOffset,ArmLIR * pcrLabel)243 static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
244 int dOffset, ArmLIR *pcrLabel)
245 {
246 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
247 }
248
249 /* Perform bound check on two registers */
genBoundsCheck(CompilationUnit * cUnit,int rIndex,int rBound,int dOffset,ArmLIR * pcrLabel)250 static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
251 int rBound, int dOffset, ArmLIR *pcrLabel)
252 {
253 return inertRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
254 pcrLabel);
255 }
256
257 /* Generate a unconditional branch to go to the interpreter */
genTrap(CompilationUnit * cUnit,int dOffset,ArmLIR * pcrLabel)258 static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
259 ArmLIR *pcrLabel)
260 {
261 ArmLIR *branch = newLIR0(cUnit, THUMB_B_UNCOND);
262 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
263 }
264
265 /* Load a wide field from an object instance */
genIGetWide(CompilationUnit * cUnit,MIR * mir,int fieldOffset)266 static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
267 {
268 DecodedInstruction *dInsn = &mir->dalvikInsn;
269 int reg0, reg1, reg2, reg3;
270
271 /* Allocate reg0..reg3 into physical registers r0..r3 */
272
273 /* See if vB is in a native register. If so, reuse it. */
274 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
275 /* Ping reg3 to the other register of the same pair containing reg2 */
276 reg3 = reg2 ^ 0x1;
277 /*
278 * Ping reg0 to the first register of the alternate register pair
279 */
280 reg0 = (reg2 + 2) & 0x2;
281 reg1 = NEXT_REG(reg0);
282
283 loadValue(cUnit, dInsn->vB, reg2);
284 loadConstant(cUnit, reg3, fieldOffset);
285 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
286 newLIR3(cUnit, THUMB_ADD_RRR, reg2, reg2, reg3);
287 newLIR2(cUnit, THUMB_LDMIA, reg2, (1<<reg0 | 1<<reg1));
288 storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
289 }
290
291 /* Store a wide field to an object instance */
genIPutWide(CompilationUnit * cUnit,MIR * mir,int fieldOffset)292 static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
293 {
294 DecodedInstruction *dInsn = &mir->dalvikInsn;
295 int reg0, reg1, reg2, reg3;
296
297 /* Allocate reg0..reg3 into physical registers r0..r3 */
298
299 /* See if vB is in a native register. If so, reuse it. */
300 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
301 /* Ping reg3 to the other register of the same pair containing reg2 */
302 reg3 = reg2 ^ 0x1;
303 /*
304 * Ping reg0 to the first register of the alternate register pair
305 */
306 reg0 = (reg2 + 2) & 0x2;
307 reg1 = NEXT_REG(reg0);
308
309
310 loadValue(cUnit, dInsn->vB, reg2);
311 loadValuePair(cUnit, dInsn->vA, reg0, reg1);
312 updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
313 loadConstant(cUnit, reg3, fieldOffset);
314 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
315 newLIR3(cUnit, THUMB_ADD_RRR, reg2, reg2, reg3);
316 newLIR2(cUnit, THUMB_STMIA, reg2, (1<<reg0 | 1<<reg1));
317 }
318
319 /*
320 * Load a field from an object instance
321 *
322 * Inst should be one of:
323 * THUMB_LDR_RRR
324 * THUMB_LDRB_RRR
325 * THUMB_LDRH_RRR
326 * THUMB_LDRSB_RRR
327 * THUMB_LDRSH_RRR
328 */
genIGet(CompilationUnit * cUnit,MIR * mir,ArmOpCode inst,int fieldOffset)329 static void genIGet(CompilationUnit *cUnit, MIR *mir, ArmOpCode inst,
330 int fieldOffset)
331 {
332 DecodedInstruction *dInsn = &mir->dalvikInsn;
333 int reg0, reg1;
334
335 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
336 reg1 = NEXT_REG(reg0);
337 /* TUNING: write a utility routine to load via base + constant offset */
338 loadValue(cUnit, dInsn->vB, reg0);
339 loadConstant(cUnit, reg1, fieldOffset);
340 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
341 newLIR3(cUnit, inst, reg0, reg0, reg1);
342 storeValue(cUnit, reg0, dInsn->vA, reg1);
343 }
344
345 /*
346 * Store a field to an object instance
347 *
348 * Inst should be one of:
349 * THUMB_STR_RRR
350 * THUMB_STRB_RRR
351 * THUMB_STRH_RRR
352 */
genIPut(CompilationUnit * cUnit,MIR * mir,ArmOpCode inst,int fieldOffset)353 static void genIPut(CompilationUnit *cUnit, MIR *mir, ArmOpCode inst,
354 int fieldOffset)
355 {
356 DecodedInstruction *dInsn = &mir->dalvikInsn;
357 int reg0, reg1, reg2;
358
359 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
360 reg1 = NEXT_REG(reg0);
361 reg2 = NEXT_REG(reg1);
362
363 /* TUNING: write a utility routine to load via base + constant offset */
364 loadValue(cUnit, dInsn->vB, reg0);
365 loadConstant(cUnit, reg1, fieldOffset);
366 loadValue(cUnit, dInsn->vA, reg2);
367 updateLiveRegister(cUnit, dInsn->vA, reg2);
368 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
369 newLIR3(cUnit, inst, reg2, reg0, reg1);
370 }
371
372
373 /* TODO: This should probably be done as an out-of-line instruction handler. */
374
375 /*
376 * Generate array load
377 *
378 * Inst should be one of:
379 * THUMB_LDR_RRR
380 * THUMB_LDRB_RRR
381 * THUMB_LDRH_RRR
382 * THUMB_LDRSB_RRR
383 * THUMB_LDRSH_RRR
384 */
genArrayGet(CompilationUnit * cUnit,MIR * mir,ArmOpCode inst,int vArray,int vIndex,int vDest,int scale)385 static void genArrayGet(CompilationUnit *cUnit, MIR *mir, ArmOpCode inst,
386 int vArray, int vIndex, int vDest, int scale)
387 {
388 int lenOffset = offsetof(ArrayObject, length);
389 int dataOffset = offsetof(ArrayObject, contents);
390 int reg0, reg1, reg2, reg3;
391
392 reg0 = selectFirstRegister(cUnit, vArray, false);
393 reg1 = NEXT_REG(reg0);
394 reg2 = NEXT_REG(reg1);
395 reg3 = NEXT_REG(reg2);
396
397 loadValue(cUnit, vArray, reg2);
398 loadValue(cUnit, vIndex, reg3);
399
400 /* null object? */
401 ArmLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
402 NULL);
403 newLIR3(cUnit, THUMB_LDR_RRI5, reg0, reg2, lenOffset >> 2); /* Get len */
404 newLIR2(cUnit, THUMB_ADD_RI8, reg2, dataOffset); /* reg2 -> array data */
405 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
406 if (scale) {
407 newLIR3(cUnit, THUMB_LSL, reg3, reg3, scale);
408 }
409 if (scale==3) {
410 newLIR3(cUnit, inst, reg0, reg2, reg3);
411 newLIR2(cUnit, THUMB_ADD_RI8, reg2, 4);
412 newLIR3(cUnit, inst, reg1, reg2, reg3);
413 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
414 } else {
415 newLIR3(cUnit, inst, reg0, reg2, reg3);
416 storeValue(cUnit, reg0, vDest, reg3);
417 }
418 }
419
420 /* TODO: This should probably be done as an out-of-line instruction handler. */
421
422 /*
423 * Generate array store
424 *
425 * Inst should be one of:
426 * THUMB_STR_RRR
427 * THUMB_STRB_RRR
428 * THUMB_STRH_RRR
429 */
genArrayPut(CompilationUnit * cUnit,MIR * mir,ArmOpCode inst,int vArray,int vIndex,int vSrc,int scale)430 static void genArrayPut(CompilationUnit *cUnit, MIR *mir, ArmOpCode inst,
431 int vArray, int vIndex, int vSrc, int scale)
432 {
433 int lenOffset = offsetof(ArrayObject, length);
434 int dataOffset = offsetof(ArrayObject, contents);
435 int reg0, reg1, reg2, reg3;
436
437 reg0 = selectFirstRegister(cUnit, vArray, false);
438 reg1 = NEXT_REG(reg0);
439 reg2 = NEXT_REG(reg1);
440 reg3 = NEXT_REG(reg2);
441
442 loadValue(cUnit, vArray, reg2);
443 loadValue(cUnit, vIndex, reg3);
444
445 /* null object? */
446 ArmLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
447 NULL);
448 newLIR3(cUnit, THUMB_LDR_RRI5, reg0, reg2, lenOffset >> 2); /* Get len */
449 newLIR2(cUnit, THUMB_ADD_RI8, reg2, dataOffset); /* reg2 -> array data */
450 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
451 /* at this point, reg2 points to array, reg3 is unscaled index */
452 if (scale==3) {
453 loadValuePair(cUnit, vSrc, reg0, reg1);
454 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
455 } else {
456 loadValue(cUnit, vSrc, reg0);
457 updateLiveRegister(cUnit, vSrc, reg0);
458 }
459 if (scale) {
460 newLIR3(cUnit, THUMB_LSL, reg3, reg3, scale);
461 }
462 /*
463 * at this point, reg2 points to array, reg3 is scaled index, and
464 * reg0[reg1] is data
465 */
466 if (scale==3) {
467 newLIR3(cUnit, inst, reg0, reg2, reg3);
468 newLIR2(cUnit, THUMB_ADD_RI8, reg2, 4);
469 newLIR3(cUnit, inst, reg1, reg2, reg3);
470 } else {
471 newLIR3(cUnit, inst, reg0, reg2, reg3);
472 }
473 }
474
genShiftOpLong(CompilationUnit * cUnit,MIR * mir,int vDest,int vSrc1,int vShift)475 static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
476 int vSrc1, int vShift)
477 {
478 /*
479 * Don't mess with the regsiters here as there is a particular calling
480 * convention to the out-of-line handler.
481 */
482 loadValue(cUnit, vShift, r2);
483 loadValuePair(cUnit, vSrc1, r0, r1);
484 switch( mir->dalvikInsn.opCode) {
485 case OP_SHL_LONG:
486 case OP_SHL_LONG_2ADDR:
487 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
488 break;
489 case OP_SHR_LONG:
490 case OP_SHR_LONG_2ADDR:
491 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
492 break;
493 case OP_USHR_LONG:
494 case OP_USHR_LONG_2ADDR:
495 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
496 break;
497 default:
498 return true;
499 }
500 storeValuePair(cUnit, r0, r1, vDest, r2);
501 return false;
502 }
genArithOpFloatPortable(CompilationUnit * cUnit,MIR * mir,int vDest,int vSrc1,int vSrc2)503 bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
504 int vDest, int vSrc1, int vSrc2)
505 {
506 /*
507 * Don't optimize the regsiter usage here as they are governed by the EABI
508 * calling convention.
509 */
510 void* funct;
511 int reg0, reg1;
512
513 /* TODO: use a proper include file to define these */
514 float __aeabi_fadd(float a, float b);
515 float __aeabi_fsub(float a, float b);
516 float __aeabi_fdiv(float a, float b);
517 float __aeabi_fmul(float a, float b);
518 float fmodf(float a, float b);
519
520 reg0 = selectFirstRegister(cUnit, vSrc2, false);
521 reg1 = NEXT_REG(reg0);
522
523 switch (mir->dalvikInsn.opCode) {
524 case OP_ADD_FLOAT_2ADDR:
525 case OP_ADD_FLOAT:
526 funct = (void*) __aeabi_fadd;
527 break;
528 case OP_SUB_FLOAT_2ADDR:
529 case OP_SUB_FLOAT:
530 funct = (void*) __aeabi_fsub;
531 break;
532 case OP_DIV_FLOAT_2ADDR:
533 case OP_DIV_FLOAT:
534 funct = (void*) __aeabi_fdiv;
535 break;
536 case OP_MUL_FLOAT_2ADDR:
537 case OP_MUL_FLOAT:
538 funct = (void*) __aeabi_fmul;
539 break;
540 case OP_REM_FLOAT_2ADDR:
541 case OP_REM_FLOAT:
542 funct = (void*) fmodf;
543 break;
544 case OP_NEG_FLOAT: {
545 loadValue(cUnit, vSrc2, reg0);
546 loadConstant(cUnit, reg1, 0x80000000);
547 newLIR3(cUnit, THUMB_ADD_RRR, reg0, reg0, reg1);
548 storeValue(cUnit, reg0, vDest, reg1);
549 return false;
550 }
551 default:
552 return true;
553 }
554 loadConstant(cUnit, r2, (int)funct);
555 loadValue(cUnit, vSrc1, r0);
556 loadValue(cUnit, vSrc2, r1);
557 newLIR1(cUnit, THUMB_BLX_R, r2);
558 storeValue(cUnit, r0, vDest, r1);
559 return false;
560 }
561
genArithOpDoublePortable(CompilationUnit * cUnit,MIR * mir,int vDest,int vSrc1,int vSrc2)562 bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
563 int vDest, int vSrc1, int vSrc2)
564 {
565 void* funct;
566 int reg0, reg1, reg2;
567
568 /* TODO: use a proper include file to define these */
569 double __aeabi_dadd(double a, double b);
570 double __aeabi_dsub(double a, double b);
571 double __aeabi_ddiv(double a, double b);
572 double __aeabi_dmul(double a, double b);
573 double fmod(double a, double b);
574
575 reg0 = selectFirstRegister(cUnit, vSrc2, true);
576 reg1 = NEXT_REG(reg0);
577 reg2 = NEXT_REG(reg1);
578
579 switch (mir->dalvikInsn.opCode) {
580 case OP_ADD_DOUBLE_2ADDR:
581 case OP_ADD_DOUBLE:
582 funct = (void*) __aeabi_dadd;
583 break;
584 case OP_SUB_DOUBLE_2ADDR:
585 case OP_SUB_DOUBLE:
586 funct = (void*) __aeabi_dsub;
587 break;
588 case OP_DIV_DOUBLE_2ADDR:
589 case OP_DIV_DOUBLE:
590 funct = (void*) __aeabi_ddiv;
591 break;
592 case OP_MUL_DOUBLE_2ADDR:
593 case OP_MUL_DOUBLE:
594 funct = (void*) __aeabi_dmul;
595 break;
596 case OP_REM_DOUBLE_2ADDR:
597 case OP_REM_DOUBLE:
598 funct = (void*) fmod;
599 break;
600 case OP_NEG_DOUBLE: {
601 loadValuePair(cUnit, vSrc2, reg0, reg1);
602 loadConstant(cUnit, reg2, 0x80000000);
603 newLIR3(cUnit, THUMB_ADD_RRR, reg1, reg1, reg2);
604 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
605 return false;
606 }
607 default:
608 return true;
609 }
610 /*
611 * Don't optimize the regsiter usage here as they are governed by the EABI
612 * calling convention.
613 */
614 loadConstant(cUnit, r4PC, (int)funct);
615 loadValuePair(cUnit, vSrc1, r0, r1);
616 loadValuePair(cUnit, vSrc2, r2, r3);
617 newLIR1(cUnit, THUMB_BLX_R, r4PC);
618 storeValuePair(cUnit, r0, r1, vDest, r2);
619 return false;
620 }
621
genArithOpLong(CompilationUnit * cUnit,MIR * mir,int vDest,int vSrc1,int vSrc2)622 static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
623 int vSrc1, int vSrc2)
624 {
625 int firstOp = THUMB_BKPT;
626 int secondOp = THUMB_BKPT;
627 bool callOut = false;
628 void *callTgt;
629 int retReg = r0;
630 int reg0, reg1, reg2, reg3;
631 /* TODO - find proper .h file to declare these */
632 long long __aeabi_ldivmod(long long op1, long long op2);
633
634 switch (mir->dalvikInsn.opCode) {
635 case OP_NOT_LONG:
636 firstOp = THUMB_MVN;
637 secondOp = THUMB_MVN;
638 break;
639 case OP_ADD_LONG:
640 case OP_ADD_LONG_2ADDR:
641 firstOp = THUMB_ADD_RRR;
642 secondOp = THUMB_ADC;
643 break;
644 case OP_SUB_LONG:
645 case OP_SUB_LONG_2ADDR:
646 firstOp = THUMB_SUB_RRR;
647 secondOp = THUMB_SBC;
648 break;
649 case OP_MUL_LONG:
650 case OP_MUL_LONG_2ADDR:
651 loadValuePair(cUnit, vSrc1, r0, r1);
652 loadValuePair(cUnit, vSrc2, r2, r3);
653 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
654 storeValuePair(cUnit, r0, r1, vDest, r2);
655 return false;
656 break;
657 case OP_DIV_LONG:
658 case OP_DIV_LONG_2ADDR:
659 callOut = true;
660 retReg = r0;
661 callTgt = (void*)__aeabi_ldivmod;
662 break;
663 /* NOTE - result is in r2/r3 instead of r0/r1 */
664 case OP_REM_LONG:
665 case OP_REM_LONG_2ADDR:
666 callOut = true;
667 callTgt = (void*)__aeabi_ldivmod;
668 retReg = r2;
669 break;
670 case OP_AND_LONG:
671 case OP_AND_LONG_2ADDR:
672 firstOp = THUMB_AND_RR;
673 secondOp = THUMB_AND_RR;
674 break;
675 case OP_OR_LONG:
676 case OP_OR_LONG_2ADDR:
677 firstOp = THUMB_ORR;
678 secondOp = THUMB_ORR;
679 break;
680 case OP_XOR_LONG:
681 case OP_XOR_LONG_2ADDR:
682 firstOp = THUMB_EOR;
683 secondOp = THUMB_EOR;
684 break;
685 case OP_NEG_LONG: {
686 reg0 = selectFirstRegister(cUnit, vSrc2, true);
687 reg1 = NEXT_REG(reg0);
688 reg2 = NEXT_REG(reg1);
689 reg3 = NEXT_REG(reg2);
690
691 loadValuePair(cUnit, vSrc2, reg0, reg1);
692 loadConstant(cUnit, reg3, 0);
693 newLIR3(cUnit, THUMB_SUB_RRR, reg2, reg3, reg0);
694 newLIR2(cUnit, THUMB_SBC, reg3, reg1);
695 storeValuePair(cUnit, reg2, reg3, vDest, reg0);
696 return false;
697 }
698 default:
699 LOGE("Invalid long arith op");
700 dvmAbort();
701 }
702 if (!callOut) {
703 reg0 = selectFirstRegister(cUnit, vSrc1, true);
704 reg1 = NEXT_REG(reg0);
705 reg2 = NEXT_REG(reg1);
706 reg3 = NEXT_REG(reg2);
707
708 loadValuePair(cUnit, vSrc1, reg0, reg1);
709 loadValuePair(cUnit, vSrc2, reg2, reg3);
710 genBinaryOpWide(cUnit, vDest, firstOp, secondOp, reg0, reg2);
711 /*
712 * Don't optimize the regsiter usage here as they are governed by the EABI
713 * calling convention.
714 */
715 } else {
716 loadValuePair(cUnit, vSrc2, r2, r3);
717 loadConstant(cUnit, r4PC, (int) callTgt);
718 loadValuePair(cUnit, vSrc1, r0, r1);
719 newLIR1(cUnit, THUMB_BLX_R, r4PC);
720 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
721 }
722 return false;
723 }
724
genArithOpInt(CompilationUnit * cUnit,MIR * mir,int vDest,int vSrc1,int vSrc2)725 static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
726 int vSrc1, int vSrc2)
727 {
728 int armOp = THUMB_BKPT;
729 bool callOut = false;
730 bool checkZero = false;
731 int retReg = r0;
732 void *callTgt;
733 int reg0, reg1, regDest;
734
735 /* TODO - find proper .h file to declare these */
736 int __aeabi_idivmod(int op1, int op2);
737 int __aeabi_idiv(int op1, int op2);
738
739 switch (mir->dalvikInsn.opCode) {
740 case OP_NEG_INT:
741 armOp = THUMB_NEG;
742 break;
743 case OP_NOT_INT:
744 armOp = THUMB_MVN;
745 break;
746 case OP_ADD_INT:
747 case OP_ADD_INT_2ADDR:
748 armOp = THUMB_ADD_RRR;
749 break;
750 case OP_SUB_INT:
751 case OP_SUB_INT_2ADDR:
752 armOp = THUMB_SUB_RRR;
753 break;
754 case OP_MUL_INT:
755 case OP_MUL_INT_2ADDR:
756 armOp = THUMB_MUL;
757 break;
758 case OP_DIV_INT:
759 case OP_DIV_INT_2ADDR:
760 callOut = true;
761 checkZero = true;
762 callTgt = __aeabi_idiv;
763 retReg = r0;
764 break;
765 /* NOTE: returns in r1 */
766 case OP_REM_INT:
767 case OP_REM_INT_2ADDR:
768 callOut = true;
769 checkZero = true;
770 callTgt = __aeabi_idivmod;
771 retReg = r1;
772 break;
773 case OP_AND_INT:
774 case OP_AND_INT_2ADDR:
775 armOp = THUMB_AND_RR;
776 break;
777 case OP_OR_INT:
778 case OP_OR_INT_2ADDR:
779 armOp = THUMB_ORR;
780 break;
781 case OP_XOR_INT:
782 case OP_XOR_INT_2ADDR:
783 armOp = THUMB_EOR;
784 break;
785 case OP_SHL_INT:
786 case OP_SHL_INT_2ADDR:
787 armOp = THUMB_LSLV;
788 break;
789 case OP_SHR_INT:
790 case OP_SHR_INT_2ADDR:
791 armOp = THUMB_ASRV;
792 break;
793 case OP_USHR_INT:
794 case OP_USHR_INT_2ADDR:
795 armOp = THUMB_LSRV;
796 break;
797 default:
798 LOGE("Invalid word arith op: 0x%x(%d)",
799 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
800 dvmAbort();
801 }
802 if (!callOut) {
803 /* Try to allocate reg0 to the currently cached source operand */
804 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
805 reg0 = selectFirstRegister(cUnit, vSrc1, false);
806 reg1 = NEXT_REG(reg0);
807 regDest = NEXT_REG(reg1);
808
809 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
810 loadValue(cUnit, vSrc2, reg1);
811 genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
812 } else {
813 reg0 = selectFirstRegister(cUnit, vSrc2, false);
814 reg1 = NEXT_REG(reg0);
815 regDest = NEXT_REG(reg1);
816
817 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
818 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
819 genBinaryOp(cUnit, vDest, armOp, reg1, reg0, regDest);
820 }
821 } else {
822 /*
823 * Load the callout target first since it will never be eliminated
824 * and its value will be used first.
825 */
826 loadConstant(cUnit, r2, (int) callTgt);
827 /*
828 * Load vSrc2 first if it is not cached in a native register or it
829 * is in r0 which will be clobbered if vSrc1 is loaded first.
830 */
831 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
832 cUnit->registerScoreboard.nativeReg == r0) {
833 /* Cannot be optimized and won't clobber r0 */
834 loadValue(cUnit, vSrc2, r1);
835 /* May be optimized if vSrc1 is cached */
836 loadValue(cUnit, vSrc1, r0);
837 } else {
838 loadValue(cUnit, vSrc1, r0);
839 loadValue(cUnit, vSrc2, r1);
840 }
841 if (checkZero) {
842 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
843 }
844 newLIR1(cUnit, THUMB_BLX_R, r2);
845 storeValue(cUnit, retReg, vDest, r2);
846 }
847 return false;
848 }
849
genArithOp(CompilationUnit * cUnit,MIR * mir)850 static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
851 {
852 OpCode opCode = mir->dalvikInsn.opCode;
853 int vA = mir->dalvikInsn.vA;
854 int vB = mir->dalvikInsn.vB;
855 int vC = mir->dalvikInsn.vC;
856
857 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
858 return genArithOpLong(cUnit,mir, vA, vA, vB);
859 }
860 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
861 return genArithOpLong(cUnit,mir, vA, vB, vC);
862 }
863 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
864 return genShiftOpLong(cUnit,mir, vA, vA, vB);
865 }
866 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
867 return genShiftOpLong(cUnit,mir, vA, vB, vC);
868 }
869 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
870 return genArithOpInt(cUnit,mir, vA, vA, vB);
871 }
872 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
873 return genArithOpInt(cUnit,mir, vA, vB, vC);
874 }
875 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
876 return genArithOpFloat(cUnit,mir, vA, vA, vB);
877 }
878 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
879 return genArithOpFloat(cUnit, mir, vA, vB, vC);
880 }
881 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
882 return genArithOpDouble(cUnit,mir, vA, vA, vB);
883 }
884 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
885 return genArithOpDouble(cUnit,mir, vA, vB, vC);
886 }
887 return true;
888 }
889
genConversionCall(CompilationUnit * cUnit,MIR * mir,void * funct,int srcSize,int tgtSize)890 static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
891 int srcSize, int tgtSize)
892 {
893 /*
894 * Don't optimize the register usage since it calls out to template
895 * functions
896 */
897 loadConstant(cUnit, r2, (int)funct);
898 if (srcSize == 1) {
899 loadValue(cUnit, mir->dalvikInsn.vB, r0);
900 } else {
901 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
902 }
903 newLIR1(cUnit, THUMB_BLX_R, r2);
904 if (tgtSize == 1) {
905 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
906 } else {
907 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
908 }
909 return false;
910 }
911
genInlinedStringLength(CompilationUnit * cUnit,MIR * mir)912 static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
913 {
914 DecodedInstruction *dInsn = &mir->dalvikInsn;
915 int offset = offsetof(InterpState, retval);
916 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
917 int reg1 = NEXT_REG(regObj);
918 loadValue(cUnit, dInsn->arg[0], regObj);
919 genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
920 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
921 newLIR3(cUnit, THUMB_STR_RRI5, reg1, rGLUE, offset >> 2);
922 return false;
923 }
924
925 /*
926 * NOTE: The amount of code for this body suggests it ought to
927 * be handled in a template (and could also be coded quite a bit
928 * more efficiently in ARM). However, the code is dependent on the
929 * internal structure layout of string objects which are most safely
930 * known at run time.
931 * TUNING: One possibility (which could also be used for StringCompareTo
932 * and StringEquals) is to generate string access helper subroutines on
933 * Jit startup, and then call them from the translated inline-executes.
934 */
genInlinedStringCharAt(CompilationUnit * cUnit,MIR * mir)935 static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
936 {
937 DecodedInstruction *dInsn = &mir->dalvikInsn;
938 int offset = offsetof(InterpState, retval);
939 int contents = offsetof(ArrayObject, contents);
940 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
941 int regIdx = NEXT_REG(regObj);
942 int regMax = NEXT_REG(regIdx);
943 int regOff = NEXT_REG(regMax);
944 loadValue(cUnit, dInsn->arg[0], regObj);
945 loadValue(cUnit, dInsn->arg[1], regIdx);
946 ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
947 mir->offset, NULL);
948 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
949 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
950 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
951 genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
952
953 newLIR2(cUnit, THUMB_ADD_RI8, regObj, contents);
954 newLIR3(cUnit, THUMB_ADD_RRR, regIdx, regIdx, regOff);
955 newLIR3(cUnit, THUMB_ADD_RRR, regIdx, regIdx, regIdx);
956 newLIR3(cUnit, THUMB_LDRH_RRR, regMax, regObj, regIdx);
957 newLIR3(cUnit, THUMB_STR_RRI5, regMax, rGLUE, offset >> 2);
958 return false;
959 }
960
genInlinedAbsInt(CompilationUnit * cUnit,MIR * mir)961 static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
962 {
963 int offset = offsetof(InterpState, retval);
964 DecodedInstruction *dInsn = &mir->dalvikInsn;
965 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
966 int sign = NEXT_REG(reg0);
967 /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
968 loadValue(cUnit, dInsn->arg[0], reg0);
969 newLIR3(cUnit, THUMB_ASR, sign, reg0, 31);
970 newLIR3(cUnit, THUMB_ADD_RRR, reg0, reg0, sign);
971 newLIR2(cUnit, THUMB_EOR, reg0, sign);
972 newLIR3(cUnit, THUMB_STR_RRI5, reg0, rGLUE, offset >> 2);
973 return false;
974 }
975
genInlinedAbsFloat(CompilationUnit * cUnit,MIR * mir)976 static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
977 {
978 int offset = offsetof(InterpState, retval);
979 DecodedInstruction *dInsn = &mir->dalvikInsn;
980 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
981 int signMask = NEXT_REG(reg0);
982 loadValue(cUnit, dInsn->arg[0], reg0);
983 loadConstant(cUnit, signMask, 0x7fffffff);
984 newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
985 newLIR3(cUnit, THUMB_STR_RRI5, reg0, rGLUE, offset >> 2);
986 return false;
987 }
988
genInlinedAbsDouble(CompilationUnit * cUnit,MIR * mir)989 static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
990 {
991 int offset = offsetof(InterpState, retval);
992 DecodedInstruction *dInsn = &mir->dalvikInsn;
993 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
994 int ophi = NEXT_REG(oplo);
995 int signMask = NEXT_REG(ophi);
996 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
997 loadConstant(cUnit, signMask, 0x7fffffff);
998 newLIR3(cUnit, THUMB_STR_RRI5, oplo, rGLUE, offset >> 2);
999 newLIR2(cUnit, THUMB_AND_RR, ophi, signMask);
1000 newLIR3(cUnit, THUMB_STR_RRI5, ophi, rGLUE, (offset >> 2)+1);
1001 return false;
1002 }
1003
1004 /* No select in thumb, so we need to branch. Thumb2 will do better */
genInlinedMinMaxInt(CompilationUnit * cUnit,MIR * mir,bool isMin)1005 static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
1006 {
1007 int offset = offsetof(InterpState, retval);
1008 DecodedInstruction *dInsn = &mir->dalvikInsn;
1009 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1010 int reg1 = NEXT_REG(reg0);
1011 loadValue(cUnit, dInsn->arg[0], reg0);
1012 loadValue(cUnit, dInsn->arg[1], reg1);
1013 newLIR2(cUnit, THUMB_CMP_RR, reg0, reg1);
1014 ArmLIR *branch1 = newLIR2(cUnit, THUMB_B_COND, 2,
1015 isMin ? ARM_COND_LT : ARM_COND_GT);
1016 newLIR2(cUnit, THUMB_MOV_RR, reg0, reg1);
1017 ArmLIR *target =
1018 newLIR3(cUnit, THUMB_STR_RRI5, reg0, rGLUE, offset >> 2);
1019 branch1->generic.target = (LIR *)target;
1020 return false;
1021 }
1022
genInlinedAbsLong(CompilationUnit * cUnit,MIR * mir)1023 static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
1024 {
1025 int offset = offsetof(InterpState, retval);
1026 DecodedInstruction *dInsn = &mir->dalvikInsn;
1027 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1028 int ophi = NEXT_REG(oplo);
1029 int sign = NEXT_REG(ophi);
1030 /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
1031 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1032 newLIR3(cUnit, THUMB_ASR, sign, ophi, 31);
1033 newLIR3(cUnit, THUMB_ADD_RRR, oplo, oplo, sign);
1034 newLIR2(cUnit, THUMB_ADC, ophi, sign);
1035 newLIR2(cUnit, THUMB_EOR, oplo, sign);
1036 newLIR2(cUnit, THUMB_EOR, ophi, sign);
1037 newLIR3(cUnit, THUMB_STR_RRI5, oplo, rGLUE, offset >> 2);
1038 newLIR3(cUnit, THUMB_STR_RRI5, ophi, rGLUE, (offset >> 2)+1);
1039 return false;
1040 }
1041
genProcessArgsNoRange(CompilationUnit * cUnit,MIR * mir,DecodedInstruction * dInsn,ArmLIR ** pcrLabel)1042 static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1043 DecodedInstruction *dInsn,
1044 ArmLIR **pcrLabel)
1045 {
1046 unsigned int i;
1047 unsigned int regMask = 0;
1048
1049 /* Load arguments to r0..r4 */
1050 for (i = 0; i < dInsn->vA; i++) {
1051 regMask |= 1 << i;
1052 loadValue(cUnit, dInsn->arg[i], i);
1053 }
1054 if (regMask) {
1055 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
1056 newLIR2(cUnit, THUMB_MOV_RR, r7, rFP);
1057 newLIR2(cUnit, THUMB_SUB_RI8, r7,
1058 sizeof(StackSaveArea) + (dInsn->vA << 2));
1059 /* generate null check */
1060 if (pcrLabel) {
1061 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1062 NULL);
1063 }
1064 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
1065 }
1066 }
1067
genProcessArgsRange(CompilationUnit * cUnit,MIR * mir,DecodedInstruction * dInsn,ArmLIR ** pcrLabel)1068 static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1069 DecodedInstruction *dInsn,
1070 ArmLIR **pcrLabel)
1071 {
1072 int srcOffset = dInsn->vC << 2;
1073 int numArgs = dInsn->vA;
1074 int regMask;
1075 /*
1076 * r4PC : &rFP[vC]
1077 * r7: &newFP[0]
1078 */
1079 if (srcOffset < 8) {
1080 newLIR3(cUnit, THUMB_ADD_RRI3, r4PC, rFP, srcOffset);
1081 } else {
1082 loadConstant(cUnit, r4PC, srcOffset);
1083 newLIR3(cUnit, THUMB_ADD_RRR, r4PC, rFP, r4PC);
1084 }
1085 /* load [r0 .. min(numArgs,4)] */
1086 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
1087 newLIR2(cUnit, THUMB_LDMIA, r4PC, regMask);
1088
1089 if (sizeof(StackSaveArea) + (numArgs << 2) < 256) {
1090 newLIR2(cUnit, THUMB_MOV_RR, r7, rFP);
1091 newLIR2(cUnit, THUMB_SUB_RI8, r7,
1092 sizeof(StackSaveArea) + (numArgs << 2));
1093 } else {
1094 loadConstant(cUnit, r7, sizeof(StackSaveArea) + (numArgs << 2));
1095 newLIR3(cUnit, THUMB_SUB_RRR, r7, rFP, r7);
1096 }
1097
1098 /* generate null check */
1099 if (pcrLabel) {
1100 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
1101 }
1102
1103 /*
1104 * Handle remaining 4n arguments:
1105 * store previously loaded 4 values and load the next 4 values
1106 */
1107 if (numArgs >= 8) {
1108 ArmLIR *loopLabel = NULL;
1109 /*
1110 * r0 contains "this" and it will be used later, so push it to the stack
1111 * first. Pushing r5 is just for stack alignment purposes.
1112 */
1113 newLIR1(cUnit, THUMB_PUSH, 1 << r0 | 1 << 5);
1114 /* No need to generate the loop structure if numArgs <= 11 */
1115 if (numArgs > 11) {
1116 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
1117 loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
1118 }
1119 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
1120 newLIR2(cUnit, THUMB_LDMIA, r4PC, regMask);
1121 /* No need to generate the loop structure if numArgs <= 11 */
1122 if (numArgs > 11) {
1123 newLIR2(cUnit, THUMB_SUB_RI8, 5, 4);
1124 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1125 }
1126 }
1127
1128 /* Save the last batch of loaded values */
1129 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
1130
1131 /* Generate the loop epilogue - don't use r0 */
1132 if ((numArgs > 4) && (numArgs % 4)) {
1133 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
1134 newLIR2(cUnit, THUMB_LDMIA, r4PC, regMask);
1135 }
1136 if (numArgs >= 8)
1137 newLIR1(cUnit, THUMB_POP, 1 << r0 | 1 << 5);
1138
1139 /* Save the modulo 4 arguments */
1140 if ((numArgs > 4) && (numArgs % 4)) {
1141 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
1142 }
1143 }
1144
1145 /*
1146 * Generate code to setup the call stack then jump to the chaining cell if it
1147 * is not a native method.
1148 */
genInvokeSingletonCommon(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList,ArmLIR * pcrLabel,const Method * calleeMethod)1149 static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
1150 BasicBlock *bb, ArmLIR *labelList,
1151 ArmLIR *pcrLabel,
1152 const Method *calleeMethod)
1153 {
1154 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
1155
1156 /* r1 = &retChainingCell */
1157 ArmLIR *addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL,
1158 r1, 0, 0);
1159 /* r4PC = dalvikCallsite */
1160 loadConstant(cUnit, r4PC,
1161 (int) (cUnit->method->insns + mir->offset));
1162 addrRetChain->generic.target = (LIR *) retChainingCell;
1163 /*
1164 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
1165 * r1 = &ChainingCell
1166 * r4PC = callsiteDPC
1167 */
1168 if (dvmIsNativeMethod(calleeMethod)) {
1169 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
1170 #if defined(INVOKE_STATS)
1171 gDvmJit.invokeNative++;
1172 #endif
1173 } else {
1174 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1175 #if defined(INVOKE_STATS)
1176 gDvmJit.invokeChain++;
1177 #endif
1178 /* Branch to the chaining cell */
1179 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1180 }
1181 /* Handle exceptions using the interpreter */
1182 genTrap(cUnit, mir->offset, pcrLabel);
1183 }
1184
1185 /*
1186 * Generate code to check the validity of a predicted chain and take actions
1187 * based on the result.
1188 *
1189 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1190 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1191 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1192 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1193 * 0x426a99b2 : blx_2 see above --+
1194 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1195 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1196 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1197 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1198 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1199 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1200 * 0x426a99c0 : blx r7 --+
1201 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1202 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1203 * 0x426a99c6 : blx_2 see above --+
1204 */
genInvokeVirtualCommon(CompilationUnit * cUnit,MIR * mir,int methodIndex,ArmLIR * retChainingCell,ArmLIR * predChainingCell,ArmLIR * pcrLabel)1205 static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1206 int methodIndex,
1207 ArmLIR *retChainingCell,
1208 ArmLIR *predChainingCell,
1209 ArmLIR *pcrLabel)
1210 {
1211 /* "this" is already left in r0 by genProcessArgs* */
1212
1213 /* r4PC = dalvikCallsite */
1214 loadConstant(cUnit, r4PC,
1215 (int) (cUnit->method->insns + mir->offset));
1216
1217 /* r1 = &retChainingCell */
1218 ArmLIR *addrRetChain = newLIR2(cUnit, THUMB_ADD_PC_REL,
1219 r1, 0);
1220 addrRetChain->generic.target = (LIR *) retChainingCell;
1221
1222 /* r2 = &predictedChainingCell */
1223 ArmLIR *predictedChainingCell =
1224 newLIR2(cUnit, THUMB_ADD_PC_REL, r2, 0);
1225 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1226
1227 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1228
1229 /* return through lr - jump to the chaining cell */
1230 genUnconditionalBranch(cUnit, predChainingCell);
1231
1232 /*
1233 * null-check on "this" may have been eliminated, but we still need a PC-
1234 * reconstruction label for stack overflow bailout.
1235 */
1236 if (pcrLabel == NULL) {
1237 int dPC = (int) (cUnit->method->insns + mir->offset);
1238 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1239 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
1240 pcrLabel->operands[0] = dPC;
1241 pcrLabel->operands[1] = mir->offset;
1242 /* Insert the place holder to the growable list */
1243 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1244 }
1245
1246 /* return through lr+2 - punt to the interpreter */
1247 genUnconditionalBranch(cUnit, pcrLabel);
1248
1249 /*
1250 * return through lr+4 - fully resolve the callee method.
1251 * r1 <- count
1252 * r2 <- &predictedChainCell
1253 * r3 <- this->class
1254 * r4 <- dPC
1255 * r7 <- this->class->vtable
1256 */
1257
1258 /* r0 <- calleeMethod */
1259 if (methodIndex < 32) {
1260 newLIR3(cUnit, THUMB_LDR_RRI5, r0, r7, methodIndex);
1261 } else {
1262 loadConstant(cUnit, r0, methodIndex<<2);
1263 newLIR3(cUnit, THUMB_LDR_RRR, r0, r7, r0);
1264 }
1265
1266 /* Check if rechain limit is reached */
1267 newLIR2(cUnit, THUMB_CMP_RI8, r1, 0);
1268
1269 ArmLIR *bypassRechaining =
1270 newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_GT);
1271
1272 newLIR3(cUnit, THUMB_LDR_RRI5, r7, rGLUE,
1273 offsetof(InterpState,
1274 jitToInterpEntries.dvmJitToPatchPredictedChain)
1275 >> 2);
1276
1277 /*
1278 * r0 = calleeMethod
1279 * r2 = &predictedChainingCell
1280 * r3 = class
1281 *
1282 * &returnChainingCell has been loaded into r1 but is not needed
1283 * when patching the chaining cell and will be clobbered upon
1284 * returning so it will be reconstructed again.
1285 */
1286 newLIR1(cUnit, THUMB_BLX_R, r7);
1287
1288 /* r1 = &retChainingCell */
1289 addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL, r1, 0, 0);
1290 addrRetChain->generic.target = (LIR *) retChainingCell;
1291
1292 bypassRechaining->generic.target = (LIR *) addrRetChain;
1293 /*
1294 * r0 = calleeMethod,
1295 * r1 = &ChainingCell,
1296 * r4PC = callsiteDPC,
1297 */
1298 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1299 #if defined(INVOKE_STATS)
1300 gDvmJit.invokePredictedChain++;
1301 #endif
1302 /* Handle exceptions using the interpreter */
1303 genTrap(cUnit, mir->offset, pcrLabel);
1304 }
1305
1306 /*
1307 * Up calling this function, "this" is stored in r0. The actual class will be
1308 * chased down off r0 and the predicted one will be retrieved through
1309 * predictedChainingCell then a comparison is performed to see whether the
1310 * previously established chaining is still valid.
1311 *
1312 * The return LIR is a branch based on the comparison result. The actual branch
1313 * target will be setup in the caller.
1314 */
genCheckPredictedChain(CompilationUnit * cUnit,ArmLIR * predChainingCell,ArmLIR * retChainingCell,MIR * mir)1315 static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1316 ArmLIR *predChainingCell,
1317 ArmLIR *retChainingCell,
1318 MIR *mir)
1319 {
1320 /* r3 now contains this->clazz */
1321 newLIR3(cUnit, THUMB_LDR_RRI5, r3, r0,
1322 offsetof(Object, clazz) >> 2);
1323
1324 /*
1325 * r2 now contains predicted class. The starting offset of the
1326 * cached value is 4 bytes into the chaining cell.
1327 */
1328 ArmLIR *getPredictedClass =
1329 newLIR3(cUnit, THUMB_LDR_PC_REL, r2, 0,
1330 offsetof(PredictedChainingCell, clazz));
1331 getPredictedClass->generic.target = (LIR *) predChainingCell;
1332
1333 /*
1334 * r0 now contains predicted method. The starting offset of the
1335 * cached value is 8 bytes into the chaining cell.
1336 */
1337 ArmLIR *getPredictedMethod =
1338 newLIR3(cUnit, THUMB_LDR_PC_REL, r0, 0,
1339 offsetof(PredictedChainingCell, method));
1340 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1341
1342 /* Load the stats counter to see if it is time to unchain and refresh */
1343 ArmLIR *getRechainingRequestCount =
1344 newLIR3(cUnit, THUMB_LDR_PC_REL, r7, 0,
1345 offsetof(PredictedChainingCell, counter));
1346 getRechainingRequestCount->generic.target =
1347 (LIR *) predChainingCell;
1348
1349 /* r4PC = dalvikCallsite */
1350 loadConstant(cUnit, r4PC,
1351 (int) (cUnit->method->insns + mir->offset));
1352
1353 /* r1 = &retChainingCell */
1354 ArmLIR *addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL,
1355 r1, 0, 0);
1356 addrRetChain->generic.target = (LIR *) retChainingCell;
1357
1358 /* Check if r2 (predicted class) == r3 (actual class) */
1359 newLIR2(cUnit, THUMB_CMP_RR, r2, r3);
1360
1361 return newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_EQ);
1362 }
1363
1364 /* Geneate a branch to go back to the interpreter */
genPuntToInterp(CompilationUnit * cUnit,unsigned int offset)1365 static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1366 {
1367 /* r0 = dalvik pc */
1368 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
1369 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE,
1370 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpPunt) >> 2);
1371 newLIR1(cUnit, THUMB_BLX_R, r1);
1372 }
1373
1374 /*
1375 * Attempt to single step one instruction using the interpreter and return
1376 * to the compiled code for the next Dalvik instruction
1377 */
genInterpSingleStep(CompilationUnit * cUnit,MIR * mir)1378 static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1379 {
1380 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1381 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1382 kInstrCanThrow;
1383 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1384 genPuntToInterp(cUnit, mir->offset);
1385 return;
1386 }
1387 int entryAddr = offsetof(InterpState,
1388 jitToInterpEntries.dvmJitToInterpSingleStep);
1389 newLIR3(cUnit, THUMB_LDR_RRI5, r2, rGLUE, entryAddr >> 2);
1390 /* r0 = dalvik pc */
1391 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1392 /* r1 = dalvik pc of following instruction */
1393 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
1394 newLIR1(cUnit, THUMB_BLX_R, r2);
1395 }
1396
1397
1398 /*****************************************************************************/
1399 /*
1400 * The following are the first-level codegen routines that analyze the format
1401 * of each bytecode then either dispatch special purpose codegen routines
1402 * or produce corresponding Thumb instructions directly.
1403 */
1404
handleFmt10t_Fmt20t_Fmt30t(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)1405 static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
1406 BasicBlock *bb, ArmLIR *labelList)
1407 {
1408 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1409 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1410 return false;
1411 }
1412
handleFmt10x(CompilationUnit * cUnit,MIR * mir)1413 static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1414 {
1415 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1416 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1417 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
1418 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1419 return true;
1420 }
1421 switch (dalvikOpCode) {
1422 case OP_RETURN_VOID:
1423 genReturnCommon(cUnit,mir);
1424 break;
1425 case OP_UNUSED_73:
1426 case OP_UNUSED_79:
1427 case OP_UNUSED_7A:
1428 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1429 return true;
1430 case OP_NOP:
1431 break;
1432 default:
1433 return true;
1434 }
1435 return false;
1436 }
1437
handleFmt11n_Fmt31i(CompilationUnit * cUnit,MIR * mir)1438 static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1439 {
1440 int reg0, reg1, reg2;
1441
1442 switch (mir->dalvikInsn.opCode) {
1443 case OP_CONST:
1444 case OP_CONST_4: {
1445 /* Avoid using the previously used register */
1446 reg0 = selectFirstRegister(cUnit, vNone, false);
1447 reg1 = NEXT_REG(reg0);
1448 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1449 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
1450 break;
1451 }
1452 case OP_CONST_WIDE_32: {
1453 /* Avoid using the previously used register */
1454 reg0 = selectFirstRegister(cUnit, vNone, true);
1455 reg1 = NEXT_REG(reg0);
1456 reg2 = NEXT_REG(reg1);
1457 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1458 newLIR3(cUnit, THUMB_ASR, reg1, reg0, 31);
1459 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
1460 break;
1461 }
1462 default:
1463 return true;
1464 }
1465 return false;
1466 }
1467
handleFmt21h(CompilationUnit * cUnit,MIR * mir)1468 static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1469 {
1470 int reg0, reg1, reg2;
1471
1472 /* Avoid using the previously used register */
1473 switch (mir->dalvikInsn.opCode) {
1474 case OP_CONST_HIGH16: {
1475 reg0 = selectFirstRegister(cUnit, vNone, false);
1476 reg1 = NEXT_REG(reg0);
1477 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
1478 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
1479 break;
1480 }
1481 case OP_CONST_WIDE_HIGH16: {
1482 reg0 = selectFirstRegister(cUnit, vNone, true);
1483 reg1 = NEXT_REG(reg0);
1484 reg2 = NEXT_REG(reg1);
1485 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
1486 loadConstant(cUnit, reg0, 0);
1487 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
1488 break;
1489 }
1490 default:
1491 return true;
1492 }
1493 return false;
1494 }
1495
handleFmt20bc(CompilationUnit * cUnit,MIR * mir)1496 static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1497 {
1498 /* For OP_THROW_VERIFICATION_ERROR */
1499 genInterpSingleStep(cUnit, mir);
1500 return false;
1501 }
1502
handleFmt21c_Fmt31c(CompilationUnit * cUnit,MIR * mir)1503 static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1504 {
1505 /* Native register to use if the interested value is vA */
1506 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
1507 /* Native register to use if source is not from Dalvik registers */
1508 int regvNone = selectFirstRegister(cUnit, vNone, false);
1509 /* Similar to regvA but for 64-bit values */
1510 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
1511 /* Similar to regvNone but for 64-bit values */
1512 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
1513
1514 switch (mir->dalvikInsn.opCode) {
1515 /*
1516 * TODO: Verify that we can ignore the resolution check here because
1517 * it will have already successfully been interpreted once
1518 */
1519 case OP_CONST_STRING_JUMBO:
1520 case OP_CONST_STRING: {
1521 void *strPtr = (void*)
1522 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1523 assert(strPtr != NULL);
1524 loadConstant(cUnit, regvNone, (int) strPtr );
1525 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
1526 break;
1527 }
1528 /*
1529 * TODO: Verify that we can ignore the resolution check here because
1530 * it will have already successfully been interpreted once
1531 */
1532 case OP_CONST_CLASS: {
1533 void *classPtr = (void*)
1534 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1535 assert(classPtr != NULL);
1536 loadConstant(cUnit, regvNone, (int) classPtr );
1537 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
1538 break;
1539 }
1540 case OP_SGET_OBJECT:
1541 case OP_SGET_BOOLEAN:
1542 case OP_SGET_CHAR:
1543 case OP_SGET_BYTE:
1544 case OP_SGET_SHORT:
1545 case OP_SGET: {
1546 int valOffset = offsetof(StaticField, value);
1547 void *fieldPtr = (void*)
1548 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1549 assert(fieldPtr != NULL);
1550 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
1551 newLIR3(cUnit, THUMB_LDR_RRI5, regvNone, regvNone, 0);
1552 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
1553 break;
1554 }
1555 case OP_SGET_WIDE: {
1556 int valOffset = offsetof(StaticField, value);
1557 void *fieldPtr = (void*)
1558 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1559 int reg0, reg1, reg2;
1560
1561 assert(fieldPtr != NULL);
1562 reg0 = regvNoneWide;
1563 reg1 = NEXT_REG(reg0);
1564 reg2 = NEXT_REG(reg1);
1565 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
1566 newLIR2(cUnit, THUMB_LDMIA, reg2, (1<<reg0 | 1<<reg1));
1567 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
1568 break;
1569 }
1570 case OP_SPUT_OBJECT:
1571 case OP_SPUT_BOOLEAN:
1572 case OP_SPUT_CHAR:
1573 case OP_SPUT_BYTE:
1574 case OP_SPUT_SHORT:
1575 case OP_SPUT: {
1576 int valOffset = offsetof(StaticField, value);
1577 void *fieldPtr = (void*)
1578 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1579
1580 assert(fieldPtr != NULL);
1581 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
1582 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
1583 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
1584 newLIR3(cUnit, THUMB_STR_RRI5, regvA, NEXT_REG(regvA), 0);
1585 break;
1586 }
1587 case OP_SPUT_WIDE: {
1588 int reg0, reg1, reg2;
1589 int valOffset = offsetof(StaticField, value);
1590 void *fieldPtr = (void*)
1591 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1592
1593 assert(fieldPtr != NULL);
1594 reg0 = regvAWide;
1595 reg1 = NEXT_REG(reg0);
1596 reg2 = NEXT_REG(reg1);
1597 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
1598 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
1599 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
1600 newLIR2(cUnit, THUMB_STMIA, reg2, (1<<reg0 | 1<<reg1));
1601 break;
1602 }
1603 case OP_NEW_INSTANCE: {
1604 /*
1605 * Obey the calling convention and don't mess with the register
1606 * usage.
1607 */
1608 ClassObject *classPtr = (void*)
1609 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1610 assert(classPtr != NULL);
1611 assert(classPtr->status & CLASS_INITIALIZED);
1612 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
1613 /* It's going to throw, just let the interp. deal with it. */
1614 genInterpSingleStep(cUnit, mir);
1615 return false;
1616 }
1617 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
1618 loadConstant(cUnit, r0, (int) classPtr);
1619 genExportPC(cUnit, mir, r2, r3 );
1620 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
1621 newLIR1(cUnit, THUMB_BLX_R, r4PC);
1622 /*
1623 * TODO: As coded, we'll bail and reinterpret on alloc failure.
1624 * Need a general mechanism to bail to thrown exception code.
1625 */
1626 genZeroCheck(cUnit, r0, mir->offset, NULL);
1627 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1628 break;
1629 }
1630 case OP_CHECK_CAST: {
1631 /*
1632 * Obey the calling convention and don't mess with the register
1633 * usage.
1634 */
1635 ClassObject *classPtr =
1636 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1637 loadConstant(cUnit, r1, (int) classPtr );
1638 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
1639 /*
1640 * TODO - in theory classPtr should be resoved by the time this
1641 * instruction made into a trace, but we are seeing NULL at runtime
1642 * so this check is temporarily used as a workaround.
1643 */
1644 ArmLIR * pcrLabel = genZeroCheck(cUnit, r1, mir->offset, NULL);
1645 newLIR2(cUnit, THUMB_CMP_RI8, r0, 0); /* Null? */
1646 ArmLIR *branch1 =
1647 newLIR2(cUnit, THUMB_B_COND, 4, ARM_COND_EQ);
1648 /* r0 now contains object->clazz */
1649 newLIR3(cUnit, THUMB_LDR_RRI5, r0, r0,
1650 offsetof(Object, clazz) >> 2);
1651 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
1652 newLIR2(cUnit, THUMB_CMP_RR, r0, r1);
1653 ArmLIR *branch2 =
1654 newLIR2(cUnit, THUMB_B_COND, 2, ARM_COND_EQ);
1655 newLIR1(cUnit, THUMB_BLX_R, r4PC);
1656 /* check cast failed - punt to the interpreter */
1657 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
1658 /* check cast passed - branch target here */
1659 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
1660 branch1->generic.target = (LIR *)target;
1661 branch2->generic.target = (LIR *)target;
1662 break;
1663 }
1664 default:
1665 return true;
1666 }
1667 return false;
1668 }
1669
handleFmt11x(CompilationUnit * cUnit,MIR * mir)1670 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1671 {
1672 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1673 switch (dalvikOpCode) {
1674 case OP_MOVE_EXCEPTION: {
1675 int offset = offsetof(InterpState, self);
1676 int exOffset = offsetof(Thread, exception);
1677 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE, offset >> 2);
1678 newLIR3(cUnit, THUMB_LDR_RRI5, r0, r1, exOffset >> 2);
1679 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1680 break;
1681 }
1682 case OP_MOVE_RESULT:
1683 case OP_MOVE_RESULT_OBJECT: {
1684 int offset = offsetof(InterpState, retval);
1685 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE, offset >> 2);
1686 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1687 break;
1688 }
1689 case OP_MOVE_RESULT_WIDE: {
1690 int offset = offsetof(InterpState, retval);
1691 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE, offset >> 2);
1692 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE, (offset >> 2)+1);
1693 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1694 break;
1695 }
1696 case OP_RETURN_WIDE: {
1697 loadValuePair(cUnit, mir->dalvikInsn.vA, r0, r1);
1698 int offset = offsetof(InterpState, retval);
1699 newLIR3(cUnit, THUMB_STR_RRI5, r0, rGLUE, offset >> 2);
1700 newLIR3(cUnit, THUMB_STR_RRI5, r1, rGLUE, (offset >> 2)+1);
1701 genReturnCommon(cUnit,mir);
1702 break;
1703 }
1704 case OP_RETURN:
1705 case OP_RETURN_OBJECT: {
1706 loadValue(cUnit, mir->dalvikInsn.vA, r0);
1707 int offset = offsetof(InterpState, retval);
1708 newLIR3(cUnit, THUMB_STR_RRI5, r0, rGLUE, offset >> 2);
1709 genReturnCommon(cUnit,mir);
1710 break;
1711 }
1712 /*
1713 * TODO-VERIFY: May be playing a bit fast and loose here. As coded,
1714 * a failure on lock/unlock will cause us to revert to the interpeter
1715 * to try again. This means we essentially ignore the first failure on
1716 * the assumption that the interpreter will correctly handle the 2nd.
1717 */
1718 case OP_MONITOR_ENTER:
1719 case OP_MONITOR_EXIT: {
1720 int offset = offsetof(InterpState, self);
1721 loadValue(cUnit, mir->dalvikInsn.vA, r1);
1722 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE, offset >> 2);
1723 if (dalvikOpCode == OP_MONITOR_ENTER) {
1724 loadConstant(cUnit, r2, (int)dvmLockObject);
1725 } else {
1726 loadConstant(cUnit, r2, (int)dvmUnlockObject);
1727 }
1728 /*
1729 * TODO-VERIFY: Note that we're not doing an EXPORT_PC, as
1730 * Lock/unlock won't throw, and this code does not support
1731 * DEADLOCK_PREDICTION or MONITOR_TRACKING. Should it?
1732 */
1733 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
1734 /* Do the call */
1735 newLIR1(cUnit, THUMB_BLX_R, r2);
1736 break;
1737 }
1738 case OP_THROW: {
1739 genInterpSingleStep(cUnit, mir);
1740 break;
1741 }
1742 default:
1743 return true;
1744 }
1745 return false;
1746 }
1747
genConversionPortable(CompilationUnit * cUnit,MIR * mir)1748 static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
1749 {
1750 OpCode opCode = mir->dalvikInsn.opCode;
1751
1752 float __aeabi_i2f( int op1 );
1753 int __aeabi_f2iz( float op1 );
1754 float __aeabi_d2f( double op1 );
1755 double __aeabi_f2d( float op1 );
1756 double __aeabi_i2d( int op1 );
1757 int __aeabi_d2iz( double op1 );
1758 float __aeabi_l2f( long op1 );
1759 double __aeabi_l2d( long op1 );
1760
1761 switch (opCode) {
1762 case OP_INT_TO_FLOAT:
1763 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
1764 case OP_FLOAT_TO_INT:
1765 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
1766 case OP_DOUBLE_TO_FLOAT:
1767 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
1768 case OP_FLOAT_TO_DOUBLE:
1769 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
1770 case OP_INT_TO_DOUBLE:
1771 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
1772 case OP_DOUBLE_TO_INT:
1773 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
1774 case OP_FLOAT_TO_LONG:
1775 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
1776 case OP_LONG_TO_FLOAT:
1777 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
1778 case OP_DOUBLE_TO_LONG:
1779 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
1780 case OP_LONG_TO_DOUBLE:
1781 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
1782 default:
1783 return true;
1784 }
1785 return false;
1786 }
1787
handleFmt12x(CompilationUnit * cUnit,MIR * mir)1788 static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1789 {
1790 OpCode opCode = mir->dalvikInsn.opCode;
1791 int vSrc1Dest = mir->dalvikInsn.vA;
1792 int vSrc2 = mir->dalvikInsn.vB;
1793 int reg0, reg1, reg2;
1794
1795 /* TODO - find the proper include file to declare these */
1796
1797 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1798 return genArithOp( cUnit, mir );
1799 }
1800
1801 /*
1802 * If data type is 64-bit, re-calculate the register numbers in the
1803 * corresponding cases.
1804 */
1805 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1806 reg1 = NEXT_REG(reg0);
1807 reg2 = NEXT_REG(reg1);
1808
1809 switch (opCode) {
1810 case OP_INT_TO_FLOAT:
1811 case OP_FLOAT_TO_INT:
1812 case OP_DOUBLE_TO_FLOAT:
1813 case OP_FLOAT_TO_DOUBLE:
1814 case OP_INT_TO_DOUBLE:
1815 case OP_DOUBLE_TO_INT:
1816 case OP_FLOAT_TO_LONG:
1817 case OP_LONG_TO_FLOAT:
1818 case OP_DOUBLE_TO_LONG:
1819 case OP_LONG_TO_DOUBLE:
1820 return genConversion(cUnit, mir);
1821 case OP_NEG_INT:
1822 case OP_NOT_INT:
1823 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
1824 case OP_NEG_LONG:
1825 case OP_NOT_LONG:
1826 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
1827 case OP_NEG_FLOAT:
1828 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
1829 case OP_NEG_DOUBLE:
1830 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
1831 case OP_MOVE_WIDE: {
1832 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1833 reg1 = NEXT_REG(reg0);
1834 reg2 = NEXT_REG(reg1);
1835
1836 loadValuePair(cUnit, vSrc2, reg0, reg1);
1837 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
1838 break;
1839 }
1840 case OP_INT_TO_LONG: {
1841 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1842 reg1 = NEXT_REG(reg0);
1843 reg2 = NEXT_REG(reg1);
1844
1845 loadValue(cUnit, vSrc2, reg0);
1846 newLIR3(cUnit, THUMB_ASR, reg1, reg0, 31);
1847 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
1848 break;
1849 }
1850 case OP_MOVE:
1851 case OP_MOVE_OBJECT:
1852 case OP_LONG_TO_INT:
1853 loadValue(cUnit, vSrc2, reg0);
1854 storeValue(cUnit, reg0, vSrc1Dest, reg1);
1855 break;
1856 case OP_INT_TO_BYTE:
1857 loadValue(cUnit, vSrc2, reg0);
1858 newLIR3(cUnit, THUMB_LSL, reg0, reg0, 24);
1859 newLIR3(cUnit, THUMB_ASR, reg0, reg0, 24);
1860 storeValue(cUnit, reg0, vSrc1Dest, reg1);
1861 break;
1862 case OP_INT_TO_SHORT:
1863 loadValue(cUnit, vSrc2, reg0);
1864 newLIR3(cUnit, THUMB_LSL, reg0, reg0, 16);
1865 newLIR3(cUnit, THUMB_ASR, reg0, reg0, 16);
1866 storeValue(cUnit, reg0, vSrc1Dest, reg1);
1867 break;
1868 case OP_INT_TO_CHAR:
1869 loadValue(cUnit, vSrc2, reg0);
1870 newLIR3(cUnit, THUMB_LSL, reg0, reg0, 16);
1871 newLIR3(cUnit, THUMB_LSR, reg0, reg0, 16);
1872 storeValue(cUnit, reg0, vSrc1Dest, reg1);
1873 break;
1874 case OP_ARRAY_LENGTH: {
1875 int lenOffset = offsetof(ArrayObject, length);
1876 loadValue(cUnit, vSrc2, reg0);
1877 genNullCheck(cUnit, vSrc2, reg0, mir->offset, NULL);
1878 newLIR3(cUnit, THUMB_LDR_RRI5, reg0, reg0, lenOffset >> 2);
1879 storeValue(cUnit, reg0, vSrc1Dest, reg1);
1880 break;
1881 }
1882 default:
1883 return true;
1884 }
1885 return false;
1886 }
1887
handleFmt21s(CompilationUnit * cUnit,MIR * mir)1888 static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
1889 {
1890 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1891 int reg0, reg1, reg2;
1892
1893 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
1894 if (dalvikOpCode == OP_CONST_WIDE_16) {
1895 int vDest = mir->dalvikInsn.vA;
1896 int BBBB = mir->dalvikInsn.vB;
1897
1898 reg0 = selectFirstRegister(cUnit, vNone, true);
1899 reg1 = NEXT_REG(reg0);
1900 reg2 = NEXT_REG(reg1);
1901
1902 loadConstant(cUnit, reg0, BBBB);
1903 newLIR3(cUnit, THUMB_ASR, reg1, reg0, 31);
1904
1905 /* Save the long values to the specified Dalvik register pair */
1906 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
1907 } else if (dalvikOpCode == OP_CONST_16) {
1908 int vDest = mir->dalvikInsn.vA;
1909 int BBBB = mir->dalvikInsn.vB;
1910
1911 reg0 = selectFirstRegister(cUnit, vNone, false);
1912 reg1 = NEXT_REG(reg0);
1913
1914 loadConstant(cUnit, reg0, BBBB);
1915 storeValue(cUnit, reg0, vDest, reg1);
1916 } else {
1917 return true;
1918 }
1919 return false;
1920 }
1921
1922 /* Compare agaist zero */
handleFmt21t(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)1923 static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
1924 ArmLIR *labelList)
1925 {
1926 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1927 ArmConditionCode cond;
1928 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
1929
1930 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
1931 newLIR2(cUnit, THUMB_CMP_RI8, reg0, 0);
1932
1933 switch (dalvikOpCode) {
1934 case OP_IF_EQZ:
1935 cond = ARM_COND_EQ;
1936 break;
1937 case OP_IF_NEZ:
1938 cond = ARM_COND_NE;
1939 break;
1940 case OP_IF_LTZ:
1941 cond = ARM_COND_LT;
1942 break;
1943 case OP_IF_GEZ:
1944 cond = ARM_COND_GE;
1945 break;
1946 case OP_IF_GTZ:
1947 cond = ARM_COND_GT;
1948 break;
1949 case OP_IF_LEZ:
1950 cond = ARM_COND_LE;
1951 break;
1952 default:
1953 cond = 0;
1954 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
1955 dvmAbort();
1956 }
1957 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1958 /* This mostly likely will be optimized away in a later phase */
1959 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1960 return false;
1961 }
1962
handleFmt22b_Fmt22s(CompilationUnit * cUnit,MIR * mir)1963 static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
1964 {
1965 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1966 int vSrc = mir->dalvikInsn.vB;
1967 int vDest = mir->dalvikInsn.vA;
1968 int lit = mir->dalvikInsn.vC;
1969 int armOp;
1970 int reg0, reg1, regDest;
1971
1972 reg0 = selectFirstRegister(cUnit, vSrc, false);
1973 reg1 = NEXT_REG(reg0);
1974 regDest = NEXT_REG(reg1);
1975
1976 /* TODO: find the proper .h file to declare these */
1977 int __aeabi_idivmod(int op1, int op2);
1978 int __aeabi_idiv(int op1, int op2);
1979
1980 switch (dalvikOpCode) {
1981 case OP_ADD_INT_LIT8:
1982 case OP_ADD_INT_LIT16:
1983 loadValue(cUnit, vSrc, reg0);
1984 if (lit <= 7 && lit >= 0) {
1985 newLIR3(cUnit, THUMB_ADD_RRI3, regDest, reg0, lit);
1986 storeValue(cUnit, regDest, vDest, reg1);
1987 } else if (lit <= 255 && lit >= 0) {
1988 newLIR2(cUnit, THUMB_ADD_RI8, reg0, lit);
1989 storeValue(cUnit, reg0, vDest, reg1);
1990 } else if (lit >= -7 && lit <= 0) {
1991 /* Convert to a small constant subtraction */
1992 newLIR3(cUnit, THUMB_SUB_RRI3, regDest, reg0, -lit);
1993 storeValue(cUnit, regDest, vDest, reg1);
1994 } else if (lit >= -255 && lit <= 0) {
1995 /* Convert to a small constant subtraction */
1996 newLIR2(cUnit, THUMB_SUB_RI8, reg0, -lit);
1997 storeValue(cUnit, reg0, vDest, reg1);
1998 } else {
1999 loadConstant(cUnit, reg1, lit);
2000 genBinaryOp(cUnit, vDest, THUMB_ADD_RRR, reg0, reg1, regDest);
2001 }
2002 break;
2003
2004 case OP_RSUB_INT_LIT8:
2005 case OP_RSUB_INT:
2006 loadValue(cUnit, vSrc, reg1);
2007 loadConstant(cUnit, reg0, lit);
2008 genBinaryOp(cUnit, vDest, THUMB_SUB_RRR, reg0, reg1, regDest);
2009 break;
2010
2011 case OP_MUL_INT_LIT8:
2012 case OP_MUL_INT_LIT16:
2013 case OP_AND_INT_LIT8:
2014 case OP_AND_INT_LIT16:
2015 case OP_OR_INT_LIT8:
2016 case OP_OR_INT_LIT16:
2017 case OP_XOR_INT_LIT8:
2018 case OP_XOR_INT_LIT16:
2019 loadValue(cUnit, vSrc, reg0);
2020 loadConstant(cUnit, reg1, lit);
2021 switch (dalvikOpCode) {
2022 case OP_MUL_INT_LIT8:
2023 case OP_MUL_INT_LIT16:
2024 armOp = THUMB_MUL;
2025 break;
2026 case OP_AND_INT_LIT8:
2027 case OP_AND_INT_LIT16:
2028 armOp = THUMB_AND_RR;
2029 break;
2030 case OP_OR_INT_LIT8:
2031 case OP_OR_INT_LIT16:
2032 armOp = THUMB_ORR;
2033 break;
2034 case OP_XOR_INT_LIT8:
2035 case OP_XOR_INT_LIT16:
2036 armOp = THUMB_EOR;
2037 break;
2038 default:
2039 dvmAbort();
2040 }
2041 genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
2042 break;
2043
2044 case OP_SHL_INT_LIT8:
2045 case OP_SHR_INT_LIT8:
2046 case OP_USHR_INT_LIT8:
2047 loadValue(cUnit, vSrc, reg0);
2048 switch (dalvikOpCode) {
2049 case OP_SHL_INT_LIT8:
2050 armOp = THUMB_LSL;
2051 break;
2052 case OP_SHR_INT_LIT8:
2053 armOp = THUMB_ASR;
2054 break;
2055 case OP_USHR_INT_LIT8:
2056 armOp = THUMB_LSR;
2057 break;
2058 default: dvmAbort();
2059 }
2060 newLIR3(cUnit, armOp, reg0, reg0, lit);
2061 storeValue(cUnit, reg0, vDest, reg1);
2062 break;
2063
2064 case OP_DIV_INT_LIT8:
2065 case OP_DIV_INT_LIT16:
2066 /* Register usage based on the calling convention */
2067 if (lit == 0) {
2068 /* Let the interpreter deal with div by 0 */
2069 genInterpSingleStep(cUnit, mir);
2070 return false;
2071 }
2072 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2073 loadConstant(cUnit, r1, lit);
2074 loadValue(cUnit, vSrc, r0);
2075 newLIR1(cUnit, THUMB_BLX_R, r2);
2076 storeValue(cUnit, r0, vDest, r2);
2077 break;
2078
2079 case OP_REM_INT_LIT8:
2080 case OP_REM_INT_LIT16:
2081 /* Register usage based on the calling convention */
2082 if (lit == 0) {
2083 /* Let the interpreter deal with div by 0 */
2084 genInterpSingleStep(cUnit, mir);
2085 return false;
2086 }
2087 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2088 loadConstant(cUnit, r1, lit);
2089 loadValue(cUnit, vSrc, r0);
2090 newLIR1(cUnit, THUMB_BLX_R, r2);
2091 storeValue(cUnit, r1, vDest, r2);
2092 break;
2093 default:
2094 return true;
2095 }
2096 return false;
2097 }
2098
handleFmt22c(CompilationUnit * cUnit,MIR * mir)2099 static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2100 {
2101 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2102 int fieldOffset;
2103
2104 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2105 InstField *pInstField = (InstField *)
2106 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2107 int fieldOffset;
2108
2109 assert(pInstField != NULL);
2110 fieldOffset = pInstField->byteOffset;
2111 } else {
2112 /* To make the compiler happy */
2113 fieldOffset = 0;
2114 }
2115 switch (dalvikOpCode) {
2116 /*
2117 * TODO: I may be assuming too much here.
2118 * Verify what is known at JIT time.
2119 */
2120 case OP_NEW_ARRAY: {
2121 void *classPtr = (void*)
2122 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2123 assert(classPtr != NULL);
2124 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2125 loadConstant(cUnit, r0, (int) classPtr );
2126 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
2127 ArmLIR *pcrLabel =
2128 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2129 genExportPC(cUnit, mir, r2, r3 );
2130 newLIR2(cUnit, THUMB_MOV_IMM,r2,ALLOC_DONT_TRACK);
2131 newLIR1(cUnit, THUMB_BLX_R, r4PC);
2132 /*
2133 * TODO: As coded, we'll bail and reinterpret on alloc failure.
2134 * Need a general mechanism to bail to thrown exception code.
2135 */
2136 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
2137 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2138 break;
2139 }
2140 /*
2141 * TODO: I may be assuming too much here.
2142 * Verify what is known at JIT time.
2143 */
2144 case OP_INSTANCE_OF: {
2145 ClassObject *classPtr =
2146 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2147 assert(classPtr != NULL);
2148 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
2149 loadConstant(cUnit, r2, (int) classPtr );
2150 newLIR2(cUnit, THUMB_CMP_RI8, r0, 0); /* Null? */
2151 /* When taken r0 has NULL which can be used for store directly */
2152 ArmLIR *branch1 = newLIR2(cUnit, THUMB_B_COND, 4,
2153 ARM_COND_EQ);
2154 /* r1 now contains object->clazz */
2155 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0,
2156 offsetof(Object, clazz) >> 2);
2157 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
2158 loadConstant(cUnit, r0, 1); /* Assume true */
2159 newLIR2(cUnit, THUMB_CMP_RR, r1, r2);
2160 ArmLIR *branch2 = newLIR2(cUnit, THUMB_B_COND, 2,
2161 ARM_COND_EQ);
2162 newLIR2(cUnit, THUMB_MOV_RR, r0, r1);
2163 newLIR2(cUnit, THUMB_MOV_RR, r1, r2);
2164 newLIR1(cUnit, THUMB_BLX_R, r4PC);
2165 /* branch target here */
2166 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
2167 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2168 branch1->generic.target = (LIR *)target;
2169 branch2->generic.target = (LIR *)target;
2170 break;
2171 }
2172 case OP_IGET_WIDE:
2173 genIGetWide(cUnit, mir, fieldOffset);
2174 break;
2175 case OP_IGET:
2176 case OP_IGET_OBJECT:
2177 genIGet(cUnit, mir, THUMB_LDR_RRR, fieldOffset);
2178 break;
2179 case OP_IGET_BOOLEAN:
2180 genIGet(cUnit, mir, THUMB_LDRB_RRR, fieldOffset);
2181 break;
2182 case OP_IGET_BYTE:
2183 genIGet(cUnit, mir, THUMB_LDRSB_RRR, fieldOffset);
2184 break;
2185 case OP_IGET_CHAR:
2186 genIGet(cUnit, mir, THUMB_LDRH_RRR, fieldOffset);
2187 break;
2188 case OP_IGET_SHORT:
2189 genIGet(cUnit, mir, THUMB_LDRSH_RRR, fieldOffset);
2190 break;
2191 case OP_IPUT_WIDE:
2192 genIPutWide(cUnit, mir, fieldOffset);
2193 break;
2194 case OP_IPUT:
2195 case OP_IPUT_OBJECT:
2196 genIPut(cUnit, mir, THUMB_STR_RRR, fieldOffset);
2197 break;
2198 case OP_IPUT_SHORT:
2199 case OP_IPUT_CHAR:
2200 genIPut(cUnit, mir, THUMB_STRH_RRR, fieldOffset);
2201 break;
2202 case OP_IPUT_BYTE:
2203 case OP_IPUT_BOOLEAN:
2204 genIPut(cUnit, mir, THUMB_STRB_RRR, fieldOffset);
2205 break;
2206 default:
2207 return true;
2208 }
2209 return false;
2210 }
2211
handleFmt22cs(CompilationUnit * cUnit,MIR * mir)2212 static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2213 {
2214 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2215 int fieldOffset = mir->dalvikInsn.vC;
2216 switch (dalvikOpCode) {
2217 case OP_IGET_QUICK:
2218 case OP_IGET_OBJECT_QUICK:
2219 genIGet(cUnit, mir, THUMB_LDR_RRR, fieldOffset);
2220 break;
2221 case OP_IPUT_QUICK:
2222 case OP_IPUT_OBJECT_QUICK:
2223 genIPut(cUnit, mir, THUMB_STR_RRR, fieldOffset);
2224 break;
2225 case OP_IGET_WIDE_QUICK:
2226 genIGetWide(cUnit, mir, fieldOffset);
2227 break;
2228 case OP_IPUT_WIDE_QUICK:
2229 genIPutWide(cUnit, mir, fieldOffset);
2230 break;
2231 default:
2232 return true;
2233 }
2234 return false;
2235
2236 }
2237
2238 /* Compare agaist zero */
handleFmt22t(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)2239 static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2240 ArmLIR *labelList)
2241 {
2242 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2243 ArmConditionCode cond;
2244 int reg0, reg1;
2245
2246 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2247 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2248 reg1 = NEXT_REG(reg0);
2249 /* Load vB first since vA can be fetched via a move */
2250 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2251 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2252 } else {
2253 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2254 reg1 = NEXT_REG(reg0);
2255 /* Load vA first since vB can be fetched via a move */
2256 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2257 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2258 }
2259 newLIR2(cUnit, THUMB_CMP_RR, reg0, reg1);
2260
2261 switch (dalvikOpCode) {
2262 case OP_IF_EQ:
2263 cond = ARM_COND_EQ;
2264 break;
2265 case OP_IF_NE:
2266 cond = ARM_COND_NE;
2267 break;
2268 case OP_IF_LT:
2269 cond = ARM_COND_LT;
2270 break;
2271 case OP_IF_GE:
2272 cond = ARM_COND_GE;
2273 break;
2274 case OP_IF_GT:
2275 cond = ARM_COND_GT;
2276 break;
2277 case OP_IF_LE:
2278 cond = ARM_COND_LE;
2279 break;
2280 default:
2281 cond = 0;
2282 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2283 dvmAbort();
2284 }
2285 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2286 /* This mostly likely will be optimized away in a later phase */
2287 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2288 return false;
2289 }
2290
handleFmt22x_Fmt32x(CompilationUnit * cUnit,MIR * mir)2291 static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2292 {
2293 OpCode opCode = mir->dalvikInsn.opCode;
2294 int vSrc1Dest = mir->dalvikInsn.vA;
2295 int vSrc2 = mir->dalvikInsn.vB;
2296 int reg0, reg1, reg2;
2297
2298 switch (opCode) {
2299 case OP_MOVE_16:
2300 case OP_MOVE_OBJECT_16:
2301 case OP_MOVE_FROM16:
2302 case OP_MOVE_OBJECT_FROM16: {
2303 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2304 reg1 = NEXT_REG(reg0);
2305 loadValue(cUnit, vSrc2, reg0);
2306 storeValue(cUnit, reg0, vSrc1Dest, reg1);
2307 break;
2308 }
2309 case OP_MOVE_WIDE_16:
2310 case OP_MOVE_WIDE_FROM16: {
2311 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2312 reg1 = NEXT_REG(reg0);
2313 reg2 = NEXT_REG(reg1);
2314 loadValuePair(cUnit, vSrc2, reg0, reg1);
2315 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
2316 break;
2317 }
2318 default:
2319 return true;
2320 }
2321 return false;
2322 }
2323
handleFmt23x(CompilationUnit * cUnit,MIR * mir)2324 static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2325 {
2326 OpCode opCode = mir->dalvikInsn.opCode;
2327 int vA = mir->dalvikInsn.vA;
2328 int vB = mir->dalvikInsn.vB;
2329 int vC = mir->dalvikInsn.vC;
2330
2331 /* Don't optimize for register usage since out-of-line handlers are used */
2332 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2333 return genArithOp( cUnit, mir );
2334 }
2335
2336 switch (opCode) {
2337 case OP_CMPL_FLOAT:
2338 case OP_CMPG_FLOAT:
2339 case OP_CMPL_DOUBLE:
2340 case OP_CMPG_DOUBLE:
2341 return genCmpX(cUnit, mir, vA, vB, vC);
2342 case OP_CMP_LONG:
2343 loadValuePair(cUnit,vB, r0, r1);
2344 loadValuePair(cUnit, vC, r2, r3);
2345 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
2346 storeValue(cUnit, r0, vA, r1);
2347 break;
2348 case OP_AGET_WIDE:
2349 genArrayGet(cUnit, mir, THUMB_LDR_RRR, vB, vC, vA, 3);
2350 break;
2351 case OP_AGET:
2352 case OP_AGET_OBJECT:
2353 genArrayGet(cUnit, mir, THUMB_LDR_RRR, vB, vC, vA, 2);
2354 break;
2355 case OP_AGET_BOOLEAN:
2356 genArrayGet(cUnit, mir, THUMB_LDRB_RRR, vB, vC, vA, 0);
2357 break;
2358 case OP_AGET_BYTE:
2359 genArrayGet(cUnit, mir, THUMB_LDRSB_RRR, vB, vC, vA, 0);
2360 break;
2361 case OP_AGET_CHAR:
2362 genArrayGet(cUnit, mir, THUMB_LDRH_RRR, vB, vC, vA, 1);
2363 break;
2364 case OP_AGET_SHORT:
2365 genArrayGet(cUnit, mir, THUMB_LDRSH_RRR, vB, vC, vA, 1);
2366 break;
2367 case OP_APUT_WIDE:
2368 genArrayPut(cUnit, mir, THUMB_STR_RRR, vB, vC, vA, 3);
2369 break;
2370 case OP_APUT:
2371 case OP_APUT_OBJECT:
2372 genArrayPut(cUnit, mir, THUMB_STR_RRR, vB, vC, vA, 2);
2373 break;
2374 case OP_APUT_SHORT:
2375 case OP_APUT_CHAR:
2376 genArrayPut(cUnit, mir, THUMB_STRH_RRR, vB, vC, vA, 1);
2377 break;
2378 case OP_APUT_BYTE:
2379 case OP_APUT_BOOLEAN:
2380 genArrayPut(cUnit, mir, THUMB_STRB_RRR, vB, vC, vA, 0);
2381 break;
2382 default:
2383 return true;
2384 }
2385 return false;
2386 }
2387
handleFmt31t(CompilationUnit * cUnit,MIR * mir)2388 static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2389 {
2390 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2391 switch (dalvikOpCode) {
2392 case OP_FILL_ARRAY_DATA: {
2393 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2394 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2395 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2396 (int) (cUnit->method->insns + mir->offset));
2397 genExportPC(cUnit, mir, r2, r3 );
2398 newLIR1(cUnit, THUMB_BLX_R, r4PC);
2399 genZeroCheck(cUnit, r0, mir->offset, NULL);
2400 break;
2401 }
2402 /*
2403 * TODO
2404 * - Add a 1 to 3-entry per-location cache here to completely
2405 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2406 * - Use out-of-line handlers for both of these
2407 */
2408 case OP_PACKED_SWITCH:
2409 case OP_SPARSE_SWITCH: {
2410 if (dalvikOpCode == OP_PACKED_SWITCH) {
2411 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2412 } else {
2413 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2414 }
2415 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2416 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2417 (int) (cUnit->method->insns + mir->offset));
2418 newLIR1(cUnit, THUMB_BLX_R, r4PC);
2419 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
2420 newLIR3(cUnit, THUMB_LDR_RRI5, r2, rGLUE,
2421 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNoChain)
2422 >> 2);
2423 newLIR3(cUnit, THUMB_ADD_RRR, r0, r0, r0);
2424 newLIR3(cUnit, THUMB_ADD_RRR, r4PC, r0, r1);
2425 newLIR1(cUnit, THUMB_BLX_R, r2);
2426 break;
2427 }
2428 default:
2429 return true;
2430 }
2431 return false;
2432 }
2433
handleFmt35c_3rc(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)2434 static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2435 ArmLIR *labelList)
2436 {
2437 ArmLIR *retChainingCell = NULL;
2438 ArmLIR *pcrLabel = NULL;
2439
2440 if (bb->fallThrough != NULL)
2441 retChainingCell = &labelList[bb->fallThrough->id];
2442
2443 DecodedInstruction *dInsn = &mir->dalvikInsn;
2444 switch (mir->dalvikInsn.opCode) {
2445 /*
2446 * calleeMethod = this->clazz->vtable[
2447 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2448 * ]
2449 */
2450 case OP_INVOKE_VIRTUAL:
2451 case OP_INVOKE_VIRTUAL_RANGE: {
2452 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2453 int methodIndex =
2454 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2455 methodIndex;
2456
2457 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2458 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2459 else
2460 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2461
2462 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2463 retChainingCell,
2464 predChainingCell,
2465 pcrLabel);
2466 break;
2467 }
2468 /*
2469 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2470 * ->pResMethods[BBBB]->methodIndex]
2471 */
2472 /* TODO - not excersized in RunPerf.jar */
2473 case OP_INVOKE_SUPER:
2474 case OP_INVOKE_SUPER_RANGE: {
2475 int mIndex = cUnit->method->clazz->pDvmDex->
2476 pResMethods[dInsn->vB]->methodIndex;
2477 const Method *calleeMethod =
2478 cUnit->method->clazz->super->vtable[mIndex];
2479
2480 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2481 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2482 else
2483 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2484
2485 /* r0 = calleeMethod */
2486 loadConstant(cUnit, r0, (int) calleeMethod);
2487
2488 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2489 calleeMethod);
2490 break;
2491 }
2492 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2493 case OP_INVOKE_DIRECT:
2494 case OP_INVOKE_DIRECT_RANGE: {
2495 const Method *calleeMethod =
2496 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2497
2498 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2499 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2500 else
2501 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2502
2503 /* r0 = calleeMethod */
2504 loadConstant(cUnit, r0, (int) calleeMethod);
2505
2506 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2507 calleeMethod);
2508 break;
2509 }
2510 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2511 case OP_INVOKE_STATIC:
2512 case OP_INVOKE_STATIC_RANGE: {
2513 const Method *calleeMethod =
2514 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2515
2516 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2517 genProcessArgsNoRange(cUnit, mir, dInsn,
2518 NULL /* no null check */);
2519 else
2520 genProcessArgsRange(cUnit, mir, dInsn,
2521 NULL /* no null check */);
2522
2523 /* r0 = calleeMethod */
2524 loadConstant(cUnit, r0, (int) calleeMethod);
2525
2526 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2527 calleeMethod);
2528 break;
2529 }
2530 /*
2531 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2532 * BBBB, method, method->clazz->pDvmDex)
2533 *
2534 * Given "invoke-interface {v0}", the following is the generated code:
2535 *
2536 * 0x426a9abe : ldr r0, [r5, #0] --+
2537 * 0x426a9ac0 : mov r7, r5 |
2538 * 0x426a9ac2 : sub r7, #24 |
2539 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
2540 * 0x426a9ac6 : beq 0x426a9afe |
2541 * 0x426a9ac8 : stmia r7, <r0> --+
2542 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2543 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
2544 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
2545 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
2546 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
2547 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
2548 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
2549 * 0x426a9ad8 : mov r9, r1 --+
2550 * 0x426a9ada : mov r10, r2 |
2551 * 0x426a9adc : mov r12, r3 |
2552 * 0x426a9ade : mov r0, r3 |
2553 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
2554 * 0x426a9ae2 : ldr r2, [pc, #76] |
2555 * 0x426a9ae4 : ldr r3, [pc, #68] |
2556 * 0x426a9ae6 : ldr r7, [pc, #64] |
2557 * 0x426a9ae8 : blx r7 --+
2558 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
2559 * 0x426a9aec : cmp r1, #0 --> compare against 0
2560 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
2561 * 0x426a9af0 : ldr r7, [r6, #96] --+
2562 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
2563 * 0x426a9af4 : mov r3, r12 |
2564 * 0x426a9af6 : blx r7 --+
2565 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
2566 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2567 * 0x426a9afc : blx_2 see above --+
2568 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
2569 * 0x426a9afe (0042): ldr r0, [pc, #52]
2570 * Exception_Handling:
2571 * 0x426a9b00 (0044): ldr r1, [r6, #84]
2572 * 0x426a9b02 (0046): blx r1
2573 * 0x426a9b04 (0048): .align4
2574 * -------- chaining cell (hot): 0x0021
2575 * 0x426a9b04 (0048): ldr r0, [r6, #92]
2576 * 0x426a9b06 (004a): blx r0
2577 * 0x426a9b08 (004c): data 0x7872(30834)
2578 * 0x426a9b0a (004e): data 0x428b(17035)
2579 * 0x426a9b0c (0050): .align4
2580 * -------- chaining cell (predicted)
2581 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
2582 * 0x426a9b0e (0052): data 0x0000(0)
2583 * 0x426a9b10 (0054): data 0x0000(0) --> class
2584 * 0x426a9b12 (0056): data 0x0000(0)
2585 * 0x426a9b14 (0058): data 0x0000(0) --> method
2586 * 0x426a9b16 (005a): data 0x0000(0)
2587 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
2588 * 0x426a9b1a (005e): data 0x0000(0)
2589 * 0x426a9b28 (006c): .word (0xad0392a5)
2590 * 0x426a9b2c (0070): .word (0x6e750)
2591 * 0x426a9b30 (0074): .word (0x4109a618)
2592 * 0x426a9b34 (0078): .word (0x428b786c)
2593 */
2594 case OP_INVOKE_INTERFACE:
2595 case OP_INVOKE_INTERFACE_RANGE: {
2596 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2597 int methodIndex = dInsn->vB;
2598
2599 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2600 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2601 else
2602 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2603
2604 /* "this" is already left in r0 by genProcessArgs* */
2605
2606 /* r4PC = dalvikCallsite */
2607 loadConstant(cUnit, r4PC,
2608 (int) (cUnit->method->insns + mir->offset));
2609
2610 /* r1 = &retChainingCell */
2611 ArmLIR *addrRetChain = newLIR2(cUnit, THUMB_ADD_PC_REL,
2612 r1, 0);
2613 addrRetChain->generic.target = (LIR *) retChainingCell;
2614
2615 /* r2 = &predictedChainingCell */
2616 ArmLIR *predictedChainingCell =
2617 newLIR2(cUnit, THUMB_ADD_PC_REL, r2, 0);
2618 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2619
2620 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2621
2622 /* return through lr - jump to the chaining cell */
2623 genUnconditionalBranch(cUnit, predChainingCell);
2624
2625 /*
2626 * null-check on "this" may have been eliminated, but we still need
2627 * a PC-reconstruction label for stack overflow bailout.
2628 */
2629 if (pcrLabel == NULL) {
2630 int dPC = (int) (cUnit->method->insns + mir->offset);
2631 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
2632 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
2633 pcrLabel->operands[0] = dPC;
2634 pcrLabel->operands[1] = mir->offset;
2635 /* Insert the place holder to the growable list */
2636 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2637 }
2638
2639 /* return through lr+2 - punt to the interpreter */
2640 genUnconditionalBranch(cUnit, pcrLabel);
2641
2642 /*
2643 * return through lr+4 - fully resolve the callee method.
2644 * r1 <- count
2645 * r2 <- &predictedChainCell
2646 * r3 <- this->class
2647 * r4 <- dPC
2648 * r7 <- this->class->vtable
2649 */
2650
2651 /* Save count, &predictedChainCell, and class to high regs first */
2652 newLIR2(cUnit, THUMB_MOV_RR_L2H, r9 & THUMB_REG_MASK, r1);
2653 newLIR2(cUnit, THUMB_MOV_RR_L2H, r10 & THUMB_REG_MASK, r2);
2654 newLIR2(cUnit, THUMB_MOV_RR_L2H, r12 & THUMB_REG_MASK, r3);
2655
2656 /* r0 now contains this->clazz */
2657 newLIR2(cUnit, THUMB_MOV_RR, r0, r3);
2658
2659 /* r1 = BBBB */
2660 loadConstant(cUnit, r1, dInsn->vB);
2661
2662 /* r2 = method (caller) */
2663 loadConstant(cUnit, r2, (int) cUnit->method);
2664
2665 /* r3 = pDvmDex */
2666 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
2667
2668 loadConstant(cUnit, r7,
2669 (intptr_t) dvmFindInterfaceMethodInCache);
2670 newLIR1(cUnit, THUMB_BLX_R, r7);
2671
2672 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
2673
2674 newLIR2(cUnit, THUMB_MOV_RR_H2L, r1, r9 & THUMB_REG_MASK);
2675
2676 /* Check if rechain limit is reached */
2677 newLIR2(cUnit, THUMB_CMP_RI8, r1, 0);
2678
2679 ArmLIR *bypassRechaining =
2680 newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_GT);
2681
2682 newLIR3(cUnit, THUMB_LDR_RRI5, r7, rGLUE,
2683 offsetof(InterpState,
2684 jitToInterpEntries.dvmJitToPatchPredictedChain)
2685 >> 2);
2686
2687 newLIR2(cUnit, THUMB_MOV_RR_H2L, r2, r10 & THUMB_REG_MASK);
2688 newLIR2(cUnit, THUMB_MOV_RR_H2L, r3, r12 & THUMB_REG_MASK);
2689
2690 /*
2691 * r0 = calleeMethod
2692 * r2 = &predictedChainingCell
2693 * r3 = class
2694 *
2695 * &returnChainingCell has been loaded into r1 but is not needed
2696 * when patching the chaining cell and will be clobbered upon
2697 * returning so it will be reconstructed again.
2698 */
2699 newLIR1(cUnit, THUMB_BLX_R, r7);
2700
2701 /* r1 = &retChainingCell */
2702 addrRetChain = newLIR3(cUnit, THUMB_ADD_PC_REL,
2703 r1, 0, 0);
2704 addrRetChain->generic.target = (LIR *) retChainingCell;
2705
2706 bypassRechaining->generic.target = (LIR *) addrRetChain;
2707
2708 /*
2709 * r0 = this, r1 = calleeMethod,
2710 * r1 = &ChainingCell,
2711 * r4PC = callsiteDPC,
2712 */
2713 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2714 #if defined(INVOKE_STATS)
2715 gDvmJit.invokePredictedChain++;
2716 #endif
2717 /* Handle exceptions using the interpreter */
2718 genTrap(cUnit, mir->offset, pcrLabel);
2719 break;
2720 }
2721 /* NOP */
2722 case OP_INVOKE_DIRECT_EMPTY: {
2723 return false;
2724 }
2725 case OP_FILLED_NEW_ARRAY:
2726 case OP_FILLED_NEW_ARRAY_RANGE: {
2727 /* Just let the interpreter deal with these */
2728 genInterpSingleStep(cUnit, mir);
2729 break;
2730 }
2731 default:
2732 return true;
2733 }
2734 return false;
2735 }
2736
handleFmt35ms_3rms(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)2737 static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
2738 BasicBlock *bb, ArmLIR *labelList)
2739 {
2740 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
2741 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2742 ArmLIR *pcrLabel = NULL;
2743
2744 DecodedInstruction *dInsn = &mir->dalvikInsn;
2745 switch (mir->dalvikInsn.opCode) {
2746 /* calleeMethod = this->clazz->vtable[BBBB] */
2747 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
2748 case OP_INVOKE_VIRTUAL_QUICK: {
2749 int methodIndex = dInsn->vB;
2750 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
2751 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2752 else
2753 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2754
2755 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2756 retChainingCell,
2757 predChainingCell,
2758 pcrLabel);
2759 break;
2760 }
2761 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2762 case OP_INVOKE_SUPER_QUICK:
2763 case OP_INVOKE_SUPER_QUICK_RANGE: {
2764 const Method *calleeMethod =
2765 cUnit->method->clazz->super->vtable[dInsn->vB];
2766
2767 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
2768 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2769 else
2770 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2771
2772 /* r0 = calleeMethod */
2773 loadConstant(cUnit, r0, (int) calleeMethod);
2774
2775 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2776 calleeMethod);
2777 /* Handle exceptions using the interpreter */
2778 genTrap(cUnit, mir->offset, pcrLabel);
2779 break;
2780 }
2781 default:
2782 return true;
2783 }
2784 return false;
2785 }
2786
2787 /*
2788 * NOTE: We assume here that the special native inline routines
2789 * are side-effect free. By making this assumption, we can safely
2790 * re-execute the routine from the interpreter if it decides it
2791 * wants to throw an exception. We still need to EXPORT_PC(), though.
2792 */
handleFmt3inline(CompilationUnit * cUnit,MIR * mir)2793 static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
2794 {
2795 DecodedInstruction *dInsn = &mir->dalvikInsn;
2796 switch( mir->dalvikInsn.opCode) {
2797 case OP_EXECUTE_INLINE: {
2798 unsigned int i;
2799 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
2800 int offset = offsetof(InterpState, retval);
2801 int operation = dInsn->vB;
2802
2803 switch (operation) {
2804 case INLINE_EMPTYINLINEMETHOD:
2805 return false; /* Nop */
2806 case INLINE_STRING_LENGTH:
2807 return genInlinedStringLength(cUnit, mir);
2808 case INLINE_MATH_ABS_INT:
2809 return genInlinedAbsInt(cUnit, mir);
2810 case INLINE_MATH_ABS_LONG:
2811 return genInlinedAbsLong(cUnit, mir);
2812 case INLINE_MATH_MIN_INT:
2813 return genInlinedMinMaxInt(cUnit, mir, true);
2814 case INLINE_MATH_MAX_INT:
2815 return genInlinedMinMaxInt(cUnit, mir, false);
2816 case INLINE_STRING_CHARAT:
2817 return genInlinedStringCharAt(cUnit, mir);
2818 case INLINE_MATH_SQRT:
2819 if (genInlineSqrt(cUnit, mir))
2820 return false;
2821 else
2822 break; /* Handle with C routine */
2823 case INLINE_MATH_COS:
2824 if (genInlineCos(cUnit, mir))
2825 return false;
2826 else
2827 break; /* Handle with C routine */
2828 case INLINE_MATH_SIN:
2829 if (genInlineSin(cUnit, mir))
2830 return false;
2831 else
2832 break; /* Handle with C routine */
2833 case INLINE_MATH_ABS_FLOAT:
2834 return genInlinedAbsFloat(cUnit, mir);
2835 case INLINE_MATH_ABS_DOUBLE:
2836 return genInlinedAbsDouble(cUnit, mir);
2837 case INLINE_STRING_COMPARETO:
2838 case INLINE_STRING_EQUALS:
2839 break;
2840 default:
2841 dvmAbort();
2842 }
2843
2844 /* Materialize pointer to retval & push */
2845 newLIR2(cUnit, THUMB_MOV_RR, r4PC, rGLUE);
2846 newLIR2(cUnit, THUMB_ADD_RI8, r4PC, offset);
2847 /* Push r4 and (just to take up space) r5) */
2848 newLIR1(cUnit, THUMB_PUSH, (1<<r4PC | 1<<rFP));
2849
2850 /* Get code pointer to inline routine */
2851 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
2852
2853 /* Export PC */
2854 genExportPC(cUnit, mir, r0, r1 );
2855
2856 /* Load arguments to r0 through r3 as applicable */
2857 for (i=0; i < dInsn->vA; i++) {
2858 loadValue(cUnit, dInsn->arg[i], i);
2859 }
2860 /* Call inline routine */
2861 newLIR1(cUnit, THUMB_BLX_R, r4PC);
2862
2863 /* Strip frame */
2864 newLIR1(cUnit, THUMB_ADD_SPI7, 2);
2865
2866 /* Did we throw? If so, redo under interpreter*/
2867 genZeroCheck(cUnit, r0, mir->offset, NULL);
2868
2869 resetRegisterScoreboard(cUnit);
2870 break;
2871 }
2872 default:
2873 return true;
2874 }
2875 return false;
2876 }
2877
handleFmt51l(CompilationUnit * cUnit,MIR * mir)2878 static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
2879 {
2880 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
2881 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
2882 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2883 return false;
2884 }
2885
2886 /*****************************************************************************/
2887 /*
2888 * The following are special processing routines that handle transfer of
2889 * controls between compiled code and the interpreter. Certain VM states like
2890 * Dalvik PC and special-purpose registers are reconstructed here.
2891 */
2892
2893 /* Chaining cell for code that may need warmup. */
handleNormalChainingCell(CompilationUnit * cUnit,unsigned int offset)2894 static void handleNormalChainingCell(CompilationUnit *cUnit,
2895 unsigned int offset)
2896 {
2897 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
2898 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
2899 newLIR1(cUnit, THUMB_BLX_R, r0);
2900 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
2901 }
2902
2903 /*
2904 * Chaining cell for instructions that immediately following already translated
2905 * code.
2906 */
handleHotChainingCell(CompilationUnit * cUnit,unsigned int offset)2907 static void handleHotChainingCell(CompilationUnit *cUnit,
2908 unsigned int offset)
2909 {
2910 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
2911 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
2912 newLIR1(cUnit, THUMB_BLX_R, r0);
2913 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
2914 }
2915
2916 /* Chaining cell for monomorphic method invocations. */
handleInvokeSingletonChainingCell(CompilationUnit * cUnit,const Method * callee)2917 static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
2918 const Method *callee)
2919 {
2920 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
2921 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
2922 newLIR1(cUnit, THUMB_BLX_R, r0);
2923 addWordData(cUnit, (int) (callee->insns), true);
2924 }
2925
2926 /* Chaining cell for monomorphic method invocations. */
handleInvokePredictedChainingCell(CompilationUnit * cUnit)2927 static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
2928 {
2929
2930 /* Should not be executed in the initial state */
2931 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
2932 /* To be filled: class */
2933 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
2934 /* To be filled: method */
2935 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
2936 /*
2937 * Rechain count. The initial value of 0 here will trigger chaining upon
2938 * the first invocation of this callsite.
2939 */
2940 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
2941 }
2942
2943 /* Load the Dalvik PC into r0 and jump to the specified target */
handlePCReconstruction(CompilationUnit * cUnit,ArmLIR * targetLabel)2944 static void handlePCReconstruction(CompilationUnit *cUnit,
2945 ArmLIR *targetLabel)
2946 {
2947 ArmLIR **pcrLabel =
2948 (ArmLIR **) cUnit->pcReconstructionList.elemList;
2949 int numElems = cUnit->pcReconstructionList.numUsed;
2950 int i;
2951 for (i = 0; i < numElems; i++) {
2952 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
2953 /* r0 = dalvik PC */
2954 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
2955 genUnconditionalBranch(cUnit, targetLabel);
2956 }
2957 }
2958
2959 /* Entry function to invoke the backend of the JIT compiler */
dvmCompilerMIR2LIR(CompilationUnit * cUnit)2960 void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
2961 {
2962 /* Used to hold the labels of each block */
2963 ArmLIR *labelList =
2964 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2965 GrowableList chainingListByType[CHAINING_CELL_LAST];
2966 int i;
2967
2968 /*
2969 * Initialize various types chaining lists.
2970 */
2971 for (i = 0; i < CHAINING_CELL_LAST; i++) {
2972 dvmInitGrowableList(&chainingListByType[i], 2);
2973 }
2974
2975 BasicBlock **blockList = cUnit->blockList;
2976
2977 if (cUnit->executionCount) {
2978 /*
2979 * Reserve 6 bytes at the beginning of the trace
2980 * +----------------------------+
2981 * | execution count (4 bytes) |
2982 * +----------------------------+
2983 * | chain cell offset (2 bytes)|
2984 * +----------------------------+
2985 * ...and then code to increment the execution
2986 * count:
2987 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
2988 * sub r0, #10 @ back up to addr of executionCount
2989 * ldr r1, [r0]
2990 * add r1, #1
2991 * str r1, [r0]
2992 */
2993 newLIR1(cUnit, ARM_16BIT_DATA, 0);
2994 newLIR1(cUnit, ARM_16BIT_DATA, 0);
2995 cUnit->chainCellOffsetLIR =
2996 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
2997 cUnit->headerSize = 6;
2998 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc & THUMB_REG_MASK);
2999 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3000 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3001 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3002 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
3003 } else {
3004 /* Just reserve 2 bytes for the chain cell offset */
3005 cUnit->chainCellOffsetLIR =
3006 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
3007 cUnit->headerSize = 2;
3008 }
3009
3010 /* Handle the content in each basic block */
3011 for (i = 0; i < cUnit->numBlocks; i++) {
3012 blockList[i]->visited = true;
3013 MIR *mir;
3014
3015 labelList[i].operands[0] = blockList[i]->startOffset;
3016
3017 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3018 /*
3019 * Append the label pseudo LIR first. Chaining cells will be handled
3020 * separately afterwards.
3021 */
3022 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3023 }
3024
3025 if (blockList[i]->blockType == DALVIK_BYTECODE) {
3026 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
3027 /* Reset the register state */
3028 resetRegisterScoreboard(cUnit);
3029 } else {
3030 switch (blockList[i]->blockType) {
3031 case CHAINING_CELL_NORMAL:
3032 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
3033 /* handle the codegen later */
3034 dvmInsertGrowableList(
3035 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
3036 break;
3037 case CHAINING_CELL_INVOKE_SINGLETON:
3038 labelList[i].opCode =
3039 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
3040 labelList[i].operands[0] =
3041 (int) blockList[i]->containingMethod;
3042 /* handle the codegen later */
3043 dvmInsertGrowableList(
3044 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3045 (void *) i);
3046 break;
3047 case CHAINING_CELL_INVOKE_PREDICTED:
3048 labelList[i].opCode =
3049 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
3050 /* handle the codegen later */
3051 dvmInsertGrowableList(
3052 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3053 (void *) i);
3054 break;
3055 case CHAINING_CELL_HOT:
3056 labelList[i].opCode =
3057 ARM_PSEUDO_CHAINING_CELL_HOT;
3058 /* handle the codegen later */
3059 dvmInsertGrowableList(
3060 &chainingListByType[CHAINING_CELL_HOT],
3061 (void *) i);
3062 break;
3063 case PC_RECONSTRUCTION:
3064 /* Make sure exception handling block is next */
3065 labelList[i].opCode =
3066 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
3067 assert (i == cUnit->numBlocks - 2);
3068 handlePCReconstruction(cUnit, &labelList[i+1]);
3069 break;
3070 case EXCEPTION_HANDLING:
3071 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
3072 if (cUnit->pcReconstructionList.numUsed) {
3073 newLIR3(cUnit, THUMB_LDR_RRI5, r1, rGLUE,
3074 offsetof(InterpState,
3075 jitToInterpEntries.dvmJitToInterpPunt)
3076 >> 2);
3077 newLIR1(cUnit, THUMB_BLX_R, r1);
3078 }
3079 break;
3080 default:
3081 break;
3082 }
3083 continue;
3084 }
3085
3086 ArmLIR *headLIR = NULL;
3087
3088 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
3089 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3090 InstructionFormat dalvikFormat =
3091 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
3092 ArmLIR *boundaryLIR =
3093 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
3094 mir->offset,dalvikOpCode);
3095 /* Remember the first LIR for this block */
3096 if (headLIR == NULL) {
3097 headLIR = boundaryLIR;
3098 }
3099 bool notHandled;
3100 /*
3101 * Debugging: screen the opcode first to see if it is in the
3102 * do[-not]-compile list
3103 */
3104 bool singleStepMe =
3105 gDvmJit.includeSelectedOp !=
3106 ((gDvmJit.opList[dalvikOpCode >> 3] &
3107 (1 << (dalvikOpCode & 0x7))) !=
3108 0);
3109 if (singleStepMe || cUnit->allSingleStep) {
3110 notHandled = false;
3111 genInterpSingleStep(cUnit, mir);
3112 } else {
3113 opcodeCoverage[dalvikOpCode]++;
3114 switch (dalvikFormat) {
3115 case kFmt10t:
3116 case kFmt20t:
3117 case kFmt30t:
3118 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3119 mir, blockList[i], labelList);
3120 break;
3121 case kFmt10x:
3122 notHandled = handleFmt10x(cUnit, mir);
3123 break;
3124 case kFmt11n:
3125 case kFmt31i:
3126 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3127 break;
3128 case kFmt11x:
3129 notHandled = handleFmt11x(cUnit, mir);
3130 break;
3131 case kFmt12x:
3132 notHandled = handleFmt12x(cUnit, mir);
3133 break;
3134 case kFmt20bc:
3135 notHandled = handleFmt20bc(cUnit, mir);
3136 break;
3137 case kFmt21c:
3138 case kFmt31c:
3139 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3140 break;
3141 case kFmt21h:
3142 notHandled = handleFmt21h(cUnit, mir);
3143 break;
3144 case kFmt21s:
3145 notHandled = handleFmt21s(cUnit, mir);
3146 break;
3147 case kFmt21t:
3148 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3149 labelList);
3150 break;
3151 case kFmt22b:
3152 case kFmt22s:
3153 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3154 break;
3155 case kFmt22c:
3156 notHandled = handleFmt22c(cUnit, mir);
3157 break;
3158 case kFmt22cs:
3159 notHandled = handleFmt22cs(cUnit, mir);
3160 break;
3161 case kFmt22t:
3162 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3163 labelList);
3164 break;
3165 case kFmt22x:
3166 case kFmt32x:
3167 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3168 break;
3169 case kFmt23x:
3170 notHandled = handleFmt23x(cUnit, mir);
3171 break;
3172 case kFmt31t:
3173 notHandled = handleFmt31t(cUnit, mir);
3174 break;
3175 case kFmt3rc:
3176 case kFmt35c:
3177 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3178 labelList);
3179 break;
3180 case kFmt3rms:
3181 case kFmt35ms:
3182 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3183 labelList);
3184 break;
3185 case kFmt3inline:
3186 notHandled = handleFmt3inline(cUnit, mir);
3187 break;
3188 case kFmt51l:
3189 notHandled = handleFmt51l(cUnit, mir);
3190 break;
3191 default:
3192 notHandled = true;
3193 break;
3194 }
3195 }
3196 if (notHandled) {
3197 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3198 mir->offset,
3199 dalvikOpCode, getOpcodeName(dalvikOpCode),
3200 dalvikFormat);
3201 dvmAbort();
3202 break;
3203 }
3204 }
3205 /* Eliminate redundant loads/stores and delay stores into later slots */
3206 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3207 cUnit->lastLIRInsn);
3208 /*
3209 * Check if the block is terminated due to trace length constraint -
3210 * insert an unconditional branch to the chaining cell.
3211 */
3212 if (blockList[i]->needFallThroughBranch) {
3213 genUnconditionalBranch(cUnit,
3214 &labelList[blockList[i]->fallThrough->id]);
3215 }
3216
3217 }
3218
3219 /* Handle the chaining cells in predefined order */
3220 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3221 size_t j;
3222 int *blockIdList = (int *) chainingListByType[i].elemList;
3223
3224 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3225
3226 /* No chaining cells of this type */
3227 if (cUnit->numChainingCells[i] == 0)
3228 continue;
3229
3230 /* Record the first LIR for a new type of chaining cell */
3231 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3232
3233 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3234 int blockId = blockIdList[j];
3235
3236 /* Align this chaining cell first */
3237 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
3238
3239 /* Insert the pseudo chaining instruction */
3240 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3241
3242
3243 switch (blockList[blockId]->blockType) {
3244 case CHAINING_CELL_NORMAL:
3245 handleNormalChainingCell(cUnit,
3246 blockList[blockId]->startOffset);
3247 break;
3248 case CHAINING_CELL_INVOKE_SINGLETON:
3249 handleInvokeSingletonChainingCell(cUnit,
3250 blockList[blockId]->containingMethod);
3251 break;
3252 case CHAINING_CELL_INVOKE_PREDICTED:
3253 handleInvokePredictedChainingCell(cUnit);
3254 break;
3255 case CHAINING_CELL_HOT:
3256 handleHotChainingCell(cUnit,
3257 blockList[blockId]->startOffset);
3258 break;
3259 default:
3260 dvmAbort();
3261 break;
3262 }
3263 }
3264 }
3265
3266 dvmCompilerApplyGlobalOptimizations(cUnit);
3267 }
3268
3269 /* Accept the work and start compiling */
dvmCompilerDoWork(CompilerWorkOrder * work)3270 bool dvmCompilerDoWork(CompilerWorkOrder *work)
3271 {
3272 bool res;
3273
3274 if (gDvmJit.codeCacheFull) {
3275 return false;
3276 }
3277
3278 switch (work->kind) {
3279 case kWorkOrderMethod:
3280 res = dvmCompileMethod(work->info, &work->result);
3281 break;
3282 case kWorkOrderTrace:
3283 /* Start compilation with maximally allowed trace length */
3284 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
3285 break;
3286 default:
3287 res = false;
3288 dvmAbort();
3289 }
3290 return res;
3291 }
3292
3293 /* Architectural-specific debugging helpers go here */
dvmCompilerArchDump(void)3294 void dvmCompilerArchDump(void)
3295 {
3296 /* Print compiled opcode in this VM instance */
3297 int i, start, streak;
3298 char buf[1024];
3299
3300 streak = i = 0;
3301 buf[0] = 0;
3302 while (opcodeCoverage[i] == 0 && i < 256) {
3303 i++;
3304 }
3305 if (i == 256) {
3306 return;
3307 }
3308 for (start = i++, streak = 1; i < 256; i++) {
3309 if (opcodeCoverage[i]) {
3310 streak++;
3311 } else {
3312 if (streak == 1) {
3313 sprintf(buf+strlen(buf), "%x,", start);
3314 } else {
3315 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3316 }
3317 streak = 0;
3318 while (opcodeCoverage[i] == 0 && i < 256) {
3319 i++;
3320 }
3321 if (i < 256) {
3322 streak = 1;
3323 start = i;
3324 }
3325 }
3326 }
3327 if (streak) {
3328 if (streak == 1) {
3329 sprintf(buf+strlen(buf), "%x", start);
3330 } else {
3331 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3332 }
3333 }
3334 if (strlen(buf)) {
3335 LOGD("dalvik.vm.jit.op = %s", buf);
3336 }
3337 }
3338