• 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  * Mark garbage collection card. Skip if the value we're storing is null.
29  */
markCard(CompilationUnit * cUnit,int valReg,int tgtAddrReg)30 static void markCard(CompilationUnit *cUnit, int valReg, int tgtAddrReg)
31 {
32     int regCardBase = dvmCompilerAllocTemp(cUnit);
33     int regCardNo = dvmCompilerAllocTemp(cUnit);
34     opRegImm(cUnit, kOpCmp, valReg, 0); /* storing null? */
35     ArmLIR *branchOver = opCondBranch(cUnit, kArmCondEq);
36     loadWordDisp(cUnit, rGLUE, offsetof(InterpState, cardTable),
37                  regCardBase);
38     opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
39     storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
40                      kUnsignedByte);
41     ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
42     target->defMask = ENCODE_ALL;
43     branchOver->generic.target = (LIR *)target;
44     dvmCompilerFreeTemp(cUnit, regCardBase);
45     dvmCompilerFreeTemp(cUnit, regCardNo);
46 }
47 
genConversionCall(CompilationUnit * cUnit,MIR * mir,void * funct,int srcSize,int tgtSize)48 static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
49                                      int srcSize, int tgtSize)
50 {
51     /*
52      * Don't optimize the register usage since it calls out to template
53      * functions
54      */
55     RegLocation rlSrc;
56     RegLocation rlDest;
57     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
58     if (srcSize == 1) {
59         rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
60         loadValueDirectFixed(cUnit, rlSrc, r0);
61     } else {
62         rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
63         loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
64     }
65     LOAD_FUNC_ADDR(cUnit, r2, (int)funct);
66     opReg(cUnit, kOpBlx, r2);
67     dvmCompilerClobberCallRegs(cUnit);
68     if (tgtSize == 1) {
69         RegLocation rlResult;
70         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
71         rlResult = dvmCompilerGetReturn(cUnit);
72         storeValue(cUnit, rlDest, rlResult);
73     } else {
74         RegLocation rlResult;
75         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
76         rlResult = dvmCompilerGetReturnWide(cUnit);
77         storeValueWide(cUnit, rlDest, rlResult);
78     }
79     return false;
80 }
81 
genArithOpFloatPortable(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlSrc2)82 static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
83                                     RegLocation rlDest, RegLocation rlSrc1,
84                                     RegLocation rlSrc2)
85 {
86     RegLocation rlResult;
87     void* funct;
88 
89     switch (mir->dalvikInsn.opCode) {
90         case OP_ADD_FLOAT_2ADDR:
91         case OP_ADD_FLOAT:
92             funct = (void*) __aeabi_fadd;
93             break;
94         case OP_SUB_FLOAT_2ADDR:
95         case OP_SUB_FLOAT:
96             funct = (void*) __aeabi_fsub;
97             break;
98         case OP_DIV_FLOAT_2ADDR:
99         case OP_DIV_FLOAT:
100             funct = (void*) __aeabi_fdiv;
101             break;
102         case OP_MUL_FLOAT_2ADDR:
103         case OP_MUL_FLOAT:
104             funct = (void*) __aeabi_fmul;
105             break;
106         case OP_REM_FLOAT_2ADDR:
107         case OP_REM_FLOAT:
108             funct = (void*) fmodf;
109             break;
110         case OP_NEG_FLOAT: {
111             genNegFloat(cUnit, rlDest, rlSrc1);
112             return false;
113         }
114         default:
115             return true;
116     }
117     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
118     loadValueDirectFixed(cUnit, rlSrc1, r0);
119     loadValueDirectFixed(cUnit, rlSrc2, r1);
120     LOAD_FUNC_ADDR(cUnit, r2, (int)funct);
121     opReg(cUnit, kOpBlx, r2);
122     dvmCompilerClobberCallRegs(cUnit);
123     rlResult = dvmCompilerGetReturn(cUnit);
124     storeValue(cUnit, rlDest, rlResult);
125     return false;
126 }
127 
genArithOpDoublePortable(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlSrc2)128 static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
129                                      RegLocation rlDest, RegLocation rlSrc1,
130                                      RegLocation rlSrc2)
131 {
132     RegLocation rlResult;
133     void* funct;
134 
135     switch (mir->dalvikInsn.opCode) {
136         case OP_ADD_DOUBLE_2ADDR:
137         case OP_ADD_DOUBLE:
138             funct = (void*) __aeabi_dadd;
139             break;
140         case OP_SUB_DOUBLE_2ADDR:
141         case OP_SUB_DOUBLE:
142             funct = (void*) __aeabi_dsub;
143             break;
144         case OP_DIV_DOUBLE_2ADDR:
145         case OP_DIV_DOUBLE:
146             funct = (void*) __aeabi_ddiv;
147             break;
148         case OP_MUL_DOUBLE_2ADDR:
149         case OP_MUL_DOUBLE:
150             funct = (void*) __aeabi_dmul;
151             break;
152         case OP_REM_DOUBLE_2ADDR:
153         case OP_REM_DOUBLE:
154             funct = (void*) fmod;
155             break;
156         case OP_NEG_DOUBLE: {
157             genNegDouble(cUnit, rlDest, rlSrc1);
158             return false;
159         }
160         default:
161             return true;
162     }
163     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
164     LOAD_FUNC_ADDR(cUnit, rlr, (int)funct);
165     loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
166     loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
167     opReg(cUnit, kOpBlx, rlr);
168     dvmCompilerClobberCallRegs(cUnit);
169     rlResult = dvmCompilerGetReturnWide(cUnit);
170     storeValueWide(cUnit, rlDest, rlResult);
171     return false;
172 }
173 
genConversionPortable(CompilationUnit * cUnit,MIR * mir)174 static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
175 {
176     OpCode opCode = mir->dalvikInsn.opCode;
177 
178     switch (opCode) {
179         case OP_INT_TO_FLOAT:
180             return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
181         case OP_FLOAT_TO_INT:
182             return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
183         case OP_DOUBLE_TO_FLOAT:
184             return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
185         case OP_FLOAT_TO_DOUBLE:
186             return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
187         case OP_INT_TO_DOUBLE:
188             return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
189         case OP_DOUBLE_TO_INT:
190             return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
191         case OP_FLOAT_TO_LONG:
192             return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
193         case OP_LONG_TO_FLOAT:
194             return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
195         case OP_DOUBLE_TO_LONG:
196             return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
197         case OP_LONG_TO_DOUBLE:
198             return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
199         default:
200             return true;
201     }
202     return false;
203 }
204 
205 #if defined(WITH_SELF_VERIFICATION)
selfVerificationBranchInsert(LIR * currentLIR,ArmOpCode opCode,int dest,int src1)206 static void selfVerificationBranchInsert(LIR *currentLIR, ArmOpCode opCode,
207                           int dest, int src1)
208 {
209      ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
210      insn->opCode = opCode;
211      insn->operands[0] = dest;
212      insn->operands[1] = src1;
213      setupResourceMasks(insn);
214      dvmCompilerInsertLIRBefore(currentLIR, (LIR *) insn);
215 }
216 
selfVerificationBranchInsertPass(CompilationUnit * cUnit)217 static void selfVerificationBranchInsertPass(CompilationUnit *cUnit)
218 {
219     ArmLIR *thisLIR;
220     TemplateOpCode opCode = TEMPLATE_MEM_OP_DECODE;
221 
222     for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn;
223          thisLIR != (ArmLIR *) cUnit->lastLIRInsn;
224          thisLIR = NEXT_LIR(thisLIR)) {
225         if (thisLIR->branchInsertSV) {
226             /* Branch to mem op decode template */
227             selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx1,
228                        (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
229                        (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
230             selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx2,
231                        (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
232                        (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
233         }
234     }
235 }
236 #endif
237 
238 /* Generate conditional branch instructions */
genConditionalBranch(CompilationUnit * cUnit,ArmConditionCode cond,ArmLIR * target)239 static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
240                                     ArmConditionCode cond,
241                                     ArmLIR *target)
242 {
243     ArmLIR *branch = opCondBranch(cUnit, cond);
244     branch->generic.target = (LIR *) target;
245     return branch;
246 }
247 
248 /* Generate a unconditional branch to go to the interpreter */
genTrap(CompilationUnit * cUnit,int dOffset,ArmLIR * pcrLabel)249 static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
250                                   ArmLIR *pcrLabel)
251 {
252     ArmLIR *branch = opNone(cUnit, kOpUncondBr);
253     return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
254 }
255 
256 /* Load a wide field from an object instance */
genIGetWide(CompilationUnit * cUnit,MIR * mir,int fieldOffset)257 static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
258 {
259     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
260     RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
261     RegLocation rlResult;
262     rlObj = loadValue(cUnit, rlObj, kCoreReg);
263     int regPtr = dvmCompilerAllocTemp(cUnit);
264 
265     assert(rlDest.wide);
266 
267     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
268                  NULL);/* null object? */
269     opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
270     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
271 
272     HEAP_ACCESS_SHADOW(true);
273     loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
274     HEAP_ACCESS_SHADOW(false);
275 
276     dvmCompilerFreeTemp(cUnit, regPtr);
277     storeValueWide(cUnit, rlDest, rlResult);
278 }
279 
280 /* Store a wide field to an object instance */
genIPutWide(CompilationUnit * cUnit,MIR * mir,int fieldOffset)281 static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
282 {
283     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
284     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 2);
285     rlObj = loadValue(cUnit, rlObj, kCoreReg);
286     int regPtr;
287     rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
288     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
289                  NULL);/* null object? */
290     regPtr = dvmCompilerAllocTemp(cUnit);
291     opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
292 
293     HEAP_ACCESS_SHADOW(true);
294     storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
295     HEAP_ACCESS_SHADOW(false);
296 
297     dvmCompilerFreeTemp(cUnit, regPtr);
298 }
299 
300 /*
301  * Load a field from an object instance
302  *
303  */
genIGet(CompilationUnit * cUnit,MIR * mir,OpSize size,int fieldOffset,bool isVolatile)304 static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
305                     int fieldOffset, bool isVolatile)
306 {
307     RegLocation rlResult;
308     RegisterClass regClass = dvmCompilerRegClassBySize(size);
309     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
310     RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
311     rlObj = loadValue(cUnit, rlObj, kCoreReg);
312     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
313     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
314                  NULL);/* null object? */
315 
316     HEAP_ACCESS_SHADOW(true);
317     loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
318                  size, rlObj.sRegLow);
319     HEAP_ACCESS_SHADOW(false);
320     if (isVolatile) {
321         dvmCompilerGenMemBarrier(cUnit);
322     }
323 
324     storeValue(cUnit, rlDest, rlResult);
325 }
326 
327 /*
328  * Store a field to an object instance
329  *
330  */
genIPut(CompilationUnit * cUnit,MIR * mir,OpSize size,int fieldOffset,bool isObject,bool isVolatile)331 static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
332                     int fieldOffset, bool isObject, bool isVolatile)
333 {
334     RegisterClass regClass = dvmCompilerRegClassBySize(size);
335     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
336     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 1);
337     rlObj = loadValue(cUnit, rlObj, kCoreReg);
338     rlSrc = loadValue(cUnit, rlSrc, regClass);
339     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
340                  NULL);/* null object? */
341 
342     if (isVolatile) {
343         dvmCompilerGenMemBarrier(cUnit);
344     }
345     HEAP_ACCESS_SHADOW(true);
346     storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
347     HEAP_ACCESS_SHADOW(false);
348     if (isObject) {
349         /* NOTE: marking card based on object head */
350         markCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
351     }
352 }
353 
354 
355 /*
356  * Generate array load
357  */
genArrayGet(CompilationUnit * cUnit,MIR * mir,OpSize size,RegLocation rlArray,RegLocation rlIndex,RegLocation rlDest,int scale)358 static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
359                         RegLocation rlArray, RegLocation rlIndex,
360                         RegLocation rlDest, int scale)
361 {
362     RegisterClass regClass = dvmCompilerRegClassBySize(size);
363     int lenOffset = offsetof(ArrayObject, length);
364     int dataOffset = offsetof(ArrayObject, contents);
365     RegLocation rlResult;
366     rlArray = loadValue(cUnit, rlArray, kCoreReg);
367     rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
368     int regPtr;
369 
370     /* null object? */
371     ArmLIR * pcrLabel = NULL;
372 
373     if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
374         pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
375                                 rlArray.lowReg, mir->offset, NULL);
376     }
377 
378     regPtr = dvmCompilerAllocTemp(cUnit);
379 
380     if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
381         int regLen = dvmCompilerAllocTemp(cUnit);
382         /* Get len */
383         loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
384         /* regPtr -> array data */
385         opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
386         genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
387                        pcrLabel);
388         dvmCompilerFreeTemp(cUnit, regLen);
389     } else {
390         /* regPtr -> array data */
391         opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
392     }
393     if ((size == kLong) || (size == kDouble)) {
394         if (scale) {
395             int rNewIndex = dvmCompilerAllocTemp(cUnit);
396             opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
397             opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
398             dvmCompilerFreeTemp(cUnit, rNewIndex);
399         } else {
400             opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
401         }
402         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
403 
404         HEAP_ACCESS_SHADOW(true);
405         loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
406         HEAP_ACCESS_SHADOW(false);
407 
408         dvmCompilerFreeTemp(cUnit, regPtr);
409         storeValueWide(cUnit, rlDest, rlResult);
410     } else {
411         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
412 
413         HEAP_ACCESS_SHADOW(true);
414         loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
415                         scale, size);
416         HEAP_ACCESS_SHADOW(false);
417 
418         dvmCompilerFreeTemp(cUnit, regPtr);
419         storeValue(cUnit, rlDest, rlResult);
420     }
421 }
422 
423 /*
424  * Generate array store
425  *
426  */
genArrayPut(CompilationUnit * cUnit,MIR * mir,OpSize size,RegLocation rlArray,RegLocation rlIndex,RegLocation rlSrc,int scale)427 static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
428                         RegLocation rlArray, RegLocation rlIndex,
429                         RegLocation rlSrc, int scale)
430 {
431     RegisterClass regClass = dvmCompilerRegClassBySize(size);
432     int lenOffset = offsetof(ArrayObject, length);
433     int dataOffset = offsetof(ArrayObject, contents);
434 
435     int regPtr;
436     rlArray = loadValue(cUnit, rlArray, kCoreReg);
437     rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
438 
439     if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) {
440         dvmCompilerClobber(cUnit, rlArray.lowReg);
441         regPtr = rlArray.lowReg;
442     } else {
443         regPtr = dvmCompilerAllocTemp(cUnit);
444         genRegCopy(cUnit, regPtr, rlArray.lowReg);
445     }
446 
447     /* null object? */
448     ArmLIR * pcrLabel = NULL;
449 
450     if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
451         pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
452                                 mir->offset, NULL);
453     }
454 
455     if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
456         int regLen = dvmCompilerAllocTemp(cUnit);
457         //NOTE: max live temps(4) here.
458         /* Get len */
459         loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
460         /* regPtr -> array data */
461         opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
462         genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
463                        pcrLabel);
464         dvmCompilerFreeTemp(cUnit, regLen);
465     } else {
466         /* regPtr -> array data */
467         opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
468     }
469     /* at this point, regPtr points to array, 2 live temps */
470     if ((size == kLong) || (size == kDouble)) {
471         //TODO: need specific wide routine that can handle fp regs
472         if (scale) {
473             int rNewIndex = dvmCompilerAllocTemp(cUnit);
474             opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
475             opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
476             dvmCompilerFreeTemp(cUnit, rNewIndex);
477         } else {
478             opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
479         }
480         rlSrc = loadValueWide(cUnit, rlSrc, regClass);
481 
482         HEAP_ACCESS_SHADOW(true);
483         storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
484         HEAP_ACCESS_SHADOW(false);
485 
486         dvmCompilerFreeTemp(cUnit, regPtr);
487     } else {
488         rlSrc = loadValue(cUnit, rlSrc, regClass);
489 
490         HEAP_ACCESS_SHADOW(true);
491         storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
492                          scale, size);
493         HEAP_ACCESS_SHADOW(false);
494     }
495 }
496 
497 /*
498  * Generate array object store
499  * Must use explicit register allocation here because of
500  * call-out to dvmCanPutArrayElement
501  */
genArrayObjectPut(CompilationUnit * cUnit,MIR * mir,RegLocation rlArray,RegLocation rlIndex,RegLocation rlSrc,int scale)502 static void genArrayObjectPut(CompilationUnit *cUnit, MIR *mir,
503                               RegLocation rlArray, RegLocation rlIndex,
504                               RegLocation rlSrc, int scale)
505 {
506     int lenOffset = offsetof(ArrayObject, length);
507     int dataOffset = offsetof(ArrayObject, contents);
508 
509     dvmCompilerFlushAllRegs(cUnit);
510 
511     int regLen = r0;
512     int regPtr = r4PC;  /* Preserved across call */
513     int regArray = r1;
514     int regIndex = r7;  /* Preserved across call */
515 
516     loadValueDirectFixed(cUnit, rlArray, regArray);
517     loadValueDirectFixed(cUnit, rlIndex, regIndex);
518 
519     /* null object? */
520     ArmLIR * pcrLabel = NULL;
521 
522     if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
523         pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, regArray,
524                                 mir->offset, NULL);
525     }
526 
527     if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
528         /* Get len */
529         loadWordDisp(cUnit, regArray, lenOffset, regLen);
530         /* regPtr -> array data */
531         opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset);
532         genBoundsCheck(cUnit, regIndex, regLen, mir->offset,
533                        pcrLabel);
534     } else {
535         /* regPtr -> array data */
536         opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset);
537     }
538 
539     /* Get object to store */
540     loadValueDirectFixed(cUnit, rlSrc, r0);
541     LOAD_FUNC_ADDR(cUnit, r2, (int)dvmCanPutArrayElement);
542 
543     /* Are we storing null?  If so, avoid check */
544     opRegImm(cUnit, kOpCmp, r0, 0);
545     ArmLIR *branchOver = opCondBranch(cUnit, kArmCondEq);
546 
547     /* Make sure the types are compatible */
548     loadWordDisp(cUnit, regArray, offsetof(Object, clazz), r1);
549     loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
550     opReg(cUnit, kOpBlx, r2);
551     dvmCompilerClobberCallRegs(cUnit);
552 
553     /*
554      * Using fixed registers here, and counting on r4 and r7 being
555      * preserved across the above call.  Tell the register allocation
556      * utilities about the regs we are using directly
557      */
558     dvmCompilerLockTemp(cUnit, regPtr);   // r4PC
559     dvmCompilerLockTemp(cUnit, regIndex); // r7
560     dvmCompilerLockTemp(cUnit, r0);
561     dvmCompilerLockTemp(cUnit, r1);
562 
563     /* Bad? - roll back and re-execute if so */
564     genRegImmCheck(cUnit, kArmCondEq, r0, 0, mir->offset, pcrLabel);
565 
566     /* Resume here - must reload element & array, regPtr & index preserved */
567     loadValueDirectFixed(cUnit, rlSrc, r0);
568     loadValueDirectFixed(cUnit, rlArray, r1);
569 
570     ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
571     target->defMask = ENCODE_ALL;
572     branchOver->generic.target = (LIR *) target;
573 
574     HEAP_ACCESS_SHADOW(true);
575     storeBaseIndexed(cUnit, regPtr, regIndex, r0,
576                      scale, kWord);
577     HEAP_ACCESS_SHADOW(false);
578 
579     dvmCompilerFreeTemp(cUnit, regPtr);
580     dvmCompilerFreeTemp(cUnit, regIndex);
581 
582     /* NOTE: marking card here based on object head */
583     markCard(cUnit, r0, r1);
584 }
585 
genShiftOpLong(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlShift)586 static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
587                            RegLocation rlDest, RegLocation rlSrc1,
588                            RegLocation rlShift)
589 {
590     /*
591      * Don't mess with the regsiters here as there is a particular calling
592      * convention to the out-of-line handler.
593      */
594     RegLocation rlResult;
595 
596     loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
597     loadValueDirect(cUnit, rlShift, r2);
598     switch( mir->dalvikInsn.opCode) {
599         case OP_SHL_LONG:
600         case OP_SHL_LONG_2ADDR:
601             genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
602             break;
603         case OP_SHR_LONG:
604         case OP_SHR_LONG_2ADDR:
605             genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
606             break;
607         case OP_USHR_LONG:
608         case OP_USHR_LONG_2ADDR:
609             genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
610             break;
611         default:
612             return true;
613     }
614     rlResult = dvmCompilerGetReturnWide(cUnit);
615     storeValueWide(cUnit, rlDest, rlResult);
616     return false;
617 }
618 
genArithOpLong(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlSrc2)619 static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir,
620                            RegLocation rlDest, RegLocation rlSrc1,
621                            RegLocation rlSrc2)
622 {
623     RegLocation rlResult;
624     OpKind firstOp = kOpBkpt;
625     OpKind secondOp = kOpBkpt;
626     bool callOut = false;
627     void *callTgt;
628     int retReg = r0;
629 
630     switch (mir->dalvikInsn.opCode) {
631         case OP_NOT_LONG:
632             rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
633             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
634             opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
635             opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
636             storeValueWide(cUnit, rlDest, rlResult);
637             return false;
638             break;
639         case OP_ADD_LONG:
640         case OP_ADD_LONG_2ADDR:
641             firstOp = kOpAdd;
642             secondOp = kOpAdc;
643             break;
644         case OP_SUB_LONG:
645         case OP_SUB_LONG_2ADDR:
646             firstOp = kOpSub;
647             secondOp = kOpSbc;
648             break;
649         case OP_MUL_LONG:
650         case OP_MUL_LONG_2ADDR:
651             genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
652             return false;
653         case OP_DIV_LONG:
654         case OP_DIV_LONG_2ADDR:
655             callOut = true;
656             retReg = r0;
657             callTgt = (void*)__aeabi_ldivmod;
658             break;
659         /* NOTE - result is in r2/r3 instead of r0/r1 */
660         case OP_REM_LONG:
661         case OP_REM_LONG_2ADDR:
662             callOut = true;
663             callTgt = (void*)__aeabi_ldivmod;
664             retReg = r2;
665             break;
666         case OP_AND_LONG_2ADDR:
667         case OP_AND_LONG:
668             firstOp = kOpAnd;
669             secondOp = kOpAnd;
670             break;
671         case OP_OR_LONG:
672         case OP_OR_LONG_2ADDR:
673             firstOp = kOpOr;
674             secondOp = kOpOr;
675             break;
676         case OP_XOR_LONG:
677         case OP_XOR_LONG_2ADDR:
678             firstOp = kOpXor;
679             secondOp = kOpXor;
680             break;
681         case OP_NEG_LONG: {
682             //TUNING: can improve this using Thumb2 code
683             int tReg = dvmCompilerAllocTemp(cUnit);
684             rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
685             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
686             loadConstantNoClobber(cUnit, tReg, 0);
687             opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
688                         tReg, rlSrc2.lowReg);
689             opRegReg(cUnit, kOpSbc, tReg, rlSrc2.highReg);
690             genRegCopy(cUnit, rlResult.highReg, tReg);
691             storeValueWide(cUnit, rlDest, rlResult);
692             return false;
693         }
694         default:
695             LOGE("Invalid long arith op");
696             dvmCompilerAbort(cUnit);
697     }
698     if (!callOut) {
699         genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
700     } else {
701         // Adjust return regs in to handle case of rem returning r2/r3
702         dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
703         loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
704         LOAD_FUNC_ADDR(cUnit, rlr, (int) callTgt);
705         loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
706         opReg(cUnit, kOpBlx, rlr);
707         dvmCompilerClobberCallRegs(cUnit);
708         if (retReg == r0)
709             rlResult = dvmCompilerGetReturnWide(cUnit);
710         else
711             rlResult = dvmCompilerGetReturnWideAlt(cUnit);
712         storeValueWide(cUnit, rlDest, rlResult);
713     }
714     return false;
715 }
716 
genArithOpInt(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlSrc2)717 static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir,
718                           RegLocation rlDest, RegLocation rlSrc1,
719                           RegLocation rlSrc2)
720 {
721     OpKind op = kOpBkpt;
722     bool callOut = false;
723     bool checkZero = false;
724     bool unary = false;
725     int retReg = r0;
726     void *callTgt;
727     RegLocation rlResult;
728     bool shiftOp = false;
729 
730     switch (mir->dalvikInsn.opCode) {
731         case OP_NEG_INT:
732             op = kOpNeg;
733             unary = true;
734             break;
735         case OP_NOT_INT:
736             op = kOpMvn;
737             unary = true;
738             break;
739         case OP_ADD_INT:
740         case OP_ADD_INT_2ADDR:
741             op = kOpAdd;
742             break;
743         case OP_SUB_INT:
744         case OP_SUB_INT_2ADDR:
745             op = kOpSub;
746             break;
747         case OP_MUL_INT:
748         case OP_MUL_INT_2ADDR:
749             op = kOpMul;
750             break;
751         case OP_DIV_INT:
752         case OP_DIV_INT_2ADDR:
753             callOut = true;
754             checkZero = true;
755             callTgt = __aeabi_idiv;
756             retReg = r0;
757             break;
758         /* NOTE: returns in r1 */
759         case OP_REM_INT:
760         case OP_REM_INT_2ADDR:
761             callOut = true;
762             checkZero = true;
763             callTgt = __aeabi_idivmod;
764             retReg = r1;
765             break;
766         case OP_AND_INT:
767         case OP_AND_INT_2ADDR:
768             op = kOpAnd;
769             break;
770         case OP_OR_INT:
771         case OP_OR_INT_2ADDR:
772             op = kOpOr;
773             break;
774         case OP_XOR_INT:
775         case OP_XOR_INT_2ADDR:
776             op = kOpXor;
777             break;
778         case OP_SHL_INT:
779         case OP_SHL_INT_2ADDR:
780             shiftOp = true;
781             op = kOpLsl;
782             break;
783         case OP_SHR_INT:
784         case OP_SHR_INT_2ADDR:
785             shiftOp = true;
786             op = kOpAsr;
787             break;
788         case OP_USHR_INT:
789         case OP_USHR_INT_2ADDR:
790             shiftOp = true;
791             op = kOpLsr;
792             break;
793         default:
794             LOGE("Invalid word arith op: 0x%x(%d)",
795                  mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
796             dvmCompilerAbort(cUnit);
797     }
798     if (!callOut) {
799         rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
800         if (unary) {
801             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
802             opRegReg(cUnit, op, rlResult.lowReg,
803                      rlSrc1.lowReg);
804         } else {
805             rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
806             if (shiftOp) {
807                 int tReg = dvmCompilerAllocTemp(cUnit);
808                 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
809                 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
810                 opRegRegReg(cUnit, op, rlResult.lowReg,
811                             rlSrc1.lowReg, tReg);
812                 dvmCompilerFreeTemp(cUnit, tReg);
813             } else {
814                 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
815                 opRegRegReg(cUnit, op, rlResult.lowReg,
816                             rlSrc1.lowReg, rlSrc2.lowReg);
817             }
818         }
819         storeValue(cUnit, rlDest, rlResult);
820     } else {
821         RegLocation rlResult;
822         dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
823         loadValueDirectFixed(cUnit, rlSrc2, r1);
824         LOAD_FUNC_ADDR(cUnit, r2, (int) callTgt);
825         loadValueDirectFixed(cUnit, rlSrc1, r0);
826         if (checkZero) {
827             genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
828         }
829         opReg(cUnit, kOpBlx, r2);
830         dvmCompilerClobberCallRegs(cUnit);
831         if (retReg == r0)
832             rlResult = dvmCompilerGetReturn(cUnit);
833         else
834             rlResult = dvmCompilerGetReturnAlt(cUnit);
835         storeValue(cUnit, rlDest, rlResult);
836     }
837     return false;
838 }
839 
genArithOp(CompilationUnit * cUnit,MIR * mir)840 static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
841 {
842     OpCode opCode = mir->dalvikInsn.opCode;
843     RegLocation rlDest;
844     RegLocation rlSrc1;
845     RegLocation rlSrc2;
846     /* Deduce sizes of operands */
847     if (mir->ssaRep->numUses == 2) {
848         rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
849         rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
850     } else if (mir->ssaRep->numUses == 3) {
851         rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
852         rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
853     } else {
854         rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
855         rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
856         assert(mir->ssaRep->numUses == 4);
857     }
858     if (mir->ssaRep->numDefs == 1) {
859         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
860     } else {
861         assert(mir->ssaRep->numDefs == 2);
862         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
863     }
864 
865     if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
866         return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
867     }
868     if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
869         return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
870     }
871     if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
872         return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
873     }
874     if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
875         return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
876     }
877     if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
878         return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
879     }
880     if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
881         return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
882     }
883     if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
884         return genArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
885     }
886     if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
887         return genArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
888     }
889     if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
890         return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
891     }
892     if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
893         return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
894     }
895     return true;
896 }
897 
898 /* Generate unconditional branch instructions */
genUnconditionalBranch(CompilationUnit * cUnit,ArmLIR * target)899 static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
900 {
901     ArmLIR *branch = opNone(cUnit, kOpUncondBr);
902     branch->generic.target = (LIR *) target;
903     return branch;
904 }
905 
906 /* Perform the actual operation for OP_RETURN_* */
genReturnCommon(CompilationUnit * cUnit,MIR * mir)907 static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
908 {
909     genDispatchToHandler(cUnit, TEMPLATE_RETURN);
910 #if defined(WITH_JIT_TUNING)
911     gDvmJit.returnOp++;
912 #endif
913     int dPC = (int) (cUnit->method->insns + mir->offset);
914     /* Insert branch, but defer setting of target */
915     ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
916     /* Set up the place holder to reconstruct this Dalvik PC */
917     ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
918     pcrLabel->opCode = kArmPseudoPCReconstructionCell;
919     pcrLabel->operands[0] = dPC;
920     pcrLabel->operands[1] = mir->offset;
921     /* Insert the place holder to the growable list */
922     dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
923     /* Branch to the PC reconstruction code */
924     branch->generic.target = (LIR *) pcrLabel;
925 }
926 
genProcessArgsNoRange(CompilationUnit * cUnit,MIR * mir,DecodedInstruction * dInsn,ArmLIR ** pcrLabel)927 static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
928                                   DecodedInstruction *dInsn,
929                                   ArmLIR **pcrLabel)
930 {
931     unsigned int i;
932     unsigned int regMask = 0;
933     RegLocation rlArg;
934     int numDone = 0;
935 
936     /*
937      * Load arguments to r0..r4.  Note that these registers may contain
938      * live values, so we clobber them immediately after loading to prevent
939      * them from being used as sources for subsequent loads.
940      */
941     dvmCompilerLockAllTemps(cUnit);
942     for (i = 0; i < dInsn->vA; i++) {
943         regMask |= 1 << i;
944         rlArg = dvmCompilerGetSrc(cUnit, mir, numDone++);
945         loadValueDirectFixed(cUnit, rlArg, i);
946     }
947     if (regMask) {
948         /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
949         opRegRegImm(cUnit, kOpSub, r7, rFP,
950                     sizeof(StackSaveArea) + (dInsn->vA << 2));
951         /* generate null check */
952         if (pcrLabel) {
953             *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0,
954                                      mir->offset, NULL);
955         }
956         storeMultiple(cUnit, r7, regMask);
957     }
958 }
959 
genProcessArgsRange(CompilationUnit * cUnit,MIR * mir,DecodedInstruction * dInsn,ArmLIR ** pcrLabel)960 static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
961                                 DecodedInstruction *dInsn,
962                                 ArmLIR **pcrLabel)
963 {
964     int srcOffset = dInsn->vC << 2;
965     int numArgs = dInsn->vA;
966     int regMask;
967 
968     /*
969      * Note: here, all promoted registers will have been flushed
970      * back to the Dalvik base locations, so register usage restrictins
971      * are lifted.  All parms loaded from original Dalvik register
972      * region - even though some might conceivably have valid copies
973      * cached in a preserved register.
974      */
975     dvmCompilerLockAllTemps(cUnit);
976 
977     /*
978      * r4PC     : &rFP[vC]
979      * r7: &newFP[0]
980      */
981     opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
982     /* load [r0 .. min(numArgs,4)] */
983     regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
984     /*
985      * Protect the loadMultiple instruction from being reordered with other
986      * Dalvik stack accesses.
987      */
988     loadMultiple(cUnit, r4PC, regMask);
989 
990     opRegRegImm(cUnit, kOpSub, r7, rFP,
991                 sizeof(StackSaveArea) + (numArgs << 2));
992     /* generate null check */
993     if (pcrLabel) {
994         *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0,
995                                  mir->offset, NULL);
996     }
997 
998     /*
999      * Handle remaining 4n arguments:
1000      * store previously loaded 4 values and load the next 4 values
1001      */
1002     if (numArgs >= 8) {
1003         ArmLIR *loopLabel = NULL;
1004         /*
1005          * r0 contains "this" and it will be used later, so push it to the stack
1006          * first. Pushing r5 (rFP) is just for stack alignment purposes.
1007          */
1008         opImm(cUnit, kOpPush, (1 << r0 | 1 << rFP));
1009         /* No need to generate the loop structure if numArgs <= 11 */
1010         if (numArgs > 11) {
1011             loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
1012             loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
1013             loopLabel->defMask = ENCODE_ALL;
1014         }
1015         storeMultiple(cUnit, r7, regMask);
1016         /*
1017          * Protect the loadMultiple instruction from being reordered with other
1018          * Dalvik stack accesses.
1019          */
1020         loadMultiple(cUnit, r4PC, regMask);
1021         /* No need to generate the loop structure if numArgs <= 11 */
1022         if (numArgs > 11) {
1023             opRegImm(cUnit, kOpSub, rFP, 4);
1024             genConditionalBranch(cUnit, kArmCondNe, loopLabel);
1025         }
1026     }
1027 
1028     /* Save the last batch of loaded values */
1029     storeMultiple(cUnit, r7, regMask);
1030 
1031     /* Generate the loop epilogue - don't use r0 */
1032     if ((numArgs > 4) && (numArgs % 4)) {
1033         regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
1034         /*
1035          * Protect the loadMultiple instruction from being reordered with other
1036          * Dalvik stack accesses.
1037          */
1038         loadMultiple(cUnit, r4PC, regMask);
1039     }
1040     if (numArgs >= 8)
1041         opImm(cUnit, kOpPop, (1 << r0 | 1 << rFP));
1042 
1043     /* Save the modulo 4 arguments */
1044     if ((numArgs > 4) && (numArgs % 4)) {
1045         storeMultiple(cUnit, r7, regMask);
1046     }
1047 }
1048 
1049 /*
1050  * Generate code to setup the call stack then jump to the chaining cell if it
1051  * is not a native method.
1052  */
genInvokeSingletonCommon(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList,ArmLIR * pcrLabel,const Method * calleeMethod)1053 static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
1054                                      BasicBlock *bb, ArmLIR *labelList,
1055                                      ArmLIR *pcrLabel,
1056                                      const Method *calleeMethod)
1057 {
1058     /*
1059      * Note: all Dalvik register state should be flushed to
1060      * memory by the point, so register usage restrictions no
1061      * longer apply.  All temp & preserved registers may be used.
1062      */
1063     dvmCompilerLockAllTemps(cUnit);
1064     ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
1065 
1066     /* r1 = &retChainingCell */
1067     dvmCompilerLockTemp(cUnit, r1);
1068     ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
1069     /* r4PC = dalvikCallsite */
1070     loadConstant(cUnit, r4PC,
1071                  (int) (cUnit->method->insns + mir->offset));
1072     addrRetChain->generic.target = (LIR *) retChainingCell;
1073     /*
1074      * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
1075      * r1 = &ChainingCell
1076      * r4PC = callsiteDPC
1077      */
1078     if (dvmIsNativeMethod(calleeMethod)) {
1079         genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
1080 #if defined(WITH_JIT_TUNING)
1081         gDvmJit.invokeNative++;
1082 #endif
1083     } else {
1084         genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1085 #if defined(WITH_JIT_TUNING)
1086         gDvmJit.invokeMonomorphic++;
1087 #endif
1088         /* Branch to the chaining cell */
1089         genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1090     }
1091     /* Handle exceptions using the interpreter */
1092     genTrap(cUnit, mir->offset, pcrLabel);
1093 }
1094 
1095 /*
1096  * Generate code to check the validity of a predicted chain and take actions
1097  * based on the result.
1098  *
1099  * 0x426a99aa : ldr     r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1100  * 0x426a99ac : add     r1, pc, #32   --> r1 <- &retChainingCell
1101  * 0x426a99ae : add     r2, pc, #40   --> r2 <- &predictedChainingCell
1102  * 0x426a99b0 : blx_1   0x426a918c    --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1103  * 0x426a99b2 : blx_2   see above     --+
1104  * 0x426a99b4 : b       0x426a99d8    --> off to the predicted chain
1105  * 0x426a99b6 : b       0x426a99c8    --> punt to the interpreter
1106  * 0x426a99b8 : ldr     r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1107  * 0x426a99ba : cmp     r1, #0        --> compare r1 (rechain count) against 0
1108  * 0x426a99bc : bgt     0x426a99c2    --> >=0? don't rechain
1109  * 0x426a99be : ldr     r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1110  * 0x426a99c0 : blx     r7            --+
1111  * 0x426a99c2 : add     r1, pc, #12   --> r1 <- &retChainingCell
1112  * 0x426a99c4 : blx_1   0x426a9098    --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1113  * 0x426a99c6 : blx_2   see above     --+
1114  */
genInvokeVirtualCommon(CompilationUnit * cUnit,MIR * mir,int methodIndex,ArmLIR * retChainingCell,ArmLIR * predChainingCell,ArmLIR * pcrLabel)1115 static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1116                                    int methodIndex,
1117                                    ArmLIR *retChainingCell,
1118                                    ArmLIR *predChainingCell,
1119                                    ArmLIR *pcrLabel)
1120 {
1121     /*
1122      * Note: all Dalvik register state should be flushed to
1123      * memory by the point, so register usage restrictions no
1124      * longer apply.  Lock temps to prevent them from being
1125      * allocated by utility routines.
1126      */
1127     dvmCompilerLockAllTemps(cUnit);
1128 
1129     /* "this" is already left in r0 by genProcessArgs* */
1130 
1131     /* r4PC = dalvikCallsite */
1132     loadConstant(cUnit, r4PC,
1133                  (int) (cUnit->method->insns + mir->offset));
1134 
1135     /* r1 = &retChainingCell */
1136     ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
1137     addrRetChain->generic.target = (LIR *) retChainingCell;
1138 
1139     /* r2 = &predictedChainingCell */
1140     ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
1141     predictedChainingCell->generic.target = (LIR *) predChainingCell;
1142 
1143     genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1144 
1145     /* return through lr - jump to the chaining cell */
1146     genUnconditionalBranch(cUnit, predChainingCell);
1147 
1148     /*
1149      * null-check on "this" may have been eliminated, but we still need a PC-
1150      * reconstruction label for stack overflow bailout.
1151      */
1152     if (pcrLabel == NULL) {
1153         int dPC = (int) (cUnit->method->insns + mir->offset);
1154         pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1155         pcrLabel->opCode = kArmPseudoPCReconstructionCell;
1156         pcrLabel->operands[0] = dPC;
1157         pcrLabel->operands[1] = mir->offset;
1158         /* Insert the place holder to the growable list */
1159         dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1160     }
1161 
1162     /* return through lr+2 - punt to the interpreter */
1163     genUnconditionalBranch(cUnit, pcrLabel);
1164 
1165     /*
1166      * return through lr+4 - fully resolve the callee method.
1167      * r1 <- count
1168      * r2 <- &predictedChainCell
1169      * r3 <- this->class
1170      * r4 <- dPC
1171      * r7 <- this->class->vtable
1172      */
1173 
1174     /* r0 <- calleeMethod */
1175     loadWordDisp(cUnit, r7, methodIndex * 4, r0);
1176 
1177     /* Check if rechain limit is reached */
1178     opRegImm(cUnit, kOpCmp, r1, 0);
1179 
1180     ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
1181 
1182     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1183                  jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
1184 
1185     genRegCopy(cUnit, r1, rGLUE);
1186 
1187     /*
1188      * r0 = calleeMethod
1189      * r2 = &predictedChainingCell
1190      * r3 = class
1191      *
1192      * &returnChainingCell has been loaded into r1 but is not needed
1193      * when patching the chaining cell and will be clobbered upon
1194      * returning so it will be reconstructed again.
1195      */
1196     opReg(cUnit, kOpBlx, r7);
1197 
1198     /* r1 = &retChainingCell */
1199     addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
1200     addrRetChain->generic.target = (LIR *) retChainingCell;
1201 
1202     bypassRechaining->generic.target = (LIR *) addrRetChain;
1203     /*
1204      * r0 = calleeMethod,
1205      * r1 = &ChainingCell,
1206      * r4PC = callsiteDPC,
1207      */
1208     genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1209 #if defined(WITH_JIT_TUNING)
1210     gDvmJit.invokePolymorphic++;
1211 #endif
1212     /* Handle exceptions using the interpreter */
1213     genTrap(cUnit, mir->offset, pcrLabel);
1214 }
1215 
1216 /* Geneate a branch to go back to the interpreter */
genPuntToInterp(CompilationUnit * cUnit,unsigned int offset)1217 static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1218 {
1219     /* r0 = dalvik pc */
1220     dvmCompilerFlushAllRegs(cUnit);
1221     loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
1222     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1223                  jitToInterpEntries.dvmJitToInterpPunt), r1);
1224     opReg(cUnit, kOpBlx, r1);
1225 }
1226 
1227 /*
1228  * Attempt to single step one instruction using the interpreter and return
1229  * to the compiled code for the next Dalvik instruction
1230  */
genInterpSingleStep(CompilationUnit * cUnit,MIR * mir)1231 static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1232 {
1233     int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1234     int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1235                        kInstrCanThrow;
1236 
1237     //If already optimized out, just ignore
1238     if (mir->dalvikInsn.opCode == OP_NOP)
1239         return;
1240 
1241     //Ugly, but necessary.  Flush all Dalvik regs so Interp can find them
1242     dvmCompilerFlushAllRegs(cUnit);
1243 
1244     if ((mir->next == NULL) || (flags & flagsToCheck)) {
1245        genPuntToInterp(cUnit, mir->offset);
1246        return;
1247     }
1248     int entryAddr = offsetof(InterpState,
1249                              jitToInterpEntries.dvmJitToInterpSingleStep);
1250     loadWordDisp(cUnit, rGLUE, entryAddr, r2);
1251     /* r0 = dalvik pc */
1252     loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1253     /* r1 = dalvik pc of following instruction */
1254     loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
1255     opReg(cUnit, kOpBlx, r2);
1256 }
1257 
1258 #if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING) || \
1259     defined(_ARMV5TE) || defined(_ARMV5TE_VFP)
1260 /*
1261  * To prevent a thread in a monitor wait from blocking the Jit from
1262  * resetting the code cache, heavyweight monitor lock will not
1263  * be allowed to return to an existing translation.  Instead, we will
1264  * handle them by branching to a handler, which will in turn call the
1265  * runtime lock routine and then branch directly back to the
1266  * interpreter main loop.  Given the high cost of the heavyweight
1267  * lock operation, this additional cost should be slight (especially when
1268  * considering that we expect the vast majority of lock operations to
1269  * use the fast-path thin lock bypass).
1270  */
genMonitorPortable(CompilationUnit * cUnit,MIR * mir)1271 static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir)
1272 {
1273     bool isEnter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
1274     genExportPC(cUnit, mir);
1275     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
1276     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1277     loadValueDirectFixed(cUnit, rlSrc, r1);
1278     loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
1279     genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
1280     if (isEnter) {
1281         /* Get dPC of next insn */
1282         loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset +
1283                  dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_ENTER)));
1284 #if defined(WITH_DEADLOCK_PREDICTION)
1285         genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER_DEBUG);
1286 #else
1287         genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER);
1288 #endif
1289     } else {
1290         LOAD_FUNC_ADDR(cUnit, r2, (int)dvmUnlockObject);
1291         /* Do the call */
1292         opReg(cUnit, kOpBlx, r2);
1293         opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */
1294         ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
1295         loadConstant(cUnit, r0,
1296                      (int) (cUnit->method->insns + mir->offset +
1297                      dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_EXIT)));
1298         genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1299         ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1300         target->defMask = ENCODE_ALL;
1301         branchOver->generic.target = (LIR *) target;
1302         dvmCompilerClobberCallRegs(cUnit);
1303     }
1304 }
1305 #endif
1306 
1307 /*
1308  * The following are the first-level codegen routines that analyze the format
1309  * of each bytecode then either dispatch special purpose codegen routines
1310  * or produce corresponding Thumb instructions directly.
1311  */
1312 
handleFmt10t_Fmt20t_Fmt30t(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)1313 static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
1314                                        BasicBlock *bb, ArmLIR *labelList)
1315 {
1316     /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1317     genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1318     return false;
1319 }
1320 
handleFmt10x(CompilationUnit * cUnit,MIR * mir)1321 static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1322 {
1323     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1324     if ((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) {
1325         LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1326         return true;
1327     }
1328     switch (dalvikOpCode) {
1329         case OP_RETURN_VOID:
1330             genReturnCommon(cUnit,mir);
1331             break;
1332         case OP_UNUSED_73:
1333         case OP_UNUSED_79:
1334         case OP_UNUSED_7A:
1335         case OP_UNUSED_F1:
1336         case OP_UNUSED_FF:
1337             LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1338             return true;
1339         case OP_NOP:
1340             break;
1341         default:
1342             return true;
1343     }
1344     return false;
1345 }
1346 
handleFmt11n_Fmt31i(CompilationUnit * cUnit,MIR * mir)1347 static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1348 {
1349     RegLocation rlDest;
1350     RegLocation rlResult;
1351     if (mir->ssaRep->numDefs == 2) {
1352         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1353     } else {
1354         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1355     }
1356 
1357     switch (mir->dalvikInsn.opCode) {
1358         case OP_CONST:
1359         case OP_CONST_4: {
1360             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1361             loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1362             storeValue(cUnit, rlDest, rlResult);
1363             break;
1364         }
1365         case OP_CONST_WIDE_32: {
1366             //TUNING: single routine to load constant pair for support doubles
1367             //TUNING: load 0/-1 separately to avoid load dependency
1368             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1369             loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1370             opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1371                         rlResult.lowReg, 31);
1372             storeValueWide(cUnit, rlDest, rlResult);
1373             break;
1374         }
1375         default:
1376             return true;
1377     }
1378     return false;
1379 }
1380 
handleFmt21h(CompilationUnit * cUnit,MIR * mir)1381 static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1382 {
1383     RegLocation rlDest;
1384     RegLocation rlResult;
1385     if (mir->ssaRep->numDefs == 2) {
1386         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1387     } else {
1388         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1389     }
1390     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1391 
1392     switch (mir->dalvikInsn.opCode) {
1393         case OP_CONST_HIGH16: {
1394             loadConstantNoClobber(cUnit, rlResult.lowReg,
1395                                   mir->dalvikInsn.vB << 16);
1396             storeValue(cUnit, rlDest, rlResult);
1397             break;
1398         }
1399         case OP_CONST_WIDE_HIGH16: {
1400             loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1401                                   0, mir->dalvikInsn.vB << 16);
1402             storeValueWide(cUnit, rlDest, rlResult);
1403             break;
1404         }
1405         default:
1406             return true;
1407     }
1408     return false;
1409 }
1410 
handleFmt20bc(CompilationUnit * cUnit,MIR * mir)1411 static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1412 {
1413     /* For OP_THROW_VERIFICATION_ERROR */
1414     genInterpSingleStep(cUnit, mir);
1415     return false;
1416 }
1417 
handleFmt21c_Fmt31c(CompilationUnit * cUnit,MIR * mir)1418 static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1419 {
1420     RegLocation rlResult;
1421     RegLocation rlDest;
1422     RegLocation rlSrc;
1423 
1424     switch (mir->dalvikInsn.opCode) {
1425         case OP_CONST_STRING_JUMBO:
1426         case OP_CONST_STRING: {
1427             void *strPtr = (void*)
1428               (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1429 
1430             if (strPtr == NULL) {
1431                 LOGE("Unexpected null string");
1432                 dvmAbort();
1433             }
1434 
1435             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1436             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1437             loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr );
1438             storeValue(cUnit, rlDest, rlResult);
1439             break;
1440         }
1441         case OP_CONST_CLASS: {
1442             void *classPtr = (void*)
1443               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1444 
1445             if (classPtr == NULL) {
1446                 LOGE("Unexpected null class");
1447                 dvmAbort();
1448             }
1449 
1450             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1451             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1452             loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr );
1453             storeValue(cUnit, rlDest, rlResult);
1454             break;
1455         }
1456         case OP_SGET_VOLATILE:
1457         case OP_SGET_OBJECT_VOLATILE:
1458         case OP_SGET_OBJECT:
1459         case OP_SGET_BOOLEAN:
1460         case OP_SGET_CHAR:
1461         case OP_SGET_BYTE:
1462         case OP_SGET_SHORT:
1463         case OP_SGET: {
1464             int valOffset = offsetof(StaticField, value);
1465             int tReg = dvmCompilerAllocTemp(cUnit);
1466             bool isVolatile;
1467             const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
1468                 mir->meta.calleeMethod : cUnit->method;
1469             void *fieldPtr = (void*)
1470               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1471 
1472             if (fieldPtr == NULL) {
1473                 LOGE("Unexpected null static field");
1474                 dvmAbort();
1475             }
1476 
1477             isVolatile = (mir->dalvikInsn.opCode == OP_SGET_VOLATILE) ||
1478                          (mir->dalvikInsn.opCode == OP_SGET_OBJECT_VOLATILE) ||
1479                          dvmIsVolatileField(fieldPtr);
1480 
1481             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1482             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1483             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
1484 
1485             if (isVolatile) {
1486                 dvmCompilerGenMemBarrier(cUnit);
1487             }
1488             HEAP_ACCESS_SHADOW(true);
1489             loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
1490             HEAP_ACCESS_SHADOW(false);
1491 
1492             storeValue(cUnit, rlDest, rlResult);
1493             break;
1494         }
1495         case OP_SGET_WIDE: {
1496             int valOffset = offsetof(StaticField, value);
1497             const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
1498                 mir->meta.calleeMethod : cUnit->method;
1499             void *fieldPtr = (void*)
1500               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1501 
1502             if (fieldPtr == NULL) {
1503                 LOGE("Unexpected null static field");
1504                 dvmAbort();
1505             }
1506 
1507             int tReg = dvmCompilerAllocTemp(cUnit);
1508             rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1509             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1510             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
1511 
1512             HEAP_ACCESS_SHADOW(true);
1513             loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
1514             HEAP_ACCESS_SHADOW(false);
1515 
1516             storeValueWide(cUnit, rlDest, rlResult);
1517             break;
1518         }
1519         case OP_SPUT_OBJECT:
1520         case OP_SPUT_OBJECT_VOLATILE:
1521         case OP_SPUT_VOLATILE:
1522         case OP_SPUT_BOOLEAN:
1523         case OP_SPUT_CHAR:
1524         case OP_SPUT_BYTE:
1525         case OP_SPUT_SHORT:
1526         case OP_SPUT: {
1527             int valOffset = offsetof(StaticField, value);
1528             int tReg = dvmCompilerAllocTemp(cUnit);
1529             int objHead;
1530             bool isVolatile;
1531             bool isSputObject;
1532             const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
1533                 mir->meta.calleeMethod : cUnit->method;
1534             void *fieldPtr = (void*)
1535               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1536 
1537             isVolatile = (mir->dalvikInsn.opCode == OP_SPUT_VOLATILE) ||
1538                          (mir->dalvikInsn.opCode == OP_SPUT_OBJECT_VOLATILE) ||
1539                          dvmIsVolatileField(fieldPtr);
1540 
1541             isSputObject = (mir->dalvikInsn.opCode == OP_SPUT_OBJECT) ||
1542                            (mir->dalvikInsn.opCode == OP_SPUT_OBJECT_VOLATILE);
1543 
1544             if (fieldPtr == NULL) {
1545                 LOGE("Unexpected null static field");
1546                 dvmAbort();
1547             }
1548 
1549             rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1550             rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1551             loadConstant(cUnit, tReg,  (int) fieldPtr);
1552             if (isSputObject) {
1553                 objHead = dvmCompilerAllocTemp(cUnit);
1554                 loadWordDisp(cUnit, tReg, offsetof(Field, clazz), objHead);
1555             }
1556             HEAP_ACCESS_SHADOW(true);
1557             storeWordDisp(cUnit, tReg, valOffset ,rlSrc.lowReg);
1558             dvmCompilerFreeTemp(cUnit, tReg);
1559             HEAP_ACCESS_SHADOW(false);
1560             if (isVolatile) {
1561                 dvmCompilerGenMemBarrier(cUnit);
1562             }
1563             if (isSputObject) {
1564                 /* NOTE: marking card based sfield->clazz */
1565                 markCard(cUnit, rlSrc.lowReg, objHead);
1566                 dvmCompilerFreeTemp(cUnit, objHead);
1567             }
1568 
1569             break;
1570         }
1571         case OP_SPUT_WIDE: {
1572             int tReg = dvmCompilerAllocTemp(cUnit);
1573             int valOffset = offsetof(StaticField, value);
1574             const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
1575                 mir->meta.calleeMethod : cUnit->method;
1576             void *fieldPtr = (void*)
1577               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1578 
1579             if (fieldPtr == NULL) {
1580                 LOGE("Unexpected null static field");
1581                 dvmAbort();
1582             }
1583 
1584             rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1585             rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1586             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
1587 
1588             HEAP_ACCESS_SHADOW(true);
1589             storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
1590             HEAP_ACCESS_SHADOW(false);
1591             break;
1592         }
1593         case OP_NEW_INSTANCE: {
1594             /*
1595              * Obey the calling convention and don't mess with the register
1596              * usage.
1597              */
1598             ClassObject *classPtr = (void*)
1599               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1600 
1601             if (classPtr == NULL) {
1602                 LOGE("Unexpected null class");
1603                 dvmAbort();
1604             }
1605 
1606             /*
1607              * If it is going to throw, it should not make to the trace to begin
1608              * with.  However, Alloc might throw, so we need to genExportPC()
1609              */
1610             assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
1611             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
1612             genExportPC(cUnit, mir);
1613             LOAD_FUNC_ADDR(cUnit, r2, (int)dvmAllocObject);
1614             loadConstant(cUnit, r0, (int) classPtr);
1615             loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
1616             opReg(cUnit, kOpBlx, r2);
1617             dvmCompilerClobberCallRegs(cUnit);
1618             /* generate a branch over if allocation is successful */
1619             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
1620             ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
1621             /*
1622              * OOM exception needs to be thrown here and cannot re-execute
1623              */
1624             loadConstant(cUnit, r0,
1625                          (int) (cUnit->method->insns + mir->offset));
1626             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1627             /* noreturn */
1628 
1629             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1630             target->defMask = ENCODE_ALL;
1631             branchOver->generic.target = (LIR *) target;
1632             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1633             rlResult = dvmCompilerGetReturn(cUnit);
1634             storeValue(cUnit, rlDest, rlResult);
1635             break;
1636         }
1637         case OP_CHECK_CAST: {
1638             /*
1639              * Obey the calling convention and don't mess with the register
1640              * usage.
1641              */
1642             ClassObject *classPtr =
1643               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1644             /*
1645              * Note: It is possible that classPtr is NULL at this point,
1646              * even though this instruction has been successfully interpreted.
1647              * If the previous interpretation had a null source, the
1648              * interpreter would not have bothered to resolve the clazz.
1649              * Bail out to the interpreter in this case, and log it
1650              * so that we can tell if it happens frequently.
1651              */
1652             if (classPtr == NULL) {
1653                  LOGVV("null clazz in OP_CHECK_CAST, single-stepping");
1654                  genInterpSingleStep(cUnit, mir);
1655                  return false;
1656             }
1657             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
1658             loadConstant(cUnit, r1, (int) classPtr );
1659             rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1660             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1661             opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);   /* Null? */
1662             ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
1663             /*
1664              *  rlSrc.lowReg now contains object->clazz.  Note that
1665              *  it could have been allocated r0, but we're okay so long
1666              *  as we don't do anything desctructive until r0 is loaded
1667              *  with clazz.
1668              */
1669             /* r0 now contains object->clazz */
1670             loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
1671             LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInstanceofNonTrivial);
1672             opRegReg(cUnit, kOpCmp, r0, r1);
1673             ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
1674             opReg(cUnit, kOpBlx, r2);
1675             dvmCompilerClobberCallRegs(cUnit);
1676             /*
1677              * If null, check cast failed - punt to the interpreter.  Because
1678              * interpreter will be the one throwing, we don't need to
1679              * genExportPC() here.
1680              */
1681             genZeroCheck(cUnit, r0, mir->offset, NULL);
1682             /* check cast passed - branch target here */
1683             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1684             target->defMask = ENCODE_ALL;
1685             branch1->generic.target = (LIR *)target;
1686             branch2->generic.target = (LIR *)target;
1687             break;
1688         }
1689         case OP_SGET_WIDE_VOLATILE:
1690         case OP_SPUT_WIDE_VOLATILE:
1691             genInterpSingleStep(cUnit, mir);
1692             break;
1693         default:
1694             return true;
1695     }
1696     return false;
1697 }
1698 
1699 /*
1700  * A typical example of inlined getter/setter from a monomorphic callsite:
1701  *
1702  * D/dalvikvm(  289): -------- dalvik offset: 0x0000 @ invoke-static (I)
1703  * D/dalvikvm(  289): -------- dalvik offset: 0x0000 @ sget-object (C) v0, ...
1704  * D/dalvikvm(  289): 0x4427fc22 (0002): ldr     r0, [pc, #56]
1705  * D/dalvikvm(  289): 0x4427fc24 (0004): ldr     r1, [r0, #0]
1706  * D/dalvikvm(  289): 0x4427fc26 (0006): str     r1, [r5, #0]
1707  * D/dalvikvm(  289): 0x4427fc28 (0008): .align4
1708  * D/dalvikvm(  289): L0x0003:
1709  * D/dalvikvm(  289): -------- dalvik offset: 0x0003 @ move-result-object (I) v0
1710  *
1711  * Note the invoke-static and move-result-object with the (I) notation are
1712  * turned into no-op.
1713  */
handleFmt11x(CompilationUnit * cUnit,MIR * mir)1714 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1715 {
1716     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1717     RegLocation rlResult;
1718     switch (dalvikOpCode) {
1719         case OP_MOVE_EXCEPTION: {
1720             int offset = offsetof(InterpState, self);
1721             int exOffset = offsetof(Thread, exception);
1722             int selfReg = dvmCompilerAllocTemp(cUnit);
1723             int resetReg = dvmCompilerAllocTemp(cUnit);
1724             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1725             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1726             loadWordDisp(cUnit, rGLUE, offset, selfReg);
1727             loadConstant(cUnit, resetReg, 0);
1728             loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg);
1729             storeWordDisp(cUnit, selfReg, exOffset, resetReg);
1730             storeValue(cUnit, rlDest, rlResult);
1731            break;
1732         }
1733         case OP_MOVE_RESULT:
1734         case OP_MOVE_RESULT_OBJECT: {
1735             /* An inlined move result is effectively no-op */
1736             if (mir->OptimizationFlags & MIR_INLINED)
1737                 break;
1738             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1739             RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
1740             rlSrc.fp = rlDest.fp;
1741             storeValue(cUnit, rlDest, rlSrc);
1742             break;
1743         }
1744         case OP_MOVE_RESULT_WIDE: {
1745             /* An inlined move result is effectively no-op */
1746             if (mir->OptimizationFlags & MIR_INLINED)
1747                 break;
1748             RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1749             RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
1750             rlSrc.fp = rlDest.fp;
1751             storeValueWide(cUnit, rlDest, rlSrc);
1752             break;
1753         }
1754         case OP_RETURN_WIDE: {
1755             RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1756             RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
1757             rlDest.fp = rlSrc.fp;
1758             storeValueWide(cUnit, rlDest, rlSrc);
1759             genReturnCommon(cUnit,mir);
1760             break;
1761         }
1762         case OP_RETURN:
1763         case OP_RETURN_OBJECT: {
1764             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1765             RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
1766             rlDest.fp = rlSrc.fp;
1767             storeValue(cUnit, rlDest, rlSrc);
1768             genReturnCommon(cUnit,mir);
1769             break;
1770         }
1771         case OP_MONITOR_EXIT:
1772         case OP_MONITOR_ENTER:
1773 #if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
1774             genMonitorPortable(cUnit, mir);
1775 #else
1776             genMonitor(cUnit, mir);
1777 #endif
1778             break;
1779         case OP_THROW: {
1780             genInterpSingleStep(cUnit, mir);
1781             break;
1782         }
1783         default:
1784             return true;
1785     }
1786     return false;
1787 }
1788 
handleFmt12x(CompilationUnit * cUnit,MIR * mir)1789 static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1790 {
1791     OpCode opCode = mir->dalvikInsn.opCode;
1792     RegLocation rlDest;
1793     RegLocation rlSrc;
1794     RegLocation rlResult;
1795 
1796     if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1797         return genArithOp( cUnit, mir );
1798     }
1799 
1800     if (mir->ssaRep->numUses == 2)
1801         rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1802     else
1803         rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1804     if (mir->ssaRep->numDefs == 2)
1805         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1806     else
1807         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1808 
1809     switch (opCode) {
1810         case OP_DOUBLE_TO_INT:
1811         case OP_INT_TO_FLOAT:
1812         case OP_FLOAT_TO_INT:
1813         case OP_DOUBLE_TO_FLOAT:
1814         case OP_FLOAT_TO_DOUBLE:
1815         case OP_INT_TO_DOUBLE:
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, rlDest, rlSrc, rlSrc);
1824         case OP_NEG_LONG:
1825         case OP_NOT_LONG:
1826             return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
1827         case OP_NEG_FLOAT:
1828             return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
1829         case OP_NEG_DOUBLE:
1830             return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
1831         case OP_MOVE_WIDE:
1832             storeValueWide(cUnit, rlDest, rlSrc);
1833             break;
1834         case OP_INT_TO_LONG:
1835             rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
1836             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1837             //TUNING: shouldn't loadValueDirect already check for phys reg?
1838             if (rlSrc.location == kLocPhysReg) {
1839                 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
1840             } else {
1841                 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
1842             }
1843             opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1844                         rlResult.lowReg, 31);
1845             storeValueWide(cUnit, rlDest, rlResult);
1846             break;
1847         case OP_LONG_TO_INT:
1848             rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
1849             rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc);
1850             // Intentional fallthrough
1851         case OP_MOVE:
1852         case OP_MOVE_OBJECT:
1853             storeValue(cUnit, rlDest, rlSrc);
1854             break;
1855         case OP_INT_TO_BYTE:
1856             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1857             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1858             opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
1859             storeValue(cUnit, rlDest, rlResult);
1860             break;
1861         case OP_INT_TO_SHORT:
1862             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1863             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1864             opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
1865             storeValue(cUnit, rlDest, rlResult);
1866             break;
1867         case OP_INT_TO_CHAR:
1868             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1869             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1870             opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
1871             storeValue(cUnit, rlDest, rlResult);
1872             break;
1873         case OP_ARRAY_LENGTH: {
1874             int lenOffset = offsetof(ArrayObject, length);
1875             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1876             genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
1877                          mir->offset, NULL);
1878             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1879             loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
1880                          rlResult.lowReg);
1881             storeValue(cUnit, rlDest, rlResult);
1882             break;
1883         }
1884         default:
1885             return true;
1886     }
1887     return false;
1888 }
1889 
handleFmt21s(CompilationUnit * cUnit,MIR * mir)1890 static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
1891 {
1892     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1893     RegLocation rlDest;
1894     RegLocation rlResult;
1895     int BBBB = mir->dalvikInsn.vB;
1896     if (dalvikOpCode == OP_CONST_WIDE_16) {
1897         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1898         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1899         loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
1900         //TUNING: do high separately to avoid load dependency
1901         opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1902         storeValueWide(cUnit, rlDest, rlResult);
1903     } else if (dalvikOpCode == OP_CONST_16) {
1904         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1905         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1906         loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
1907         storeValue(cUnit, rlDest, rlResult);
1908     } else
1909         return true;
1910     return false;
1911 }
1912 
1913 /* Compare agaist zero */
handleFmt21t(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)1914 static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
1915                          ArmLIR *labelList)
1916 {
1917     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1918     ArmConditionCode cond;
1919     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1920     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1921     opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
1922 
1923 //TUNING: break this out to allow use of Thumb2 CB[N]Z
1924     switch (dalvikOpCode) {
1925         case OP_IF_EQZ:
1926             cond = kArmCondEq;
1927             break;
1928         case OP_IF_NEZ:
1929             cond = kArmCondNe;
1930             break;
1931         case OP_IF_LTZ:
1932             cond = kArmCondLt;
1933             break;
1934         case OP_IF_GEZ:
1935             cond = kArmCondGe;
1936             break;
1937         case OP_IF_GTZ:
1938             cond = kArmCondGt;
1939             break;
1940         case OP_IF_LEZ:
1941             cond = kArmCondLe;
1942             break;
1943         default:
1944             cond = 0;
1945             LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
1946             dvmCompilerAbort(cUnit);
1947     }
1948     genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1949     /* This mostly likely will be optimized away in a later phase */
1950     genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1951     return false;
1952 }
1953 
isPowerOfTwo(int x)1954 static bool isPowerOfTwo(int x)
1955 {
1956     return (x & (x - 1)) == 0;
1957 }
1958 
1959 // Returns true if no more than two bits are set in 'x'.
isPopCountLE2(unsigned int x)1960 static bool isPopCountLE2(unsigned int x)
1961 {
1962     x &= x - 1;
1963     return (x & (x - 1)) == 0;
1964 }
1965 
1966 // Returns the index of the lowest set bit in 'x'.
lowestSetBit(unsigned int x)1967 static int lowestSetBit(unsigned int x) {
1968     int bit_posn = 0;
1969     while ((x & 0xf) == 0) {
1970         bit_posn += 4;
1971         x >>= 4;
1972     }
1973     while ((x & 1) == 0) {
1974         bit_posn++;
1975         x >>= 1;
1976     }
1977     return bit_posn;
1978 }
1979 
1980 // Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1981 // and store the result in 'rlDest'.
handleEasyDivide(CompilationUnit * cUnit,OpCode dalvikOpCode,RegLocation rlSrc,RegLocation rlDest,int lit)1982 static bool handleEasyDivide(CompilationUnit *cUnit, OpCode dalvikOpCode,
1983                              RegLocation rlSrc, RegLocation rlDest, int lit)
1984 {
1985     if (lit < 2 || !isPowerOfTwo(lit)) {
1986         return false;
1987     }
1988     int k = lowestSetBit(lit);
1989     if (k >= 30) {
1990         // Avoid special cases.
1991         return false;
1992     }
1993     bool div = (dalvikOpCode == OP_DIV_INT_LIT8 || dalvikOpCode == OP_DIV_INT_LIT16);
1994     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1995     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1996     if (div) {
1997         int tReg = dvmCompilerAllocTemp(cUnit);
1998         if (lit == 2) {
1999             // Division by 2 is by far the most common division by constant.
2000             opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
2001             opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
2002             opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
2003         } else {
2004             opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
2005             opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
2006             opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
2007             opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
2008         }
2009     } else {
2010         int cReg = dvmCompilerAllocTemp(cUnit);
2011         loadConstant(cUnit, cReg, lit - 1);
2012         int tReg1 = dvmCompilerAllocTemp(cUnit);
2013         int tReg2 = dvmCompilerAllocTemp(cUnit);
2014         if (lit == 2) {
2015             opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
2016             opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
2017             opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
2018             opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
2019         } else {
2020             opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
2021             opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
2022             opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
2023             opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
2024             opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
2025         }
2026     }
2027     storeValue(cUnit, rlDest, rlResult);
2028     return true;
2029 }
2030 
2031 // Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
2032 // and store the result in 'rlDest'.
handleEasyMultiply(CompilationUnit * cUnit,RegLocation rlSrc,RegLocation rlDest,int lit)2033 static bool handleEasyMultiply(CompilationUnit *cUnit,
2034                                RegLocation rlSrc, RegLocation rlDest, int lit)
2035 {
2036     // Can we simplify this multiplication?
2037     bool powerOfTwo = false;
2038     bool popCountLE2 = false;
2039     bool powerOfTwoMinusOne = false;
2040     if (lit < 2) {
2041         // Avoid special cases.
2042         return false;
2043     } else if (isPowerOfTwo(lit)) {
2044         powerOfTwo = true;
2045     } else if (isPopCountLE2(lit)) {
2046         popCountLE2 = true;
2047     } else if (isPowerOfTwo(lit + 1)) {
2048         powerOfTwoMinusOne = true;
2049     } else {
2050         return false;
2051     }
2052     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2053     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2054     if (powerOfTwo) {
2055         // Shift.
2056         opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
2057                     lowestSetBit(lit));
2058     } else if (popCountLE2) {
2059         // Shift and add and shift.
2060         int firstBit = lowestSetBit(lit);
2061         int secondBit = lowestSetBit(lit ^ (1 << firstBit));
2062         genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
2063                                       firstBit, secondBit);
2064     } else {
2065         // Reverse subtract: (src << (shift + 1)) - src.
2066         assert(powerOfTwoMinusOne);
2067         // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1)
2068         int tReg = dvmCompilerAllocTemp(cUnit);
2069         opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
2070         opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
2071     }
2072     storeValue(cUnit, rlDest, rlResult);
2073     return true;
2074 }
2075 
handleFmt22b_Fmt22s(CompilationUnit * cUnit,MIR * mir)2076 static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2077 {
2078     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2079     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2080     RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2081     RegLocation rlResult;
2082     int lit = mir->dalvikInsn.vC;
2083     OpKind op = 0;      /* Make gcc happy */
2084     int shiftOp = false;
2085     bool isDiv = false;
2086 
2087     switch (dalvikOpCode) {
2088         case OP_RSUB_INT_LIT8:
2089         case OP_RSUB_INT: {
2090             int tReg;
2091             //TUNING: add support for use of Arm rsub op
2092             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2093             tReg = dvmCompilerAllocTemp(cUnit);
2094             loadConstant(cUnit, tReg, lit);
2095             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2096             opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
2097                         tReg, rlSrc.lowReg);
2098             storeValue(cUnit, rlDest, rlResult);
2099             return false;
2100             break;
2101         }
2102 
2103         case OP_ADD_INT_LIT8:
2104         case OP_ADD_INT_LIT16:
2105             op = kOpAdd;
2106             break;
2107         case OP_MUL_INT_LIT8:
2108         case OP_MUL_INT_LIT16: {
2109             if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
2110                 return false;
2111             }
2112             op = kOpMul;
2113             break;
2114         }
2115         case OP_AND_INT_LIT8:
2116         case OP_AND_INT_LIT16:
2117             op = kOpAnd;
2118             break;
2119         case OP_OR_INT_LIT8:
2120         case OP_OR_INT_LIT16:
2121             op = kOpOr;
2122             break;
2123         case OP_XOR_INT_LIT8:
2124         case OP_XOR_INT_LIT16:
2125             op = kOpXor;
2126             break;
2127         case OP_SHL_INT_LIT8:
2128             lit &= 31;
2129             shiftOp = true;
2130             op = kOpLsl;
2131             break;
2132         case OP_SHR_INT_LIT8:
2133             lit &= 31;
2134             shiftOp = true;
2135             op = kOpAsr;
2136             break;
2137         case OP_USHR_INT_LIT8:
2138             lit &= 31;
2139             shiftOp = true;
2140             op = kOpLsr;
2141             break;
2142 
2143         case OP_DIV_INT_LIT8:
2144         case OP_DIV_INT_LIT16:
2145         case OP_REM_INT_LIT8:
2146         case OP_REM_INT_LIT16:
2147             if (lit == 0) {
2148                 /* Let the interpreter deal with div by 0 */
2149                 genInterpSingleStep(cUnit, mir);
2150                 return false;
2151             }
2152             if (handleEasyDivide(cUnit, dalvikOpCode, rlSrc, rlDest, lit)) {
2153                 return false;
2154             }
2155             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2156             loadValueDirectFixed(cUnit, rlSrc, r0);
2157             dvmCompilerClobber(cUnit, r0);
2158             if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
2159                 (dalvikOpCode == OP_DIV_INT_LIT16)) {
2160                 LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idiv);
2161                 isDiv = true;
2162             } else {
2163                 LOAD_FUNC_ADDR(cUnit, r2, (int)__aeabi_idivmod);
2164                 isDiv = false;
2165             }
2166             loadConstant(cUnit, r1, lit);
2167             opReg(cUnit, kOpBlx, r2);
2168             dvmCompilerClobberCallRegs(cUnit);
2169             if (isDiv)
2170                 rlResult = dvmCompilerGetReturn(cUnit);
2171             else
2172                 rlResult = dvmCompilerGetReturnAlt(cUnit);
2173             storeValue(cUnit, rlDest, rlResult);
2174             return false;
2175             break;
2176         default:
2177             return true;
2178     }
2179     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2180     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2181     // Avoid shifts by literal 0 - no support in Thumb.  Change to copy
2182     if (shiftOp && (lit == 0)) {
2183         genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2184     } else {
2185         opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2186     }
2187     storeValue(cUnit, rlDest, rlResult);
2188     return false;
2189 }
2190 
handleFmt22c(CompilationUnit * cUnit,MIR * mir)2191 static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2192 {
2193     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2194     int fieldOffset = -1;
2195     bool isVolatile = false;
2196     switch (dalvikOpCode) {
2197         /*
2198          * Wide volatiles currently handled via single step.
2199          * Add them here if generating in-line code.
2200          *     case OP_IGET_WIDE_VOLATILE:
2201          *     case OP_IPUT_WIDE_VOLATILE:
2202          */
2203         case OP_IGET:
2204         case OP_IGET_VOLATILE:
2205         case OP_IGET_WIDE:
2206         case OP_IGET_OBJECT:
2207         case OP_IGET_OBJECT_VOLATILE:
2208         case OP_IGET_BOOLEAN:
2209         case OP_IGET_BYTE:
2210         case OP_IGET_CHAR:
2211         case OP_IGET_SHORT:
2212         case OP_IPUT:
2213         case OP_IPUT_VOLATILE:
2214         case OP_IPUT_WIDE:
2215         case OP_IPUT_OBJECT:
2216         case OP_IPUT_OBJECT_VOLATILE:
2217         case OP_IPUT_BOOLEAN:
2218         case OP_IPUT_BYTE:
2219         case OP_IPUT_CHAR:
2220         case OP_IPUT_SHORT: {
2221             const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
2222                 mir->meta.calleeMethod : cUnit->method;
2223             Field *fieldPtr =
2224                 method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2225 
2226             if (fieldPtr == NULL) {
2227                 LOGE("Unexpected null instance field");
2228                 dvmAbort();
2229             }
2230             isVolatile = dvmIsVolatileField(fieldPtr);
2231             fieldOffset = ((InstField *)fieldPtr)->byteOffset;
2232             break;
2233         }
2234         default:
2235             break;
2236     }
2237 
2238     switch (dalvikOpCode) {
2239         case OP_NEW_ARRAY: {
2240             // Generates a call - use explicit registers
2241             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2242             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2243             RegLocation rlResult;
2244             void *classPtr = (void*)
2245               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2246 
2247             if (classPtr == NULL) {
2248                 LOGE("Unexpected null class");
2249                 dvmAbort();
2250             }
2251 
2252             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2253             genExportPC(cUnit, mir);
2254             loadValueDirectFixed(cUnit, rlSrc, r1);   /* Len */
2255             loadConstant(cUnit, r0, (int) classPtr );
2256             LOAD_FUNC_ADDR(cUnit, r3, (int)dvmAllocArrayByClass);
2257             /*
2258              * "len < 0": bail to the interpreter to re-execute the
2259              * instruction
2260              */
2261             genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
2262             loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2263             opReg(cUnit, kOpBlx, r3);
2264             dvmCompilerClobberCallRegs(cUnit);
2265             /* generate a branch over if allocation is successful */
2266             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2267             ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
2268             /*
2269              * OOM exception needs to be thrown here and cannot re-execute
2270              */
2271             loadConstant(cUnit, r0,
2272                          (int) (cUnit->method->insns + mir->offset));
2273             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2274             /* noreturn */
2275 
2276             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2277             target->defMask = ENCODE_ALL;
2278             branchOver->generic.target = (LIR *) target;
2279             rlResult = dvmCompilerGetReturn(cUnit);
2280             storeValue(cUnit, rlDest, rlResult);
2281             break;
2282         }
2283         case OP_INSTANCE_OF: {
2284             // May generate a call - use explicit registers
2285             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2286             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2287             RegLocation rlResult;
2288             ClassObject *classPtr =
2289               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2290             /*
2291              * Note: It is possible that classPtr is NULL at this point,
2292              * even though this instruction has been successfully interpreted.
2293              * If the previous interpretation had a null source, the
2294              * interpreter would not have bothered to resolve the clazz.
2295              * Bail out to the interpreter in this case, and log it
2296              * so that we can tell if it happens frequently.
2297              */
2298             if (classPtr == NULL) {
2299                 LOGD("null clazz in OP_INSTANCE_OF, single-stepping");
2300                 genInterpSingleStep(cUnit, mir);
2301                 break;
2302             }
2303             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2304             loadValueDirectFixed(cUnit, rlSrc, r0);  /* Ref */
2305             loadConstant(cUnit, r2, (int) classPtr );
2306 //TUNING: compare to 0 primative to allow use of CB[N]Z
2307             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2308             /* When taken r0 has NULL which can be used for store directly */
2309             ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
2310             /* r1 now contains object->clazz */
2311             loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
2312             /* r1 now contains object->clazz */
2313             LOAD_FUNC_ADDR(cUnit, r3, (int)dvmInstanceofNonTrivial);
2314             loadConstant(cUnit, r0, 1);                /* Assume true */
2315             opRegReg(cUnit, kOpCmp, r1, r2);
2316             ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
2317             genRegCopy(cUnit, r0, r1);
2318             genRegCopy(cUnit, r1, r2);
2319             opReg(cUnit, kOpBlx, r3);
2320             dvmCompilerClobberCallRegs(cUnit);
2321             /* branch target here */
2322             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2323             target->defMask = ENCODE_ALL;
2324             rlResult = dvmCompilerGetReturn(cUnit);
2325             storeValue(cUnit, rlDest, rlResult);
2326             branch1->generic.target = (LIR *)target;
2327             branch2->generic.target = (LIR *)target;
2328             break;
2329         }
2330         case OP_IGET_WIDE:
2331             genIGetWide(cUnit, mir, fieldOffset);
2332             break;
2333         case OP_IGET_VOLATILE:
2334         case OP_IGET_OBJECT_VOLATILE:
2335             isVolatile = true;
2336             // NOTE: intentional fallthrough
2337         case OP_IGET:
2338         case OP_IGET_OBJECT:
2339         case OP_IGET_BOOLEAN:
2340         case OP_IGET_BYTE:
2341         case OP_IGET_CHAR:
2342         case OP_IGET_SHORT:
2343             genIGet(cUnit, mir, kWord, fieldOffset, isVolatile);
2344             break;
2345         case OP_IPUT_WIDE:
2346             genIPutWide(cUnit, mir, fieldOffset);
2347             break;
2348         case OP_IPUT:
2349         case OP_IPUT_SHORT:
2350         case OP_IPUT_CHAR:
2351         case OP_IPUT_BYTE:
2352         case OP_IPUT_BOOLEAN:
2353             genIPut(cUnit, mir, kWord, fieldOffset, false, isVolatile);
2354             break;
2355         case OP_IPUT_VOLATILE:
2356         case OP_IPUT_OBJECT_VOLATILE:
2357             isVolatile = true;
2358             // NOTE: intentional fallthrough
2359         case OP_IPUT_OBJECT:
2360             genIPut(cUnit, mir, kWord, fieldOffset, true, isVolatile);
2361             break;
2362         case OP_IGET_WIDE_VOLATILE:
2363         case OP_IPUT_WIDE_VOLATILE:
2364             genInterpSingleStep(cUnit, mir);
2365             break;
2366         default:
2367             return true;
2368     }
2369     return false;
2370 }
2371 
handleFmt22cs(CompilationUnit * cUnit,MIR * mir)2372 static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2373 {
2374     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2375     int fieldOffset =  mir->dalvikInsn.vC;
2376     switch (dalvikOpCode) {
2377         case OP_IGET_QUICK:
2378         case OP_IGET_OBJECT_QUICK:
2379             genIGet(cUnit, mir, kWord, fieldOffset, false);
2380             break;
2381         case OP_IPUT_QUICK:
2382             genIPut(cUnit, mir, kWord, fieldOffset, false, false);
2383             break;
2384         case OP_IPUT_OBJECT_QUICK:
2385             genIPut(cUnit, mir, kWord, fieldOffset, true, false);
2386             break;
2387         case OP_IGET_WIDE_QUICK:
2388             genIGetWide(cUnit, mir, fieldOffset);
2389             break;
2390         case OP_IPUT_WIDE_QUICK:
2391             genIPutWide(cUnit, mir, fieldOffset);
2392             break;
2393         default:
2394             return true;
2395     }
2396     return false;
2397 
2398 }
2399 
2400 /* Compare agaist zero */
handleFmt22t(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)2401 static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2402                          ArmLIR *labelList)
2403 {
2404     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2405     ArmConditionCode cond;
2406     RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2407     RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
2408 
2409     rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
2410     rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
2411     opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
2412 
2413     switch (dalvikOpCode) {
2414         case OP_IF_EQ:
2415             cond = kArmCondEq;
2416             break;
2417         case OP_IF_NE:
2418             cond = kArmCondNe;
2419             break;
2420         case OP_IF_LT:
2421             cond = kArmCondLt;
2422             break;
2423         case OP_IF_GE:
2424             cond = kArmCondGe;
2425             break;
2426         case OP_IF_GT:
2427             cond = kArmCondGt;
2428             break;
2429         case OP_IF_LE:
2430             cond = kArmCondLe;
2431             break;
2432         default:
2433             cond = 0;
2434             LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2435             dvmCompilerAbort(cUnit);
2436     }
2437     genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2438     /* This mostly likely will be optimized away in a later phase */
2439     genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2440     return false;
2441 }
2442 
handleFmt22x_Fmt32x(CompilationUnit * cUnit,MIR * mir)2443 static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2444 {
2445     OpCode opCode = mir->dalvikInsn.opCode;
2446 
2447     switch (opCode) {
2448         case OP_MOVE_16:
2449         case OP_MOVE_OBJECT_16:
2450         case OP_MOVE_FROM16:
2451         case OP_MOVE_OBJECT_FROM16: {
2452             storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0),
2453                        dvmCompilerGetSrc(cUnit, mir, 0));
2454             break;
2455         }
2456         case OP_MOVE_WIDE_16:
2457         case OP_MOVE_WIDE_FROM16: {
2458             storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1),
2459                            dvmCompilerGetSrcWide(cUnit, mir, 0, 1));
2460             break;
2461         }
2462         default:
2463             return true;
2464     }
2465     return false;
2466 }
2467 
handleFmt23x(CompilationUnit * cUnit,MIR * mir)2468 static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2469 {
2470     OpCode opCode = mir->dalvikInsn.opCode;
2471     RegLocation rlSrc1;
2472     RegLocation rlSrc2;
2473     RegLocation rlDest;
2474 
2475     if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2476         return genArithOp( cUnit, mir );
2477     }
2478 
2479     /* APUTs have 3 sources and no targets */
2480     if (mir->ssaRep->numDefs == 0) {
2481         if (mir->ssaRep->numUses == 3) {
2482             rlDest = dvmCompilerGetSrc(cUnit, mir, 0);
2483             rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1);
2484             rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
2485         } else {
2486             assert(mir->ssaRep->numUses == 4);
2487             rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2488             rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2);
2489             rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3);
2490         }
2491     } else {
2492         /* Two sources and 1 dest.  Deduce the operand sizes */
2493         if (mir->ssaRep->numUses == 4) {
2494             rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2495             rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
2496         } else {
2497             assert(mir->ssaRep->numUses == 2);
2498             rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2499             rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
2500         }
2501         if (mir->ssaRep->numDefs == 2) {
2502             rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
2503         } else {
2504             assert(mir->ssaRep->numDefs == 1);
2505             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2506         }
2507     }
2508 
2509 
2510     switch (opCode) {
2511         case OP_CMPL_FLOAT:
2512         case OP_CMPG_FLOAT:
2513         case OP_CMPL_DOUBLE:
2514         case OP_CMPG_DOUBLE:
2515             return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2516         case OP_CMP_LONG:
2517             genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2518             break;
2519         case OP_AGET_WIDE:
2520             genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
2521             break;
2522         case OP_AGET:
2523         case OP_AGET_OBJECT:
2524             genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
2525             break;
2526         case OP_AGET_BOOLEAN:
2527             genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
2528             break;
2529         case OP_AGET_BYTE:
2530             genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
2531             break;
2532         case OP_AGET_CHAR:
2533             genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2534             break;
2535         case OP_AGET_SHORT:
2536             genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2537             break;
2538         case OP_APUT_WIDE:
2539             genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
2540             break;
2541         case OP_APUT:
2542             genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
2543             break;
2544         case OP_APUT_OBJECT:
2545             genArrayObjectPut(cUnit, mir, rlSrc1, rlSrc2, rlDest, 2);
2546             break;
2547         case OP_APUT_SHORT:
2548         case OP_APUT_CHAR:
2549             genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2550             break;
2551         case OP_APUT_BYTE:
2552         case OP_APUT_BOOLEAN:
2553             genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
2554             break;
2555         default:
2556             return true;
2557     }
2558     return false;
2559 }
2560 
2561 /*
2562  * Find the matching case.
2563  *
2564  * return values:
2565  * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
2566  *    including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
2567  * r1 (high 32-bit): the branch offset of the matching case (only for indexes
2568  *    above MAX_CHAINED_SWITCH_CASES).
2569  *
2570  * Instructions around the call are:
2571  *
2572  * mov r2, pc
2573  * blx &findPackedSwitchIndex
2574  * mov pc, r0
2575  * .align4
2576  * chaining cell for case 0 [12 bytes]
2577  * chaining cell for case 1 [12 bytes]
2578  *               :
2579  * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [12 bytes]
2580  * chaining cell for case default [8 bytes]
2581  * noChain exit
2582  */
findPackedSwitchIndex(const u2 * switchData,int testVal,int pc)2583 static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
2584 {
2585     int size;
2586     int firstKey;
2587     const int *entries;
2588     int index;
2589     int jumpIndex;
2590     int caseDPCOffset = 0;
2591     /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
2592     int chainingPC = (pc + 4) & ~3;
2593 
2594     /*
2595      * Packed switch data format:
2596      *  ushort ident = 0x0100   magic value
2597      *  ushort size             number of entries in the table
2598      *  int first_key           first (and lowest) switch case value
2599      *  int targets[size]       branch targets, relative to switch opcode
2600      *
2601      * Total size is (4+size*2) 16-bit code units.
2602      */
2603     size = switchData[1];
2604     assert(size > 0);
2605 
2606     firstKey = switchData[2];
2607     firstKey |= switchData[3] << 16;
2608 
2609 
2610     /* The entries are guaranteed to be aligned on a 32-bit boundary;
2611      * we can treat them as a native int array.
2612      */
2613     entries = (const int*) &switchData[4];
2614     assert(((u4)entries & 0x3) == 0);
2615 
2616     index = testVal - firstKey;
2617 
2618     /* Jump to the default cell */
2619     if (index < 0 || index >= size) {
2620         jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
2621     /* Jump to the non-chaining exit point */
2622     } else if (index >= MAX_CHAINED_SWITCH_CASES) {
2623         jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
2624         caseDPCOffset = entries[index];
2625     /* Jump to the inline chaining cell */
2626     } else {
2627         jumpIndex = index;
2628     }
2629 
2630     chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE;
2631     return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
2632 }
2633 
2634 /* See comments for findPackedSwitchIndex */
findSparseSwitchIndex(const u2 * switchData,int testVal,int pc)2635 static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
2636 {
2637     int size;
2638     const int *keys;
2639     const int *entries;
2640     int chainingPC = (pc + 4) & ~3;
2641     int i;
2642 
2643     /*
2644      * Sparse switch data format:
2645      *  ushort ident = 0x0200   magic value
2646      *  ushort size             number of entries in the table; > 0
2647      *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
2648      *  int targets[size]       branch targets, relative to switch opcode
2649      *
2650      * Total size is (2+size*4) 16-bit code units.
2651      */
2652 
2653     size = switchData[1];
2654     assert(size > 0);
2655 
2656     /* The keys are guaranteed to be aligned on a 32-bit boundary;
2657      * we can treat them as a native int array.
2658      */
2659     keys = (const int*) &switchData[2];
2660     assert(((u4)keys & 0x3) == 0);
2661 
2662     /* The entries are guaranteed to be aligned on a 32-bit boundary;
2663      * we can treat them as a native int array.
2664      */
2665     entries = keys + size;
2666     assert(((u4)entries & 0x3) == 0);
2667 
2668     /*
2669      * Run through the list of keys, which are guaranteed to
2670      * be sorted low-to-high.
2671      *
2672      * Most tables have 3-4 entries.  Few have more than 10.  A binary
2673      * search here is probably not useful.
2674      */
2675     for (i = 0; i < size; i++) {
2676         int k = keys[i];
2677         if (k == testVal) {
2678             /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
2679             int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
2680                            i : MAX_CHAINED_SWITCH_CASES + 1;
2681             chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE;
2682             return (((s8) entries[i]) << 32) | (u8) chainingPC;
2683         } else if (k > testVal) {
2684             break;
2685         }
2686     }
2687     return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) *
2688            CHAIN_CELL_NORMAL_SIZE;
2689 }
2690 
handleFmt31t(CompilationUnit * cUnit,MIR * mir)2691 static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2692 {
2693     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2694     switch (dalvikOpCode) {
2695         case OP_FILL_ARRAY_DATA: {
2696             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2697             // Making a call - use explicit registers
2698             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2699             genExportPC(cUnit, mir);
2700             loadValueDirectFixed(cUnit, rlSrc, r0);
2701             LOAD_FUNC_ADDR(cUnit, r2, (int)dvmInterpHandleFillArrayData);
2702             loadConstant(cUnit, r1,
2703                (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
2704             opReg(cUnit, kOpBlx, r2);
2705             dvmCompilerClobberCallRegs(cUnit);
2706             /* generate a branch over if successful */
2707             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2708             ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
2709             loadConstant(cUnit, r0,
2710                          (int) (cUnit->method->insns + mir->offset));
2711             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2712             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2713             target->defMask = ENCODE_ALL;
2714             branchOver->generic.target = (LIR *) target;
2715             break;
2716         }
2717         /*
2718          * Compute the goto target of up to
2719          * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
2720          * See the comment before findPackedSwitchIndex for the code layout.
2721          */
2722         case OP_PACKED_SWITCH:
2723         case OP_SPARSE_SWITCH: {
2724             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2725             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
2726             loadValueDirectFixed(cUnit, rlSrc, r1);
2727             dvmCompilerLockAllTemps(cUnit);
2728             if (dalvikOpCode == OP_PACKED_SWITCH) {
2729                 LOAD_FUNC_ADDR(cUnit, r4PC, (int)findPackedSwitchIndex);
2730             } else {
2731                 LOAD_FUNC_ADDR(cUnit, r4PC, (int)findSparseSwitchIndex);
2732             }
2733             /* r0 <- Addr of the switch data */
2734             loadConstant(cUnit, r0,
2735                (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
2736             /* r2 <- pc of the instruction following the blx */
2737             opRegReg(cUnit, kOpMov, r2, rpc);
2738             opReg(cUnit, kOpBlx, r4PC);
2739             dvmCompilerClobberCallRegs(cUnit);
2740             /* pc <- computed goto target */
2741             opRegReg(cUnit, kOpMov, rpc, r0);
2742             break;
2743         }
2744         default:
2745             return true;
2746     }
2747     return false;
2748 }
2749 
2750 /*
2751  * See the example of predicted inlining listed before the
2752  * genValidationForPredictedInline function. The function here takes care the
2753  * branch over at 0x4858de78 and the misprediction target at 0x4858de7a.
2754  */
genLandingPadForMispredictedCallee(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)2755 static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir,
2756                                                BasicBlock *bb,
2757                                                ArmLIR *labelList)
2758 {
2759     BasicBlock *fallThrough = bb->fallThrough;
2760 
2761     /* Bypass the move-result block if there is one */
2762     if (fallThrough->firstMIRInsn) {
2763         assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED);
2764         fallThrough = fallThrough->fallThrough;
2765     }
2766     /* Generate a branch over if the predicted inlining is correct */
2767     genUnconditionalBranch(cUnit, &labelList[fallThrough->id]);
2768 
2769     /* Reset the register state */
2770     dvmCompilerResetRegPool(cUnit);
2771     dvmCompilerClobberAllRegs(cUnit);
2772     dvmCompilerResetNullCheck(cUnit);
2773 
2774     /* Target for the slow invoke path */
2775     ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2776     target->defMask = ENCODE_ALL;
2777     /* Hook up the target to the verification branch */
2778     mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target;
2779 }
2780 
handleFmt35c_3rc(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)2781 static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2782                              ArmLIR *labelList)
2783 {
2784     ArmLIR *retChainingCell = NULL;
2785     ArmLIR *pcrLabel = NULL;
2786 
2787     /* An invoke with the MIR_INLINED is effectively a no-op */
2788     if (mir->OptimizationFlags & MIR_INLINED)
2789         return false;
2790 
2791     if (bb->fallThrough != NULL)
2792         retChainingCell = &labelList[bb->fallThrough->id];
2793 
2794     DecodedInstruction *dInsn = &mir->dalvikInsn;
2795     switch (mir->dalvikInsn.opCode) {
2796         /*
2797          * calleeMethod = this->clazz->vtable[
2798          *     method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2799          * ]
2800          */
2801         case OP_INVOKE_VIRTUAL:
2802         case OP_INVOKE_VIRTUAL_RANGE: {
2803             ArmLIR *predChainingCell = &labelList[bb->taken->id];
2804             int methodIndex =
2805                 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2806                 methodIndex;
2807 
2808             /*
2809              * If the invoke has non-null misPredBranchOver, we need to generate
2810              * the non-inlined version of the invoke here to handle the
2811              * mispredicted case.
2812              */
2813             if (mir->meta.callsiteInfo->misPredBranchOver) {
2814                 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
2815             }
2816 
2817             if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2818                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2819             else
2820                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2821 
2822             genInvokeVirtualCommon(cUnit, mir, methodIndex,
2823                                    retChainingCell,
2824                                    predChainingCell,
2825                                    pcrLabel);
2826             break;
2827         }
2828         /*
2829          * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2830          *                ->pResMethods[BBBB]->methodIndex]
2831          */
2832         case OP_INVOKE_SUPER:
2833         case OP_INVOKE_SUPER_RANGE: {
2834             /* Grab the method ptr directly from what the interpreter sees */
2835             const Method *calleeMethod = mir->meta.callsiteInfo->method;
2836             assert(calleeMethod == cUnit->method->clazz->super->vtable[
2837                                      cUnit->method->clazz->pDvmDex->
2838                                        pResMethods[dInsn->vB]->methodIndex]);
2839 
2840             if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2841                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2842             else
2843                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2844 
2845             /* r0 = calleeMethod */
2846             loadConstant(cUnit, r0, (int) calleeMethod);
2847 
2848             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2849                                      calleeMethod);
2850             break;
2851         }
2852         /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2853         case OP_INVOKE_DIRECT:
2854         case OP_INVOKE_DIRECT_RANGE: {
2855             /* Grab the method ptr directly from what the interpreter sees */
2856             const Method *calleeMethod = mir->meta.callsiteInfo->method;
2857             assert(calleeMethod ==
2858                    cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
2859 
2860             if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2861                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2862             else
2863                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2864 
2865             /* r0 = calleeMethod */
2866             loadConstant(cUnit, r0, (int) calleeMethod);
2867 
2868             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2869                                      calleeMethod);
2870             break;
2871         }
2872         /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2873         case OP_INVOKE_STATIC:
2874         case OP_INVOKE_STATIC_RANGE: {
2875             /* Grab the method ptr directly from what the interpreter sees */
2876             const Method *calleeMethod = mir->meta.callsiteInfo->method;
2877             assert(calleeMethod ==
2878                    cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
2879 
2880             if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2881                 genProcessArgsNoRange(cUnit, mir, dInsn,
2882                                       NULL /* no null check */);
2883             else
2884                 genProcessArgsRange(cUnit, mir, dInsn,
2885                                     NULL /* no null check */);
2886 
2887             /* r0 = calleeMethod */
2888             loadConstant(cUnit, r0, (int) calleeMethod);
2889 
2890             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2891                                      calleeMethod);
2892             break;
2893         }
2894         /*
2895          * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2896          *                    BBBB, method, method->clazz->pDvmDex)
2897          *
2898          * The following is an example of generated code for
2899          *      "invoke-interface v0"
2900          *
2901          * -------- dalvik offset: 0x0008 @ invoke-interface v0
2902          * 0x47357e36 : ldr     r0, [r5, #0]   --+
2903          * 0x47357e38 : sub     r7,r5,#24        |
2904          * 0x47357e3c : cmp     r0, #0           | genProcessArgsNoRange
2905          * 0x47357e3e : beq     0x47357e82       |
2906          * 0x47357e40 : stmia   r7, <r0>       --+
2907          * 0x47357e42 : ldr     r4, [pc, #120] --> r4 <- dalvikPC of this invoke
2908          * 0x47357e44 : add     r1, pc, #64    --> r1 <- &retChainingCell
2909          * 0x47357e46 : add     r2, pc, #72    --> r2 <- &predictedChainingCell
2910          * 0x47357e48 : blx_1   0x47348190     --+ TEMPLATE_INVOKE_METHOD_
2911          * 0x47357e4a : blx_2   see above      --+     PREDICTED_CHAIN
2912          * 0x47357e4c : b       0x47357e90     --> off to the predicted chain
2913          * 0x47357e4e : b       0x47357e82     --> punt to the interpreter
2914          * 0x47357e50 : mov     r8, r1         --+
2915          * 0x47357e52 : mov     r9, r2           |
2916          * 0x47357e54 : ldr     r2, [pc, #96]    |
2917          * 0x47357e56 : mov     r10, r3          |
2918          * 0x47357e58 : movs    r0, r3           | dvmFindInterfaceMethodInCache
2919          * 0x47357e5a : ldr     r3, [pc, #88]    |
2920          * 0x47357e5c : ldr     r7, [pc, #80]    |
2921          * 0x47357e5e : mov     r1, #1452        |
2922          * 0x47357e62 : blx     r7             --+
2923          * 0x47357e64 : cmp     r0, #0         --> calleeMethod == NULL?
2924          * 0x47357e66 : bne     0x47357e6e     --> branch over the throw if !r0
2925          * 0x47357e68 : ldr     r0, [pc, #80]  --> load Dalvik PC of the invoke
2926          * 0x47357e6a : blx_1   0x47348494     --+ TEMPLATE_THROW_EXCEPTION_
2927          * 0x47357e6c : blx_2   see above      --+     COMMON
2928          * 0x47357e6e : mov     r1, r8         --> r1 <- &retChainingCell
2929          * 0x47357e70 : cmp     r1, #0         --> compare against 0
2930          * 0x47357e72 : bgt     0x47357e7c     --> >=0? don't rechain
2931          * 0x47357e74 : ldr     r7, [r6, #108] --+
2932          * 0x47357e76 : mov     r2, r9           | dvmJitToPatchPredictedChain
2933          * 0x47357e78 : mov     r3, r10          |
2934          * 0x47357e7a : blx     r7             --+
2935          * 0x47357e7c : add     r1, pc, #8     --> r1 <- &retChainingCell
2936          * 0x47357e7e : blx_1   0x4734809c     --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2937          * 0x47357e80 : blx_2   see above      --+
2938          * -------- reconstruct dalvik PC : 0x425719dc @ +0x0008
2939          * 0x47357e82 : ldr     r0, [pc, #56]
2940          * Exception_Handling:
2941          * 0x47357e84 : ldr     r1, [r6, #92]
2942          * 0x47357e86 : blx     r1
2943          * 0x47357e88 : .align4
2944          * -------- chaining cell (hot): 0x000b
2945          * 0x47357e88 : ldr     r0, [r6, #104]
2946          * 0x47357e8a : blx     r0
2947          * 0x47357e8c : data    0x19e2(6626)
2948          * 0x47357e8e : data    0x4257(16983)
2949          * 0x47357e90 : .align4
2950          * -------- chaining cell (predicted)
2951          * 0x47357e90 : data    0xe7fe(59390)  --> will be patched into bx
2952          * 0x47357e92 : data    0x0000(0)
2953          * 0x47357e94 : data    0x0000(0)      --> class
2954          * 0x47357e96 : data    0x0000(0)
2955          * 0x47357e98 : data    0x0000(0)      --> method
2956          * 0x47357e9a : data    0x0000(0)
2957          * 0x47357e9c : data    0x0000(0)      --> rechain count
2958          * 0x47357e9e : data    0x0000(0)
2959          * -------- end of chaining cells (0x006c)
2960          * 0x47357eb0 : .word (0xad03e369)
2961          * 0x47357eb4 : .word (0x28a90)
2962          * 0x47357eb8 : .word (0x41a63394)
2963          * 0x47357ebc : .word (0x425719dc)
2964          */
2965         case OP_INVOKE_INTERFACE:
2966         case OP_INVOKE_INTERFACE_RANGE: {
2967             ArmLIR *predChainingCell = &labelList[bb->taken->id];
2968 
2969             /*
2970              * If the invoke has non-null misPredBranchOver, we need to generate
2971              * the non-inlined version of the invoke here to handle the
2972              * mispredicted case.
2973              */
2974             if (mir->meta.callsiteInfo->misPredBranchOver) {
2975                 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
2976             }
2977 
2978             if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2979                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2980             else
2981                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2982 
2983             /* "this" is already left in r0 by genProcessArgs* */
2984 
2985             /* r4PC = dalvikCallsite */
2986             loadConstant(cUnit, r4PC,
2987                          (int) (cUnit->method->insns + mir->offset));
2988 
2989             /* r1 = &retChainingCell */
2990             ArmLIR *addrRetChain =
2991                 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
2992             addrRetChain->generic.target = (LIR *) retChainingCell;
2993 
2994             /* r2 = &predictedChainingCell */
2995             ArmLIR *predictedChainingCell =
2996                 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
2997             predictedChainingCell->generic.target = (LIR *) predChainingCell;
2998 
2999             genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3000 
3001             /* return through lr - jump to the chaining cell */
3002             genUnconditionalBranch(cUnit, predChainingCell);
3003 
3004             /*
3005              * null-check on "this" may have been eliminated, but we still need
3006              * a PC-reconstruction label for stack overflow bailout.
3007              */
3008             if (pcrLabel == NULL) {
3009                 int dPC = (int) (cUnit->method->insns + mir->offset);
3010                 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3011                 pcrLabel->opCode = kArmPseudoPCReconstructionCell;
3012                 pcrLabel->operands[0] = dPC;
3013                 pcrLabel->operands[1] = mir->offset;
3014                 /* Insert the place holder to the growable list */
3015                 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3016             }
3017 
3018             /* return through lr+2 - punt to the interpreter */
3019             genUnconditionalBranch(cUnit, pcrLabel);
3020 
3021             /*
3022              * return through lr+4 - fully resolve the callee method.
3023              * r1 <- count
3024              * r2 <- &predictedChainCell
3025              * r3 <- this->class
3026              * r4 <- dPC
3027              * r7 <- this->class->vtable
3028              */
3029 
3030             /* Save count, &predictedChainCell, and class to high regs first */
3031             genRegCopy(cUnit, r8, r1);
3032             genRegCopy(cUnit, r9, r2);
3033             genRegCopy(cUnit, r10, r3);
3034 
3035             /* r0 now contains this->clazz */
3036             genRegCopy(cUnit, r0, r3);
3037 
3038             /* r1 = BBBB */
3039             loadConstant(cUnit, r1, dInsn->vB);
3040 
3041             /* r2 = method (caller) */
3042             loadConstant(cUnit, r2, (int) cUnit->method);
3043 
3044             /* r3 = pDvmDex */
3045             loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3046 
3047             LOAD_FUNC_ADDR(cUnit, r7,
3048                            (intptr_t) dvmFindInterfaceMethodInCache);
3049             opReg(cUnit, kOpBlx, r7);
3050             /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3051 
3052             dvmCompilerClobberCallRegs(cUnit);
3053             /* generate a branch over if the interface method is resolved */
3054             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3055             ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
3056             /*
3057              * calleeMethod == NULL -> throw
3058              */
3059             loadConstant(cUnit, r0,
3060                          (int) (cUnit->method->insns + mir->offset));
3061             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3062             /* noreturn */
3063 
3064             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3065             target->defMask = ENCODE_ALL;
3066             branchOver->generic.target = (LIR *) target;
3067 
3068             genRegCopy(cUnit, r1, r8);
3069 
3070             /* Check if rechain limit is reached */
3071             opRegImm(cUnit, kOpCmp, r1, 0);
3072 
3073             ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
3074 
3075             loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3076                          jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
3077 
3078             genRegCopy(cUnit, r1, rGLUE);
3079             genRegCopy(cUnit, r2, r9);
3080             genRegCopy(cUnit, r3, r10);
3081 
3082             /*
3083              * r0 = calleeMethod
3084              * r2 = &predictedChainingCell
3085              * r3 = class
3086              *
3087              * &returnChainingCell has been loaded into r1 but is not needed
3088              * when patching the chaining cell and will be clobbered upon
3089              * returning so it will be reconstructed again.
3090              */
3091             opReg(cUnit, kOpBlx, r7);
3092 
3093             /* r1 = &retChainingCell */
3094             addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
3095             addrRetChain->generic.target = (LIR *) retChainingCell;
3096 
3097             bypassRechaining->generic.target = (LIR *) addrRetChain;
3098 
3099             /*
3100              * r0 = this, r1 = calleeMethod,
3101              * r1 = &ChainingCell,
3102              * r4PC = callsiteDPC,
3103              */
3104             genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3105 #if defined(WITH_JIT_TUNING)
3106             gDvmJit.invokePolymorphic++;
3107 #endif
3108             /* Handle exceptions using the interpreter */
3109             genTrap(cUnit, mir->offset, pcrLabel);
3110             break;
3111         }
3112         /* NOP */
3113         case OP_INVOKE_DIRECT_EMPTY: {
3114             return false;
3115         }
3116         case OP_FILLED_NEW_ARRAY:
3117         case OP_FILLED_NEW_ARRAY_RANGE: {
3118             /* Just let the interpreter deal with these */
3119             genInterpSingleStep(cUnit, mir);
3120             break;
3121         }
3122         default:
3123             return true;
3124     }
3125     return false;
3126 }
3127 
handleFmt35ms_3rms(CompilationUnit * cUnit,MIR * mir,BasicBlock * bb,ArmLIR * labelList)3128 static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
3129                                BasicBlock *bb, ArmLIR *labelList)
3130 {
3131     ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3132     ArmLIR *predChainingCell = &labelList[bb->taken->id];
3133     ArmLIR *pcrLabel = NULL;
3134 
3135     /* An invoke with the MIR_INLINED is effectively a no-op */
3136     if (mir->OptimizationFlags & MIR_INLINED)
3137         return false;
3138 
3139     DecodedInstruction *dInsn = &mir->dalvikInsn;
3140     switch (mir->dalvikInsn.opCode) {
3141         /* calleeMethod = this->clazz->vtable[BBBB] */
3142         case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3143         case OP_INVOKE_VIRTUAL_QUICK: {
3144             int methodIndex = dInsn->vB;
3145 
3146             /*
3147              * If the invoke has non-null misPredBranchOver, we need to generate
3148              * the non-inlined version of the invoke here to handle the
3149              * mispredicted case.
3150              */
3151             if (mir->meta.callsiteInfo->misPredBranchOver) {
3152                 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
3153             }
3154 
3155             if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3156                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3157             else
3158                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3159 
3160             genInvokeVirtualCommon(cUnit, mir, methodIndex,
3161                                    retChainingCell,
3162                                    predChainingCell,
3163                                    pcrLabel);
3164             break;
3165         }
3166         /* calleeMethod = method->clazz->super->vtable[BBBB] */
3167         case OP_INVOKE_SUPER_QUICK:
3168         case OP_INVOKE_SUPER_QUICK_RANGE: {
3169             /* Grab the method ptr directly from what the interpreter sees */
3170             const Method *calleeMethod = mir->meta.callsiteInfo->method;
3171             assert(calleeMethod ==
3172                    cUnit->method->clazz->super->vtable[dInsn->vB]);
3173 
3174             if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3175                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3176             else
3177                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3178 
3179             /* r0 = calleeMethod */
3180             loadConstant(cUnit, r0, (int) calleeMethod);
3181 
3182             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3183                                      calleeMethod);
3184             break;
3185         }
3186         default:
3187             return true;
3188     }
3189     return false;
3190 }
3191 
3192 /*
3193  * This operation is complex enough that we'll do it partly inline
3194  * and partly with a handler.  NOTE: the handler uses hardcoded
3195  * values for string object offsets and must be revisitied if the
3196  * layout changes.
3197  */
genInlinedCompareTo(CompilationUnit * cUnit,MIR * mir)3198 static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
3199 {
3200 #if defined(USE_GLOBAL_STRING_DEFS)
3201     return false;
3202 #else
3203     ArmLIR *rollback;
3204     RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
3205     RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1);
3206 
3207     loadValueDirectFixed(cUnit, rlThis, r0);
3208     loadValueDirectFixed(cUnit, rlComp, r1);
3209     /* Test objects for NULL */
3210     rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
3211     genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback);
3212     /*
3213      * TUNING: we could check for object pointer equality before invoking
3214      * handler. Unclear whether the gain would be worth the added code size
3215      * expansion.
3216      */
3217     genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
3218     storeValue(cUnit, inlinedTarget(cUnit, mir, false),
3219                dvmCompilerGetReturn(cUnit));
3220     return true;
3221 #endif
3222 }
3223 
genInlinedFastIndexOf(CompilationUnit * cUnit,MIR * mir)3224 static bool genInlinedFastIndexOf(CompilationUnit *cUnit, MIR *mir)
3225 {
3226 #if defined(USE_GLOBAL_STRING_DEFS)
3227     return false;
3228 #else
3229     RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
3230     RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1);
3231 
3232     loadValueDirectFixed(cUnit, rlThis, r0);
3233     loadValueDirectFixed(cUnit, rlChar, r1);
3234     RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
3235     loadValueDirectFixed(cUnit, rlStart, r2);
3236     /* Test objects for NULL */
3237     genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
3238     genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
3239     storeValue(cUnit, inlinedTarget(cUnit, mir, false),
3240                dvmCompilerGetReturn(cUnit));
3241     return true;
3242 #endif
3243 }
3244 
3245 // Generates an inlined String.isEmpty or String.length.
genInlinedStringIsEmptyOrLength(CompilationUnit * cUnit,MIR * mir,bool isEmpty)3246 static bool genInlinedStringIsEmptyOrLength(CompilationUnit *cUnit, MIR *mir,
3247                                             bool isEmpty)
3248 {
3249     // dst = src.length();
3250     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
3251     RegLocation rlDest = inlinedTarget(cUnit, mir, false);
3252     rlObj = loadValue(cUnit, rlObj, kCoreReg);
3253     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3254     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
3255     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
3256                  rlResult.lowReg);
3257     if (isEmpty) {
3258         // dst = (dst == 0);
3259         int tReg = dvmCompilerAllocTemp(cUnit);
3260         opRegReg(cUnit, kOpNeg, tReg, rlResult.lowReg);
3261         opRegRegReg(cUnit, kOpAdc, rlResult.lowReg, rlResult.lowReg, tReg);
3262     }
3263     storeValue(cUnit, rlDest, rlResult);
3264     return false;
3265 }
3266 
genInlinedStringLength(CompilationUnit * cUnit,MIR * mir)3267 static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
3268 {
3269     return genInlinedStringIsEmptyOrLength(cUnit, mir, false);
3270 }
3271 
genInlinedStringIsEmpty(CompilationUnit * cUnit,MIR * mir)3272 static bool genInlinedStringIsEmpty(CompilationUnit *cUnit, MIR *mir)
3273 {
3274     return genInlinedStringIsEmptyOrLength(cUnit, mir, true);
3275 }
3276 
genInlinedStringCharAt(CompilationUnit * cUnit,MIR * mir)3277 static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
3278 {
3279     int contents = offsetof(ArrayObject, contents);
3280     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
3281     RegLocation rlIdx = dvmCompilerGetSrc(cUnit, mir, 1);
3282     RegLocation rlDest = inlinedTarget(cUnit, mir, false);
3283     RegLocation rlResult;
3284     rlObj = loadValue(cUnit, rlObj, kCoreReg);
3285     rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
3286     int regMax = dvmCompilerAllocTemp(cUnit);
3287     int regOff = dvmCompilerAllocTemp(cUnit);
3288     int regPtr = dvmCompilerAllocTemp(cUnit);
3289     ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
3290                                     mir->offset, NULL);
3291     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
3292     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
3293     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
3294     genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
3295     dvmCompilerFreeTemp(cUnit, regMax);
3296     opRegImm(cUnit, kOpAdd, regPtr, contents);
3297     opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
3298     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3299     loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
3300     storeValue(cUnit, rlDest, rlResult);
3301     return false;
3302 }
3303 
genInlinedAbsInt(CompilationUnit * cUnit,MIR * mir)3304 static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
3305 {
3306     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
3307     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
3308     RegLocation rlDest = inlinedTarget(cUnit, mir, false);
3309     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3310     int signReg = dvmCompilerAllocTemp(cUnit);
3311     /*
3312      * abs(x) = y<=x>>31, (x+y)^y.
3313      * Thumb2's IT block also yields 3 instructions, but imposes
3314      * scheduling constraints.
3315      */
3316     opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
3317     opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
3318     opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
3319     storeValue(cUnit, rlDest, rlResult);
3320     return false;
3321 }
3322 
genInlinedAbsLong(CompilationUnit * cUnit,MIR * mir)3323 static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
3324 {
3325     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
3326     RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
3327     rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
3328     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3329     int signReg = dvmCompilerAllocTemp(cUnit);
3330     /*
3331      * abs(x) = y<=x>>31, (x+y)^y.
3332      * Thumb2 IT block allows slightly shorter sequence,
3333      * but introduces a scheduling barrier.  Stick with this
3334      * mechanism for now.
3335      */
3336     opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
3337     opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
3338     opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg);
3339     opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
3340     opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
3341     storeValueWide(cUnit, rlDest, rlResult);
3342     return false;
3343 }
3344 
genInlinedIntFloatConversion(CompilationUnit * cUnit,MIR * mir)3345 static bool genInlinedIntFloatConversion(CompilationUnit *cUnit, MIR *mir)
3346 {
3347     // Just move from source to destination...
3348     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
3349     RegLocation rlDest = inlinedTarget(cUnit, mir, false);
3350     storeValue(cUnit, rlDest, rlSrc);
3351     return false;
3352 }
3353 
genInlinedLongDoubleConversion(CompilationUnit * cUnit,MIR * mir)3354 static bool genInlinedLongDoubleConversion(CompilationUnit *cUnit, MIR *mir)
3355 {
3356     // Just move from source to destination...
3357     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
3358     RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
3359     storeValueWide(cUnit, rlDest, rlSrc);
3360     return false;
3361 }
3362 
3363 /*
3364  * NOTE: Handles both range and non-range versions (arguments
3365  * have already been normalized by this point).
3366  */
handleExecuteInline(CompilationUnit * cUnit,MIR * mir)3367 static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
3368 {
3369     DecodedInstruction *dInsn = &mir->dalvikInsn;
3370     switch( mir->dalvikInsn.opCode) {
3371         case OP_EXECUTE_INLINE_RANGE:
3372         case OP_EXECUTE_INLINE: {
3373             unsigned int i;
3374             const InlineOperation* inLineTable = dvmGetInlineOpsTable();
3375             int offset = offsetof(InterpState, retval);
3376             int operation = dInsn->vB;
3377             switch (operation) {
3378                 case INLINE_EMPTYINLINEMETHOD:
3379                     return false;  /* Nop */
3380                 case INLINE_STRING_LENGTH:
3381                     return genInlinedStringLength(cUnit, mir);
3382                 case INLINE_STRING_IS_EMPTY:
3383                     return genInlinedStringIsEmpty(cUnit, mir);
3384                 case INLINE_MATH_ABS_INT:
3385                     return genInlinedAbsInt(cUnit, mir);
3386                 case INLINE_MATH_ABS_LONG:
3387                     return genInlinedAbsLong(cUnit, mir);
3388                 case INLINE_MATH_MIN_INT:
3389                     return genInlinedMinMaxInt(cUnit, mir, true);
3390                 case INLINE_MATH_MAX_INT:
3391                     return genInlinedMinMaxInt(cUnit, mir, false);
3392                 case INLINE_STRING_CHARAT:
3393                     return genInlinedStringCharAt(cUnit, mir);
3394                 case INLINE_MATH_SQRT:
3395                     if (genInlineSqrt(cUnit, mir))
3396                         return false;
3397                     else
3398                         break;   /* Handle with C routine */
3399                 case INLINE_MATH_ABS_FLOAT:
3400                     if (genInlinedAbsFloat(cUnit, mir))
3401                         return false;
3402                     else
3403                         break;
3404                 case INLINE_MATH_ABS_DOUBLE:
3405                     if (genInlinedAbsDouble(cUnit, mir))
3406                         return false;
3407                     else
3408                         break;
3409                 case INLINE_STRING_COMPARETO:
3410                     if (genInlinedCompareTo(cUnit, mir))
3411                         return false;
3412                     else
3413                         break;
3414                 case INLINE_STRING_FASTINDEXOF_II:
3415                     if (genInlinedFastIndexOf(cUnit, mir))
3416                         return false;
3417                     else
3418                         break;
3419                 case INLINE_FLOAT_TO_RAW_INT_BITS:
3420                 case INLINE_INT_BITS_TO_FLOAT:
3421                     return genInlinedIntFloatConversion(cUnit, mir);
3422                 case INLINE_DOUBLE_TO_RAW_LONG_BITS:
3423                 case INLINE_LONG_BITS_TO_DOUBLE:
3424                     return genInlinedLongDoubleConversion(cUnit, mir);
3425                 case INLINE_STRING_EQUALS:
3426                 case INLINE_MATH_COS:
3427                 case INLINE_MATH_SIN:
3428                 case INLINE_FLOAT_TO_INT_BITS:
3429                 case INLINE_DOUBLE_TO_LONG_BITS:
3430                     break;   /* Handle with C routine */
3431                 default:
3432                     dvmCompilerAbort(cUnit);
3433             }
3434             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
3435             dvmCompilerClobberCallRegs(cUnit);
3436             dvmCompilerClobber(cUnit, r4PC);
3437             dvmCompilerClobber(cUnit, r7);
3438             opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
3439             opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
3440             LOAD_FUNC_ADDR(cUnit, r4PC, (int)inLineTable[operation].func);
3441             genExportPC(cUnit, mir);
3442             for (i=0; i < dInsn->vA; i++) {
3443                 loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i);
3444             }
3445             opReg(cUnit, kOpBlx, r4PC);
3446             opRegImm(cUnit, kOpAdd, r13, 8);
3447             opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3448             ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
3449             loadConstant(cUnit, r0,
3450                          (int) (cUnit->method->insns + mir->offset));
3451             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3452             ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3453             target->defMask = ENCODE_ALL;
3454             branchOver->generic.target = (LIR *) target;
3455             break;
3456         }
3457         default:
3458             return true;
3459     }
3460     return false;
3461 }
3462 
handleFmt51l(CompilationUnit * cUnit,MIR * mir)3463 static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3464 {
3465     //TUNING: We're using core regs here - not optimal when target is a double
3466     RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
3467     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3468     loadConstantNoClobber(cUnit, rlResult.lowReg,
3469                           mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3470     loadConstantNoClobber(cUnit, rlResult.highReg,
3471                           (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3472     storeValueWide(cUnit, rlDest, rlResult);
3473     return false;
3474 }
3475 
3476 /*
3477  * The following are special processing routines that handle transfer of
3478  * controls between compiled code and the interpreter. Certain VM states like
3479  * Dalvik PC and special-purpose registers are reconstructed here.
3480  */
3481 
3482 /*
3483  * Insert a
3484  *    b   .+4
3485  *    nop
3486  * pair at the beginning of a chaining cell.  This serves as the
3487  * switch branch that selects between reverting to the interpreter or
3488  * not.  Once the cell is chained to a translation, the cell will
3489  * contain a 32-bit branch.  Subsequent chain/unchain operations will
3490  * then only alter that first 16-bits - the "b .+4" for unchaining,
3491  * and the restoration of the first half of the 32-bit branch for
3492  * rechaining.
3493  */
insertChainingSwitch(CompilationUnit * cUnit)3494 static void insertChainingSwitch(CompilationUnit *cUnit)
3495 {
3496     ArmLIR *branch = newLIR0(cUnit, kThumbBUncond);
3497     newLIR2(cUnit, kThumbOrr, r0, r0);
3498     ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3499     target->defMask = ENCODE_ALL;
3500     branch->generic.target = (LIR *) target;
3501 }
3502 
3503 /* Chaining cell for code that may need warmup. */
handleNormalChainingCell(CompilationUnit * cUnit,unsigned int offset)3504 static void handleNormalChainingCell(CompilationUnit *cUnit,
3505                                      unsigned int offset)
3506 {
3507     /*
3508      * Use raw instruction constructors to guarantee that the generated
3509      * instructions fit the predefined cell size.
3510      */
3511     insertChainingSwitch(cUnit);
3512     newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
3513             offsetof(InterpState,
3514                      jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3515     newLIR1(cUnit, kThumbBlxR, r0);
3516     addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3517 }
3518 
3519 /*
3520  * Chaining cell for instructions that immediately following already translated
3521  * code.
3522  */
handleHotChainingCell(CompilationUnit * cUnit,unsigned int offset)3523 static void handleHotChainingCell(CompilationUnit *cUnit,
3524                                   unsigned int offset)
3525 {
3526     /*
3527      * Use raw instruction constructors to guarantee that the generated
3528      * instructions fit the predefined cell size.
3529      */
3530     insertChainingSwitch(cUnit);
3531     newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
3532             offsetof(InterpState,
3533                      jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2);
3534     newLIR1(cUnit, kThumbBlxR, r0);
3535     addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3536 }
3537 
3538 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
3539 /* Chaining cell for branches that branch back into the same basic block */
handleBackwardBranchChainingCell(CompilationUnit * cUnit,unsigned int offset)3540 static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3541                                              unsigned int offset)
3542 {
3543     /*
3544      * Use raw instruction constructors to guarantee that the generated
3545      * instructions fit the predefined cell size.
3546      */
3547     insertChainingSwitch(cUnit);
3548 #if defined(WITH_SELF_VERIFICATION)
3549     newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
3550         offsetof(InterpState,
3551                  jitToInterpEntries.dvmJitToInterpBackwardBranch) >> 2);
3552 #else
3553     newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
3554         offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3555 #endif
3556     newLIR1(cUnit, kThumbBlxR, r0);
3557     addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3558 }
3559 
3560 #endif
3561 /* Chaining cell for monomorphic method invocations. */
handleInvokeSingletonChainingCell(CompilationUnit * cUnit,const Method * callee)3562 static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3563                                               const Method *callee)
3564 {
3565     /*
3566      * Use raw instruction constructors to guarantee that the generated
3567      * instructions fit the predefined cell size.
3568      */
3569     insertChainingSwitch(cUnit);
3570     newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
3571             offsetof(InterpState,
3572                      jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2);
3573     newLIR1(cUnit, kThumbBlxR, r0);
3574     addWordData(cUnit, (int) (callee->insns), true);
3575 }
3576 
3577 /* Chaining cell for monomorphic method invocations. */
handleInvokePredictedChainingCell(CompilationUnit * cUnit)3578 static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3579 {
3580 
3581     /* Should not be executed in the initial state */
3582     addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3583     /* To be filled: class */
3584     addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3585     /* To be filled: method */
3586     addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3587     /*
3588      * Rechain count. The initial value of 0 here will trigger chaining upon
3589      * the first invocation of this callsite.
3590      */
3591     addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3592 }
3593 
3594 /* Load the Dalvik PC into r0 and jump to the specified target */
handlePCReconstruction(CompilationUnit * cUnit,ArmLIR * targetLabel)3595 static void handlePCReconstruction(CompilationUnit *cUnit,
3596                                    ArmLIR *targetLabel)
3597 {
3598     ArmLIR **pcrLabel =
3599         (ArmLIR **) cUnit->pcReconstructionList.elemList;
3600     int numElems = cUnit->pcReconstructionList.numUsed;
3601     int i;
3602     for (i = 0; i < numElems; i++) {
3603         dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3604         /* r0 = dalvik PC */
3605         loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3606         genUnconditionalBranch(cUnit, targetLabel);
3607     }
3608 }
3609 
3610 static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
3611     "kMirOpPhi",
3612     "kMirOpNullNRangeUpCheck",
3613     "kMirOpNullNRangeDownCheck",
3614     "kMirOpLowerBound",
3615     "kMirOpPunt",
3616     "kMirOpCheckInlinePrediction",
3617 };
3618 
3619 /*
3620  * vA = arrayReg;
3621  * vB = idxReg;
3622  * vC = endConditionReg;
3623  * arg[0] = maxC
3624  * arg[1] = minC
3625  * arg[2] = loopBranchConditionCode
3626  */
genHoistedChecksForCountUpLoop(CompilationUnit * cUnit,MIR * mir)3627 static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3628 {
3629     /*
3630      * NOTE: these synthesized blocks don't have ssa names assigned
3631      * for Dalvik registers.  However, because they dominate the following
3632      * blocks we can simply use the Dalvik name w/ subscript 0 as the
3633      * ssa name.
3634      */
3635     DecodedInstruction *dInsn = &mir->dalvikInsn;
3636     const int lenOffset = offsetof(ArrayObject, length);
3637     const int maxC = dInsn->arg[0];
3638     int regLength;
3639     RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3640     RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
3641 
3642     /* regArray <- arrayRef */
3643     rlArray = loadValue(cUnit, rlArray, kCoreReg);
3644     rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
3645     genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
3646                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3647 
3648     /* regLength <- len(arrayRef) */
3649     regLength = dvmCompilerAllocTemp(cUnit);
3650     loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
3651 
3652     int delta = maxC;
3653     /*
3654      * If the loop end condition is ">=" instead of ">", then the largest value
3655      * of the index is "endCondition - 1".
3656      */
3657     if (dInsn->arg[2] == OP_IF_GE) {
3658         delta--;
3659     }
3660 
3661     if (delta) {
3662         int tReg = dvmCompilerAllocTemp(cUnit);
3663         opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
3664         rlIdxEnd.lowReg = tReg;
3665         dvmCompilerFreeTemp(cUnit, tReg);
3666     }
3667     /* Punt if "regIdxEnd < len(Array)" is false */
3668     genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
3669                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3670 }
3671 
3672 /*
3673  * vA = arrayReg;
3674  * vB = idxReg;
3675  * vC = endConditionReg;
3676  * arg[0] = maxC
3677  * arg[1] = minC
3678  * arg[2] = loopBranchConditionCode
3679  */
genHoistedChecksForCountDownLoop(CompilationUnit * cUnit,MIR * mir)3680 static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3681 {
3682     DecodedInstruction *dInsn = &mir->dalvikInsn;
3683     const int lenOffset = offsetof(ArrayObject, length);
3684     const int regLength = dvmCompilerAllocTemp(cUnit);
3685     const int maxC = dInsn->arg[0];
3686     RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3687     RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
3688 
3689     /* regArray <- arrayRef */
3690     rlArray = loadValue(cUnit, rlArray, kCoreReg);
3691     rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
3692     genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
3693                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3694 
3695     /* regLength <- len(arrayRef) */
3696     loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
3697 
3698     if (maxC) {
3699         int tReg = dvmCompilerAllocTemp(cUnit);
3700         opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
3701         rlIdxInit.lowReg = tReg;
3702         dvmCompilerFreeTemp(cUnit, tReg);
3703     }
3704 
3705     /* Punt if "regIdxInit < len(Array)" is false */
3706     genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
3707                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3708 }
3709 
3710 /*
3711  * vA = idxReg;
3712  * vB = minC;
3713  */
genHoistedLowerBoundCheck(CompilationUnit * cUnit,MIR * mir)3714 static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3715 {
3716     DecodedInstruction *dInsn = &mir->dalvikInsn;
3717     const int minC = dInsn->vB;
3718     RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
3719 
3720     /* regIdx <- initial index value */
3721     rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
3722 
3723     /* Punt if "regIdxInit + minC >= 0" is false */
3724     genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
3725                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3726 }
3727 
3728 /*
3729  * vC = this
3730  *
3731  * A predicted inlining target looks like the following, where instructions
3732  * between 0x4858de66 and 0x4858de72 are checking if the predicted class
3733  * matches "this", and the verificaion code is generated by this routine.
3734  *
3735  * (C) means the instruction is inlined from the callee, and (PI) means the
3736  * instruction is the predicted inlined invoke, whose corresponding
3737  * instructions are still generated to handle the mispredicted case.
3738  *
3739  * D/dalvikvm(   86): -------- kMirOpCheckInlinePrediction
3740  * D/dalvikvm(   86): 0x4858de66 (0002): ldr     r0, [r5, #68]
3741  * D/dalvikvm(   86): 0x4858de68 (0004): ldr     r1, [pc, #140]
3742  * D/dalvikvm(   86): 0x4858de6a (0006): cmp     r0, #0
3743  * D/dalvikvm(   86): 0x4858de6c (0008): beq     0x4858deb2
3744  * D/dalvikvm(   86): 0x4858de6e (000a): ldr     r2, [r0, #0]
3745  * D/dalvikvm(   86): 0x4858de70 (000c): cmp     r1, r2
3746  * D/dalvikvm(   86): 0x4858de72 (000e): bne     0x4858de7a
3747  * D/dalvikvm(   86): -------- dalvik offset: 0x004c @ +iget-object-quick (C)
3748  * v4, v17, (#8)
3749  * D/dalvikvm(   86): 0x4858de74 (0010): ldr     r3, [r0, #8]
3750  * D/dalvikvm(   86): 0x4858de76 (0012): str     r3, [r5, #16]
3751  * D/dalvikvm(   86): -------- dalvik offset: 0x004c @
3752  * +invoke-virtual-quick/range (PI) v17..v17
3753  * D/dalvikvm(   86): 0x4858de78 (0014): b       0x4858debc
3754  * D/dalvikvm(   86): 0x4858de7a (0016): add     r4,r5,#68
3755  * D/dalvikvm(   86): -------- BARRIER
3756  * D/dalvikvm(   86): 0x4858de7e (001a): ldmia   r4, <r0>
3757  * D/dalvikvm(   86): -------- BARRIER
3758  * D/dalvikvm(   86): 0x4858de80 (001c): sub     r7,r5,#24
3759  * D/dalvikvm(   86): 0x4858de84 (0020): cmp     r0, #0
3760  * D/dalvikvm(   86): 0x4858de86 (0022): beq     0x4858deb6
3761  * D/dalvikvm(   86): -------- BARRIER
3762  * D/dalvikvm(   86): 0x4858de88 (0024): stmia   r7, <r0>
3763  * D/dalvikvm(   86): -------- BARRIER
3764  * D/dalvikvm(   86): 0x4858de8a (0026): ldr     r4, [pc, #104]
3765  * D/dalvikvm(   86): 0x4858de8c (0028): add     r1, pc, #28
3766  * D/dalvikvm(   86): 0x4858de8e (002a): add     r2, pc, #56
3767  * D/dalvikvm(   86): 0x4858de90 (002c): blx_1   0x48589198
3768  * D/dalvikvm(   86): 0x4858de92 (002e): blx_2   see above
3769  * D/dalvikvm(   86): 0x4858de94 (0030): b       0x4858dec8
3770  * D/dalvikvm(   86): 0x4858de96 (0032): b       0x4858deb6
3771  * D/dalvikvm(   86): 0x4858de98 (0034): ldr     r0, [r7, #72]
3772  * D/dalvikvm(   86): 0x4858de9a (0036): cmp     r1, #0
3773  * D/dalvikvm(   86): 0x4858de9c (0038): bgt     0x4858dea4
3774  * D/dalvikvm(   86): 0x4858de9e (003a): ldr     r7, [r6, #116]
3775  * D/dalvikvm(   86): 0x4858dea0 (003c): movs    r1, r6
3776  * D/dalvikvm(   86): 0x4858dea2 (003e): blx     r7
3777  * D/dalvikvm(   86): 0x4858dea4 (0040): add     r1, pc, #4
3778  * D/dalvikvm(   86): 0x4858dea6 (0042): blx_1   0x485890a0
3779  * D/dalvikvm(   86): 0x4858dea8 (0044): blx_2   see above
3780  * D/dalvikvm(   86): 0x4858deaa (0046): b       0x4858deb6
3781  * D/dalvikvm(   86): 0x4858deac (0048): .align4
3782  * D/dalvikvm(   86): L0x004f:
3783  * D/dalvikvm(   86): -------- dalvik offset: 0x004f @ move-result-object (PI)
3784  * v4, (#0), (#0)
3785  * D/dalvikvm(   86): 0x4858deac (0048): ldr     r4, [r6, #8]
3786  * D/dalvikvm(   86): 0x4858deae (004a): str     r4, [r5, #16]
3787  * D/dalvikvm(   86): 0x4858deb0 (004c): b       0x4858debc
3788  * D/dalvikvm(   86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
3789  * D/dalvikvm(   86): 0x4858deb2 (004e): ldr     r0, [pc, #64]
3790  * D/dalvikvm(   86): 0x4858deb4 (0050): b       0x4858deb8
3791  * D/dalvikvm(   86): -------- reconstruct dalvik PC : 0x42beefcc @ +0x004c
3792  * D/dalvikvm(   86): 0x4858deb6 (0052): ldr     r0, [pc, #60]
3793  * D/dalvikvm(   86): Exception_Handling:
3794  * D/dalvikvm(   86): 0x4858deb8 (0054): ldr     r1, [r6, #100]
3795  * D/dalvikvm(   86): 0x4858deba (0056): blx     r1
3796  * D/dalvikvm(   86): 0x4858debc (0058): .align4
3797  * D/dalvikvm(   86): -------- chaining cell (hot): 0x0050
3798  * D/dalvikvm(   86): 0x4858debc (0058): b       0x4858dec0
3799  * D/dalvikvm(   86): 0x4858debe (005a): orrs    r0, r0
3800  * D/dalvikvm(   86): 0x4858dec0 (005c): ldr     r0, [r6, #112]
3801  * D/dalvikvm(   86): 0x4858dec2 (005e): blx     r0
3802  * D/dalvikvm(   86): 0x4858dec4 (0060): data    0xefd4(61396)
3803  * D/dalvikvm(   86): 0x4858dec6 (0062): data    0x42be(17086)
3804  * D/dalvikvm(   86): 0x4858dec8 (0064): .align4
3805  * D/dalvikvm(   86): -------- chaining cell (predicted)
3806  * D/dalvikvm(   86): 0x4858dec8 (0064): data    0xe7fe(59390)
3807  * D/dalvikvm(   86): 0x4858deca (0066): data    0x0000(0)
3808  * D/dalvikvm(   86): 0x4858decc (0068): data    0x0000(0)
3809  * D/dalvikvm(   86): 0x4858dece (006a): data    0x0000(0)
3810  * :
3811  */
genValidationForPredictedInline(CompilationUnit * cUnit,MIR * mir)3812 static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir)
3813 {
3814     CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
3815     RegLocation rlThis = cUnit->regLocation[mir->dalvikInsn.vC];
3816 
3817     rlThis = loadValue(cUnit, rlThis, kCoreReg);
3818     int regPredictedClass = dvmCompilerAllocTemp(cUnit);
3819     loadConstant(cUnit, regPredictedClass, (int) callsiteInfo->clazz);
3820     genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset,
3821                  NULL);/* null object? */
3822     int regActualClass = dvmCompilerAllocTemp(cUnit);
3823     loadWordDisp(cUnit, rlThis.lowReg, offsetof(Object, clazz), regActualClass);
3824     opRegReg(cUnit, kOpCmp, regPredictedClass, regActualClass);
3825     /*
3826      * Set the misPredBranchOver target so that it will be generated when the
3827      * code for the non-optimized invoke is generated.
3828      */
3829     callsiteInfo->misPredBranchOver = (LIR *) opCondBranch(cUnit, kArmCondNe);
3830 }
3831 
3832 /* Extended MIR instructions like PHI */
handleExtendedMIR(CompilationUnit * cUnit,MIR * mir)3833 static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3834 {
3835     int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
3836     char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3837                                false);
3838     strcpy(msg, extendedMIROpNames[opOffset]);
3839     newLIR1(cUnit, kArmPseudoExtended, (int) msg);
3840 
3841     switch (mir->dalvikInsn.opCode) {
3842         case kMirOpPhi: {
3843             char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3844             newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
3845             break;
3846         }
3847         case kMirOpNullNRangeUpCheck: {
3848             genHoistedChecksForCountUpLoop(cUnit, mir);
3849             break;
3850         }
3851         case kMirOpNullNRangeDownCheck: {
3852             genHoistedChecksForCountDownLoop(cUnit, mir);
3853             break;
3854         }
3855         case kMirOpLowerBound: {
3856             genHoistedLowerBoundCheck(cUnit, mir);
3857             break;
3858         }
3859         case kMirOpPunt: {
3860             genUnconditionalBranch(cUnit,
3861                                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3862             break;
3863         }
3864         case kMirOpCheckInlinePrediction: {
3865             genValidationForPredictedInline(cUnit, mir);
3866             break;
3867         }
3868         default:
3869             break;
3870     }
3871 }
3872 
3873 /*
3874  * Create a PC-reconstruction cell for the starting offset of this trace.
3875  * Since the PCR cell is placed near the end of the compiled code which is
3876  * usually out of range for a conditional branch, we put two branches (one
3877  * branch over to the loop body and one layover branch to the actual PCR) at the
3878  * end of the entry block.
3879  */
setupLoopEntryBlock(CompilationUnit * cUnit,BasicBlock * entry,ArmLIR * bodyLabel)3880 static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3881                                 ArmLIR *bodyLabel)
3882 {
3883     /* Set up the place holder to reconstruct this Dalvik PC */
3884     ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3885     pcrLabel->opCode = kArmPseudoPCReconstructionCell;
3886     pcrLabel->operands[0] =
3887         (int) (cUnit->method->insns + entry->startOffset);
3888     pcrLabel->operands[1] = entry->startOffset;
3889     /* Insert the place holder to the growable list */
3890     dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3891 
3892     /*
3893      * Next, create two branches - one branch over to the loop body and the
3894      * other branch to the PCR cell to punt.
3895      */
3896     ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
3897     branchToBody->opCode = kThumbBUncond;
3898     branchToBody->generic.target = (LIR *) bodyLabel;
3899     setupResourceMasks(branchToBody);
3900     cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3901 
3902     ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
3903     branchToPCR->opCode = kThumbBUncond;
3904     branchToPCR->generic.target = (LIR *) pcrLabel;
3905     setupResourceMasks(branchToPCR);
3906     cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3907 }
3908 
3909 #if defined(WITH_SELF_VERIFICATION)
selfVerificationPuntOps(MIR * mir)3910 static bool selfVerificationPuntOps(MIR *mir)
3911 {
3912     DecodedInstruction *decInsn = &mir->dalvikInsn;
3913     OpCode op = decInsn->opCode;
3914 
3915     /*
3916      * All opcodes that can throw exceptions and use the
3917      * TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace
3918      * under self-verification mode.
3919      */
3920     return (op == OP_MONITOR_ENTER || op == OP_MONITOR_EXIT ||
3921             op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY ||
3922             op == OP_CHECK_CAST || op == OP_MOVE_EXCEPTION ||
3923             op == OP_FILL_ARRAY_DATA || op == OP_EXECUTE_INLINE ||
3924             op == OP_EXECUTE_INLINE_RANGE);
3925 }
3926 #endif
3927 
dvmCompilerMIR2LIR(CompilationUnit * cUnit)3928 void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3929 {
3930     /* Used to hold the labels of each block */
3931     ArmLIR *labelList =
3932         dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
3933     GrowableList chainingListByType[kChainingCellGap];
3934     int i;
3935 
3936     /*
3937      * Initialize various types chaining lists.
3938      */
3939     for (i = 0; i < kChainingCellGap; i++) {
3940         dvmInitGrowableList(&chainingListByType[i], 2);
3941     }
3942 
3943     BasicBlock **blockList = cUnit->blockList;
3944 
3945     if (cUnit->executionCount) {
3946         /*
3947          * Reserve 6 bytes at the beginning of the trace
3948          *        +----------------------------+
3949          *        | execution count (4 bytes)  |
3950          *        +----------------------------+
3951          *        | chain cell offset (2 bytes)|
3952          *        +----------------------------+
3953          * ...and then code to increment the execution
3954          * count:
3955          *       mov   r0, pc       @ move adr of "mov r0,pc" + 4 to r0
3956          *       sub   r0, #10      @ back up to addr of executionCount
3957          *       ldr   r1, [r0]
3958          *       add   r1, #1
3959          *       str   r1, [r0]
3960          */
3961         newLIR1(cUnit, kArm16BitData, 0);
3962         newLIR1(cUnit, kArm16BitData, 0);
3963         cUnit->chainCellOffsetLIR =
3964             (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
3965         cUnit->headerSize = 6;
3966         /* Thumb instruction used directly here to ensure correct size */
3967         newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc);
3968         newLIR2(cUnit, kThumbSubRI8, r0, 10);
3969         newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
3970         newLIR2(cUnit, kThumbAddRI8, r1, 1);
3971         newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
3972     } else {
3973          /* Just reserve 2 bytes for the chain cell offset */
3974         cUnit->chainCellOffsetLIR =
3975             (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
3976         cUnit->headerSize = 2;
3977     }
3978 
3979     /* Handle the content in each basic block */
3980     for (i = 0; i < cUnit->numBlocks; i++) {
3981         blockList[i]->visited = true;
3982         MIR *mir;
3983 
3984         labelList[i].operands[0] = blockList[i]->startOffset;
3985 
3986         if (blockList[i]->blockType >= kChainingCellGap) {
3987             if (blockList[i]->isFallThroughFromInvoke == true) {
3988                 /* Align this block first since it is a return chaining cell */
3989                 newLIR0(cUnit, kArmPseudoPseudoAlign4);
3990             }
3991             /*
3992              * Append the label pseudo LIR first. Chaining cells will be handled
3993              * separately afterwards.
3994              */
3995             dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3996         }
3997 
3998         if (blockList[i]->blockType == kTraceEntryBlock) {
3999             labelList[i].opCode = kArmPseudoEntryBlock;
4000             if (blockList[i]->firstMIRInsn == NULL) {
4001                 continue;
4002             } else {
4003               setupLoopEntryBlock(cUnit, blockList[i],
4004                                   &labelList[blockList[i]->fallThrough->id]);
4005             }
4006         } else if (blockList[i]->blockType == kTraceExitBlock) {
4007             labelList[i].opCode = kArmPseudoExitBlock;
4008             goto gen_fallthrough;
4009         } else if (blockList[i]->blockType == kDalvikByteCode) {
4010             labelList[i].opCode = kArmPseudoNormalBlockLabel;
4011             /* Reset the register state */
4012             dvmCompilerResetRegPool(cUnit);
4013             dvmCompilerClobberAllRegs(cUnit);
4014             dvmCompilerResetNullCheck(cUnit);
4015         } else {
4016             switch (blockList[i]->blockType) {
4017                 case kChainingCellNormal:
4018                     labelList[i].opCode = kArmPseudoChainingCellNormal;
4019                     /* handle the codegen later */
4020                     dvmInsertGrowableList(
4021                         &chainingListByType[kChainingCellNormal], (void *) i);
4022                     break;
4023                 case kChainingCellInvokeSingleton:
4024                     labelList[i].opCode =
4025                         kArmPseudoChainingCellInvokeSingleton;
4026                     labelList[i].operands[0] =
4027                         (int) blockList[i]->containingMethod;
4028                     /* handle the codegen later */
4029                     dvmInsertGrowableList(
4030                         &chainingListByType[kChainingCellInvokeSingleton],
4031                         (void *) i);
4032                     break;
4033                 case kChainingCellInvokePredicted:
4034                     labelList[i].opCode =
4035                         kArmPseudoChainingCellInvokePredicted;
4036                     /* handle the codegen later */
4037                     dvmInsertGrowableList(
4038                         &chainingListByType[kChainingCellInvokePredicted],
4039                         (void *) i);
4040                     break;
4041                 case kChainingCellHot:
4042                     labelList[i].opCode =
4043                         kArmPseudoChainingCellHot;
4044                     /* handle the codegen later */
4045                     dvmInsertGrowableList(
4046                         &chainingListByType[kChainingCellHot],
4047                         (void *) i);
4048                     break;
4049                 case kPCReconstruction:
4050                     /* Make sure exception handling block is next */
4051                     labelList[i].opCode =
4052                         kArmPseudoPCReconstructionBlockLabel;
4053                     assert (i == cUnit->numBlocks - 2);
4054                     handlePCReconstruction(cUnit, &labelList[i+1]);
4055                     break;
4056                 case kExceptionHandling:
4057                     labelList[i].opCode = kArmPseudoEHBlockLabel;
4058                     if (cUnit->pcReconstructionList.numUsed) {
4059                         loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4060                                      jitToInterpEntries.dvmJitToInterpPunt),
4061                                      r1);
4062                         opReg(cUnit, kOpBlx, r1);
4063                     }
4064                     break;
4065 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
4066                 case kChainingCellBackwardBranch:
4067                     labelList[i].opCode =
4068                         kArmPseudoChainingCellBackwardBranch;
4069                     /* handle the codegen later */
4070                     dvmInsertGrowableList(
4071                         &chainingListByType[kChainingCellBackwardBranch],
4072                         (void *) i);
4073                     break;
4074 #endif
4075                 default:
4076                     break;
4077             }
4078             continue;
4079         }
4080 
4081         ArmLIR *headLIR = NULL;
4082 
4083         for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
4084 
4085             dvmCompilerResetRegPool(cUnit);
4086             if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
4087                 dvmCompilerClobberAllRegs(cUnit);
4088             }
4089 
4090             if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
4091                 dvmCompilerResetDefTracking(cUnit);
4092             }
4093 
4094             if (mir->dalvikInsn.opCode >= kMirOpFirst) {
4095                 handleExtendedMIR(cUnit, mir);
4096                 continue;
4097             }
4098 
4099 
4100             OpCode dalvikOpCode = mir->dalvikInsn.opCode;
4101             InstructionFormat dalvikFormat =
4102                 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
4103             char *note;
4104             if (mir->OptimizationFlags & MIR_INLINED) {
4105                 note = " (I)";
4106             } else if (mir->OptimizationFlags & MIR_INLINED_PRED) {
4107                 note = " (PI)";
4108             } else if (mir->OptimizationFlags & MIR_CALLEE) {
4109                 note = " (C)";
4110             } else {
4111                 note = NULL;
4112             }
4113 
4114             ArmLIR *boundaryLIR =
4115                 newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary,
4116                         mir->offset,
4117                         (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn,
4118                                                               note));
4119             if (mir->ssaRep) {
4120                 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
4121                 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
4122             }
4123 
4124             /* Remember the first LIR for this block */
4125             if (headLIR == NULL) {
4126                 headLIR = boundaryLIR;
4127                 /* Set the first boundaryLIR as a scheduling barrier */
4128                 headLIR->defMask = ENCODE_ALL;
4129             }
4130 
4131             bool notHandled;
4132             /*
4133              * Debugging: screen the opcode first to see if it is in the
4134              * do[-not]-compile list
4135              */
4136             bool singleStepMe = SINGLE_STEP_OP(dalvikOpCode);
4137 #if defined(WITH_SELF_VERIFICATION)
4138           if (singleStepMe == false) {
4139               singleStepMe = selfVerificationPuntOps(mir);
4140           }
4141 #endif
4142             if (singleStepMe || cUnit->allSingleStep) {
4143                 notHandled = false;
4144                 genInterpSingleStep(cUnit, mir);
4145             } else {
4146                 opcodeCoverage[dalvikOpCode]++;
4147                 switch (dalvikFormat) {
4148                     case kFmt10t:
4149                     case kFmt20t:
4150                     case kFmt30t:
4151                         notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
4152                                   mir, blockList[i], labelList);
4153                         break;
4154                     case kFmt10x:
4155                         notHandled = handleFmt10x(cUnit, mir);
4156                         break;
4157                     case kFmt11n:
4158                     case kFmt31i:
4159                         notHandled = handleFmt11n_Fmt31i(cUnit, mir);
4160                         break;
4161                     case kFmt11x:
4162                         notHandled = handleFmt11x(cUnit, mir);
4163                         break;
4164                     case kFmt12x:
4165                         notHandled = handleFmt12x(cUnit, mir);
4166                         break;
4167                     case kFmt20bc:
4168                         notHandled = handleFmt20bc(cUnit, mir);
4169                         break;
4170                     case kFmt21c:
4171                     case kFmt31c:
4172                         notHandled = handleFmt21c_Fmt31c(cUnit, mir);
4173                         break;
4174                     case kFmt21h:
4175                         notHandled = handleFmt21h(cUnit, mir);
4176                         break;
4177                     case kFmt21s:
4178                         notHandled = handleFmt21s(cUnit, mir);
4179                         break;
4180                     case kFmt21t:
4181                         notHandled = handleFmt21t(cUnit, mir, blockList[i],
4182                                                   labelList);
4183                         break;
4184                     case kFmt22b:
4185                     case kFmt22s:
4186                         notHandled = handleFmt22b_Fmt22s(cUnit, mir);
4187                         break;
4188                     case kFmt22c:
4189                         notHandled = handleFmt22c(cUnit, mir);
4190                         break;
4191                     case kFmt22cs:
4192                         notHandled = handleFmt22cs(cUnit, mir);
4193                         break;
4194                     case kFmt22t:
4195                         notHandled = handleFmt22t(cUnit, mir, blockList[i],
4196                                                   labelList);
4197                         break;
4198                     case kFmt22x:
4199                     case kFmt32x:
4200                         notHandled = handleFmt22x_Fmt32x(cUnit, mir);
4201                         break;
4202                     case kFmt23x:
4203                         notHandled = handleFmt23x(cUnit, mir);
4204                         break;
4205                     case kFmt31t:
4206                         notHandled = handleFmt31t(cUnit, mir);
4207                         break;
4208                     case kFmt3rc:
4209                     case kFmt35c:
4210                         notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
4211                                                       labelList);
4212                         break;
4213                     case kFmt3rms:
4214                     case kFmt35ms:
4215                         notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
4216                                                         labelList);
4217                         break;
4218                     case kFmt3inline:
4219                     case kFmt3rinline:
4220                         notHandled = handleExecuteInline(cUnit, mir);
4221                         break;
4222                     case kFmt51l:
4223                         notHandled = handleFmt51l(cUnit, mir);
4224                         break;
4225                     default:
4226                         notHandled = true;
4227                         break;
4228                 }
4229             }
4230             if (notHandled) {
4231                 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
4232                      mir->offset,
4233                      dalvikOpCode, dexGetOpcodeName(dalvikOpCode),
4234                      dalvikFormat);
4235                 dvmCompilerAbort(cUnit);
4236                 break;
4237             }
4238         }
4239 
4240         if (blockList[i]->blockType == kTraceEntryBlock) {
4241             dvmCompilerAppendLIR(cUnit,
4242                                  (LIR *) cUnit->loopAnalysis->branchToBody);
4243             dvmCompilerAppendLIR(cUnit,
4244                                  (LIR *) cUnit->loopAnalysis->branchToPCR);
4245         }
4246 
4247         if (headLIR) {
4248             /*
4249              * Eliminate redundant loads/stores and delay stores into later
4250              * slots
4251              */
4252             dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4253                                                cUnit->lastLIRInsn);
4254         }
4255 
4256 gen_fallthrough:
4257         /*
4258          * Check if the block is terminated due to trace length constraint -
4259          * insert an unconditional branch to the chaining cell.
4260          */
4261         if (blockList[i]->needFallThroughBranch) {
4262             genUnconditionalBranch(cUnit,
4263                                    &labelList[blockList[i]->fallThrough->id]);
4264         }
4265 
4266     }
4267 
4268     /* Handle the chaining cells in predefined order */
4269     for (i = 0; i < kChainingCellGap; i++) {
4270         size_t j;
4271         int *blockIdList = (int *) chainingListByType[i].elemList;
4272 
4273         cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4274 
4275         /* No chaining cells of this type */
4276         if (cUnit->numChainingCells[i] == 0)
4277             continue;
4278 
4279         /* Record the first LIR for a new type of chaining cell */
4280         cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4281 
4282         for (j = 0; j < chainingListByType[i].numUsed; j++) {
4283             int blockId = blockIdList[j];
4284 
4285             /* Align this chaining cell first */
4286             newLIR0(cUnit, kArmPseudoPseudoAlign4);
4287 
4288             /* Insert the pseudo chaining instruction */
4289             dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4290 
4291 
4292             switch (blockList[blockId]->blockType) {
4293                 case kChainingCellNormal:
4294                     handleNormalChainingCell(cUnit,
4295                       blockList[blockId]->startOffset);
4296                     break;
4297                 case kChainingCellInvokeSingleton:
4298                     handleInvokeSingletonChainingCell(cUnit,
4299                         blockList[blockId]->containingMethod);
4300                     break;
4301                 case kChainingCellInvokePredicted:
4302                     handleInvokePredictedChainingCell(cUnit);
4303                     break;
4304                 case kChainingCellHot:
4305                     handleHotChainingCell(cUnit,
4306                         blockList[blockId]->startOffset);
4307                     break;
4308 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
4309                 case kChainingCellBackwardBranch:
4310                     handleBackwardBranchChainingCell(cUnit,
4311                         blockList[blockId]->startOffset);
4312                     break;
4313 #endif
4314                 default:
4315                     LOGE("Bad blocktype %d", blockList[blockId]->blockType);
4316                     dvmCompilerAbort(cUnit);
4317             }
4318         }
4319     }
4320 
4321     /* Mark the bottom of chaining cells */
4322     cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kArmChainingCellBottom);
4323 
4324     /*
4325      * Generate the branch to the dvmJitToInterpNoChain entry point at the end
4326      * of all chaining cells for the overflow cases.
4327      */
4328     if (cUnit->switchOverflowPad) {
4329         loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad);
4330         loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4331                      jitToInterpEntries.dvmJitToInterpNoChain), r2);
4332         opRegReg(cUnit, kOpAdd, r1, r1);
4333         opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
4334 #if defined(WITH_JIT_TUNING)
4335         loadConstant(cUnit, r0, kSwitchOverflow);
4336 #endif
4337         opReg(cUnit, kOpBlx, r2);
4338     }
4339 
4340     dvmCompilerApplyGlobalOptimizations(cUnit);
4341 
4342 #if defined(WITH_SELF_VERIFICATION)
4343     selfVerificationBranchInsertPass(cUnit);
4344 #endif
4345 }
4346 
4347 /* Accept the work and start compiling */
dvmCompilerDoWork(CompilerWorkOrder * work)4348 bool dvmCompilerDoWork(CompilerWorkOrder *work)
4349 {
4350     bool res;
4351 
4352     if (gDvmJit.codeCacheFull) {
4353         return false;
4354     }
4355 
4356     switch (work->kind) {
4357         case kWorkOrderTrace:
4358             /* Start compilation with maximally allowed trace length */
4359             res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
4360                                   work->bailPtr, 0 /* no hints */);
4361             break;
4362         case kWorkOrderTraceDebug: {
4363             bool oldPrintMe = gDvmJit.printMe;
4364             gDvmJit.printMe = true;
4365             /* Start compilation with maximally allowed trace length */
4366             res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
4367                                   work->bailPtr, 0 /* no hints */);
4368             gDvmJit.printMe = oldPrintMe;
4369             break;
4370         }
4371         default:
4372             res = false;
4373             LOGE("Jit: unknown work order type");
4374             assert(0);  // Bail if debug build, discard otherwise
4375     }
4376     return res;
4377 }
4378 
4379 /* Architectural-specific debugging helpers go here */
dvmCompilerArchDump(void)4380 void dvmCompilerArchDump(void)
4381 {
4382     /* Print compiled opcode in this VM instance */
4383     int i, start, streak;
4384     char buf[1024];
4385 
4386     streak = i = 0;
4387     buf[0] = 0;
4388     while (opcodeCoverage[i] == 0 && i < 256) {
4389         i++;
4390     }
4391     if (i == 256) {
4392         return;
4393     }
4394     for (start = i++, streak = 1; i < 256; i++) {
4395         if (opcodeCoverage[i]) {
4396             streak++;
4397         } else {
4398             if (streak == 1) {
4399                 sprintf(buf+strlen(buf), "%x,", start);
4400             } else {
4401                 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4402             }
4403             streak = 0;
4404             while (opcodeCoverage[i] == 0 && i < 256) {
4405                 i++;
4406             }
4407             if (i < 256) {
4408                 streak = 1;
4409                 start = i;
4410             }
4411         }
4412     }
4413     if (streak) {
4414         if (streak == 1) {
4415             sprintf(buf+strlen(buf), "%x", start);
4416         } else {
4417             sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4418         }
4419     }
4420     if (strlen(buf)) {
4421         LOGD("dalvik.vm.jit.op = %s", buf);
4422     }
4423 }
4424 
4425 /* Common initialization routine for an architecture family */
dvmCompilerArchInit()4426 bool dvmCompilerArchInit()
4427 {
4428     int i;
4429 
4430     for (i = 0; i < kArmLast; i++) {
4431         if (EncodingMap[i].opCode != i) {
4432             LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
4433                  EncodingMap[i].name, i, EncodingMap[i].opCode);
4434             dvmAbort();  // OK to dvmAbort - build error
4435         }
4436     }
4437 
4438     return dvmCompilerArchVariantInit();
4439 }
4440 
dvmCompilerGetInterpretTemplate()4441 void *dvmCompilerGetInterpretTemplate()
4442 {
4443       return (void*) ((int)gDvmJit.codeCache +
4444                       templateEntryOffsets[TEMPLATE_INTERPRET]);
4445 }
4446 
4447 /* Needed by the Assembler */
dvmCompilerSetupResourceMasks(ArmLIR * lir)4448 void dvmCompilerSetupResourceMasks(ArmLIR *lir)
4449 {
4450     setupResourceMasks(lir);
4451 }
4452 
4453 /* Needed by the ld/st optmizatons */
dvmCompilerRegCopyNoInsert(CompilationUnit * cUnit,int rDest,int rSrc)4454 ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
4455 {
4456     return genRegCopyNoInsert(cUnit, rDest, rSrc);
4457 }
4458 
4459 /* Needed by the register allocator */
dvmCompilerRegCopy(CompilationUnit * cUnit,int rDest,int rSrc)4460 ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
4461 {
4462     return genRegCopy(cUnit, rDest, rSrc);
4463 }
4464 
4465 /* Needed by the register allocator */
dvmCompilerRegCopyWide(CompilationUnit * cUnit,int destLo,int destHi,int srcLo,int srcHi)4466 void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
4467                             int srcLo, int srcHi)
4468 {
4469     genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
4470 }
4471 
dvmCompilerFlushRegImpl(CompilationUnit * cUnit,int rBase,int displacement,int rSrc,OpSize size)4472 void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
4473                              int displacement, int rSrc, OpSize size)
4474 {
4475     storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
4476 }
4477 
dvmCompilerFlushRegWideImpl(CompilationUnit * cUnit,int rBase,int displacement,int rSrcLo,int rSrcHi)4478 void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
4479                                  int displacement, int rSrcLo, int rSrcHi)
4480 {
4481     storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
4482 }
4483