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