• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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