2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * This file contains codegen and support common to all supported
19 * ARM variants. It is included by:
21 * Codegen-$(TARGET_ARCH_VARIANT).c
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
27 static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
28 int srcSize, int tgtSize)
31 * Don't optimize the register usage since it calls out to template
36 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
38 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
39 loadValueDirectFixed(cUnit, rlSrc, r0);
41 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
42 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
44 loadConstant(cUnit, r2, (int)funct);
45 opReg(cUnit, kOpBlx, r2);
46 dvmCompilerClobberCallRegs(cUnit);
49 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
50 rlResult = dvmCompilerGetReturn(cUnit);
51 storeValue(cUnit, rlDest, rlResult);
54 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
55 rlResult = dvmCompilerGetReturnWide(cUnit);
56 storeValueWide(cUnit, rlDest, rlResult);
62 static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
63 RegLocation rlDest, RegLocation rlSrc1,
69 /* TODO: use a proper include file to define these */
70 float __aeabi_fadd(float a, float b);
71 float __aeabi_fsub(float a, float b);
72 float __aeabi_fdiv(float a, float b);
73 float __aeabi_fmul(float a, float b);
74 float fmodf(float a, float b);
76 switch (mir->dalvikInsn.opCode) {
77 case OP_ADD_FLOAT_2ADDR:
79 funct = (void*) __aeabi_fadd;
81 case OP_SUB_FLOAT_2ADDR:
83 funct = (void*) __aeabi_fsub;
85 case OP_DIV_FLOAT_2ADDR:
87 funct = (void*) __aeabi_fdiv;
89 case OP_MUL_FLOAT_2ADDR:
91 funct = (void*) __aeabi_fmul;
93 case OP_REM_FLOAT_2ADDR:
95 funct = (void*) fmodf;
98 genNegFloat(cUnit, rlDest, rlSrc1);
104 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
105 loadValueDirectFixed(cUnit, rlSrc1, r0);
106 loadValueDirectFixed(cUnit, rlSrc2, r1);
107 loadConstant(cUnit, r2, (int)funct);
108 opReg(cUnit, kOpBlx, r2);
109 dvmCompilerClobberCallRegs(cUnit);
110 rlResult = dvmCompilerGetReturn(cUnit);
111 storeValue(cUnit, rlDest, rlResult);
115 static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
116 RegLocation rlDest, RegLocation rlSrc1,
119 RegLocation rlResult;
122 /* TODO: use a proper include file to define these */
123 double __aeabi_dadd(double a, double b);
124 double __aeabi_dsub(double a, double b);
125 double __aeabi_ddiv(double a, double b);
126 double __aeabi_dmul(double a, double b);
127 double fmod(double a, double b);
129 switch (mir->dalvikInsn.opCode) {
130 case OP_ADD_DOUBLE_2ADDR:
132 funct = (void*) __aeabi_dadd;
134 case OP_SUB_DOUBLE_2ADDR:
136 funct = (void*) __aeabi_dsub;
138 case OP_DIV_DOUBLE_2ADDR:
140 funct = (void*) __aeabi_ddiv;
142 case OP_MUL_DOUBLE_2ADDR:
144 funct = (void*) __aeabi_dmul;
146 case OP_REM_DOUBLE_2ADDR:
148 funct = (void*) fmod;
150 case OP_NEG_DOUBLE: {
151 genNegDouble(cUnit, rlDest, rlSrc1);
157 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
158 loadConstant(cUnit, rlr, (int)funct);
159 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
160 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
161 opReg(cUnit, kOpBlx, rlr);
162 dvmCompilerClobberCallRegs(cUnit);
163 rlResult = dvmCompilerGetReturnWide(cUnit);
164 storeValueWide(cUnit, rlDest, rlResult);
168 static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
170 OpCode opCode = mir->dalvikInsn.opCode;
172 float __aeabi_i2f( int op1 );
173 int __aeabi_f2iz( float op1 );
174 float __aeabi_d2f( double op1 );
175 double __aeabi_f2d( float op1 );
176 double __aeabi_i2d( int op1 );
177 int __aeabi_d2iz( double op1 );
178 float __aeabi_l2f( long op1 );
179 double __aeabi_l2d( long op1 );
180 s8 dvmJitf2l( float op1 );
181 s8 dvmJitd2l( double op1 );
184 case OP_INT_TO_FLOAT:
185 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
186 case OP_FLOAT_TO_INT:
187 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
188 case OP_DOUBLE_TO_FLOAT:
189 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
190 case OP_FLOAT_TO_DOUBLE:
191 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
192 case OP_INT_TO_DOUBLE:
193 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
194 case OP_DOUBLE_TO_INT:
195 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
196 case OP_FLOAT_TO_LONG:
197 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
198 case OP_LONG_TO_FLOAT:
199 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
200 case OP_DOUBLE_TO_LONG:
201 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
202 case OP_LONG_TO_DOUBLE:
203 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
210 #if defined(WITH_SELF_VERIFICATION)
211 static void selfVerificationBranchInsert(LIR *currentLIR, ArmOpCode opCode,
214 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
215 insn->opCode = opCode;
216 insn->operands[0] = dest;
217 insn->operands[1] = src1;
218 setupResourceMasks(insn);
219 dvmCompilerInsertLIRBefore(currentLIR, (LIR *) insn);
222 static void selfVerificationBranchInsertPass(CompilationUnit *cUnit)
225 ArmLIR *branchLIR = dvmCompilerNew(sizeof(ArmLIR), true);
226 TemplateOpCode opCode = TEMPLATE_MEM_OP_DECODE;
228 for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn;
229 thisLIR != (ArmLIR *) cUnit->lastLIRInsn;
230 thisLIR = NEXT_LIR(thisLIR)) {
231 if (thisLIR->branchInsertSV) {
232 /* Branch to mem op decode template */
233 selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx1,
234 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
235 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
236 selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx2,
237 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
238 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
244 /* Generate a unconditional branch to go to the interpreter */
245 static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
248 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
249 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
252 /* Load a wide field from an object instance */
253 static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
255 DecodedInstruction *dInsn = &mir->dalvikInsn;
256 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
257 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
258 RegLocation rlResult;
259 rlObj = loadValue(cUnit, rlObj, kCoreReg);
260 int regPtr = dvmCompilerAllocTemp(cUnit);
264 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
265 NULL);/* null object? */
266 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
267 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
268 #if defined(WITH_SELF_VERIFICATION)
269 cUnit->heapMemOp = true;
271 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
272 #if defined(WITH_SELF_VERIFICATION)
273 cUnit->heapMemOp = false;
275 dvmCompilerFreeTemp(cUnit, regPtr);
276 storeValueWide(cUnit, rlDest, rlResult);
279 /* Store a wide field to an object instance */
280 static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
282 DecodedInstruction *dInsn = &mir->dalvikInsn;
283 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
284 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 2);
285 rlObj = loadValue(cUnit, rlObj, kCoreReg);
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 #if defined(WITH_SELF_VERIFICATION)
293 cUnit->heapMemOp = true;
295 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
296 #if defined(WITH_SELF_VERIFICATION)
297 cUnit->heapMemOp = false;
299 dvmCompilerFreeTemp(cUnit, regPtr);
303 * Load a field from an object instance
306 static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
310 RegLocation rlResult;
311 DecodedInstruction *dInsn = &mir->dalvikInsn;
312 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
313 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
314 rlObj = loadValue(cUnit, rlObj, kCoreReg);
315 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
316 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
317 NULL);/* null object? */
318 #if defined(WITH_SELF_VERIFICATION)
319 cUnit->heapMemOp = true;
321 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
322 size, rlObj.sRegLow);
323 #if defined(WITH_SELF_VERIFICATION)
324 cUnit->heapMemOp = false;
326 storeValue(cUnit, rlDest, rlResult);
330 * Store a field to an object instance
333 static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
336 DecodedInstruction *dInsn = &mir->dalvikInsn;
337 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
338 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 1);
339 rlObj = loadValue(cUnit, rlObj, kCoreReg);
340 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
342 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
343 NULL);/* null object? */
344 #if defined(WITH_SELF_VERIFICATION)
345 cUnit->heapMemOp = true;
347 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
348 #if defined(WITH_SELF_VERIFICATION)
349 cUnit->heapMemOp = false;
355 * Generate array load
357 static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
358 RegLocation rlArray, RegLocation rlIndex,
359 RegLocation rlDest, int scale)
361 int lenOffset = offsetof(ArrayObject, length);
362 int dataOffset = offsetof(ArrayObject, contents);
363 RegLocation rlResult;
364 rlArray = loadValue(cUnit, rlArray, kCoreReg);
365 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
369 ArmLIR * pcrLabel = NULL;
371 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
372 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
373 rlArray.lowReg, mir->offset, NULL);
376 regPtr = dvmCompilerAllocTemp(cUnit);
378 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
379 int regLen = dvmCompilerAllocTemp(cUnit);
381 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
382 /* regPtr -> array data */
383 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
384 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
386 dvmCompilerFreeTemp(cUnit, regLen);
388 /* regPtr -> array data */
389 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
391 if ((size == kLong) || (size == kDouble)) {
393 int rNewIndex = dvmCompilerAllocTemp(cUnit);
394 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
395 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
396 dvmCompilerFreeTemp(cUnit, rNewIndex);
398 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
400 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
401 #if defined(WITH_SELF_VERIFICATION)
402 cUnit->heapMemOp = true;
404 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
405 #if defined(WITH_SELF_VERIFICATION)
406 cUnit->heapMemOp = false;
408 dvmCompilerFreeTemp(cUnit, regPtr);
409 storeValueWide(cUnit, rlDest, rlResult);
411 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
412 #if defined(WITH_SELF_VERIFICATION)
413 cUnit->heapMemOp = true;
415 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
417 #if defined(WITH_SELF_VERIFICATION)
418 cUnit->heapMemOp = false;
420 dvmCompilerFreeTemp(cUnit, regPtr);
421 storeValue(cUnit, rlDest, rlResult);
426 * Generate array store
429 static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
430 RegLocation rlArray, RegLocation rlIndex,
431 RegLocation rlSrc, int scale)
433 int lenOffset = offsetof(ArrayObject, length);
434 int dataOffset = offsetof(ArrayObject, contents);
437 rlArray = loadValue(cUnit, rlArray, kCoreReg);
438 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
440 if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) {
441 dvmCompilerClobber(cUnit, rlArray.lowReg);
442 regPtr = rlArray.lowReg;
444 regPtr = dvmCompilerAllocTemp(cUnit);
445 genRegCopy(cUnit, regPtr, rlArray.lowReg);
449 ArmLIR * pcrLabel = NULL;
451 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
452 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
456 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
457 int regLen = dvmCompilerAllocTemp(cUnit);
458 //NOTE: max live temps(4) here.
460 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
461 /* regPtr -> array data */
462 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
463 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
465 dvmCompilerFreeTemp(cUnit, regLen);
467 /* regPtr -> array data */
468 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
470 /* at this point, regPtr points to array, 2 live temps */
471 if ((size == kLong) || (size == kDouble)) {
472 //TODO: need specific wide routine that can handle fp regs
474 int rNewIndex = dvmCompilerAllocTemp(cUnit);
475 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
476 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
477 dvmCompilerFreeTemp(cUnit, rNewIndex);
479 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
481 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
482 #if defined(WITH_SELF_VERIFICATION)
483 cUnit->heapMemOp = true;
485 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
486 #if defined(WITH_SELF_VERIFICATION)
487 cUnit->heapMemOp = false;
489 dvmCompilerFreeTemp(cUnit, regPtr);
491 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
492 #if defined(WITH_SELF_VERIFICATION)
493 cUnit->heapMemOp = true;
495 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
497 #if defined(WITH_SELF_VERIFICATION)
498 cUnit->heapMemOp = false;
503 static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
504 RegLocation rlDest, RegLocation rlSrc1,
508 * Don't mess with the regsiters here as there is a particular calling
509 * convention to the out-of-line handler.
511 RegLocation rlResult;
513 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
514 loadValueDirect(cUnit, rlShift, r2);
515 switch( mir->dalvikInsn.opCode) {
517 case OP_SHL_LONG_2ADDR:
518 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
521 case OP_SHR_LONG_2ADDR:
522 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
525 case OP_USHR_LONG_2ADDR:
526 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
531 rlResult = dvmCompilerGetReturnWide(cUnit);
532 storeValueWide(cUnit, rlDest, rlResult);
536 static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir,
537 RegLocation rlDest, RegLocation rlSrc1,
540 RegLocation rlResult;
541 OpKind firstOp = kOpBkpt;
542 OpKind secondOp = kOpBkpt;
543 bool callOut = false;
546 /* TODO - find proper .h file to declare these */
547 long long __aeabi_ldivmod(long long op1, long long op2);
549 switch (mir->dalvikInsn.opCode) {
551 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
552 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
553 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
554 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
555 storeValueWide(cUnit, rlDest, rlResult);
559 case OP_ADD_LONG_2ADDR:
564 case OP_SUB_LONG_2ADDR:
569 case OP_MUL_LONG_2ADDR:
570 genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
573 case OP_DIV_LONG_2ADDR:
576 callTgt = (void*)__aeabi_ldivmod;
578 /* NOTE - result is in r2/r3 instead of r0/r1 */
580 case OP_REM_LONG_2ADDR:
582 callTgt = (void*)__aeabi_ldivmod;
585 case OP_AND_LONG_2ADDR:
591 case OP_OR_LONG_2ADDR:
596 case OP_XOR_LONG_2ADDR:
601 //TUNING: can improve this using Thumb2 code
602 int tReg = dvmCompilerAllocTemp(cUnit);
603 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
604 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
605 loadConstantValue(cUnit, tReg, 0);
606 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
607 tReg, rlSrc2.lowReg);
608 opRegReg(cUnit, kOpSbc, tReg, rlSrc2.highReg);
609 genRegCopy(cUnit, rlResult.highReg, tReg);
610 storeValueWide(cUnit, rlDest, rlResult);
614 LOGE("Invalid long arith op");
618 genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
620 // Adjust return regs in to handle case of rem returning r2/r3
621 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
622 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
623 loadConstant(cUnit, rlr, (int) callTgt);
624 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
625 opReg(cUnit, kOpBlx, rlr);
626 dvmCompilerClobberCallRegs(cUnit);
628 rlResult = dvmCompilerGetReturnWide(cUnit);
630 rlResult = dvmCompilerGetReturnWideAlt(cUnit);
631 storeValueWide(cUnit, rlDest, rlResult);
636 static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir,
637 RegLocation rlDest, RegLocation rlSrc1,
641 bool callOut = false;
642 bool checkZero = false;
646 RegLocation rlResult;
647 bool shiftOp = false;
649 /* TODO - find proper .h file to declare these */
650 int __aeabi_idivmod(int op1, int op2);
651 int __aeabi_idiv(int op1, int op2);
653 switch (mir->dalvikInsn.opCode) {
663 case OP_ADD_INT_2ADDR:
667 case OP_SUB_INT_2ADDR:
671 case OP_MUL_INT_2ADDR:
675 case OP_DIV_INT_2ADDR:
678 callTgt = __aeabi_idiv;
681 /* NOTE: returns in r1 */
683 case OP_REM_INT_2ADDR:
686 callTgt = __aeabi_idivmod;
690 case OP_AND_INT_2ADDR:
694 case OP_OR_INT_2ADDR:
698 case OP_XOR_INT_2ADDR:
702 case OP_SHL_INT_2ADDR:
707 case OP_SHR_INT_2ADDR:
712 case OP_USHR_INT_2ADDR:
717 LOGE("Invalid word arith op: 0x%x(%d)",
718 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
722 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
724 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
725 opRegReg(cUnit, op, rlResult.lowReg,
728 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
730 int tReg = dvmCompilerAllocTemp(cUnit);
731 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
732 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
733 opRegRegReg(cUnit, op, rlResult.lowReg,
734 rlSrc1.lowReg, tReg);
735 dvmCompilerFreeTemp(cUnit, tReg);
737 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
738 opRegRegReg(cUnit, op, rlResult.lowReg,
739 rlSrc1.lowReg, rlSrc2.lowReg);
742 storeValue(cUnit, rlDest, rlResult);
744 RegLocation rlResult;
745 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
746 loadValueDirectFixed(cUnit, rlSrc2, r1);
747 loadConstant(cUnit, r2, (int) callTgt);
748 loadValueDirectFixed(cUnit, rlSrc1, r0);
750 genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
752 opReg(cUnit, kOpBlx, r2);
753 dvmCompilerClobberCallRegs(cUnit);
755 rlResult = dvmCompilerGetReturn(cUnit);
757 rlResult = dvmCompilerGetReturnAlt(cUnit);
758 storeValue(cUnit, rlDest, rlResult);
763 static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
765 OpCode opCode = mir->dalvikInsn.opCode;
769 /* Deduce sizes of operands */
770 if (mir->ssaRep->numUses == 2) {
771 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
772 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
773 } else if (mir->ssaRep->numUses == 3) {
774 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
775 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
777 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
778 rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
779 assert(mir->ssaRep->numUses == 4);
781 if (mir->ssaRep->numDefs == 1) {
782 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
784 assert(mir->ssaRep->numDefs == 2);
785 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
788 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
789 return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
791 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
792 return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
794 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
795 return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
797 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
798 return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
800 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
801 return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
803 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
804 return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
806 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
807 return genArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
809 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
810 return genArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
812 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
813 return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
815 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
816 return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
821 /* Generate conditional branch instructions */
822 static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
823 ArmConditionCode cond,
826 ArmLIR *branch = opCondBranch(cUnit, cond);
827 branch->generic.target = (LIR *) target;
831 /* Generate unconditional branch instructions */
832 static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
834 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
835 branch->generic.target = (LIR *) target;
839 /* Perform the actual operation for OP_RETURN_* */
840 static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
842 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
843 #if defined(INVOKE_STATS)
846 int dPC = (int) (cUnit->method->insns + mir->offset);
847 /* Insert branch, but defer setting of target */
848 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
849 /* Set up the place holder to reconstruct this Dalvik PC */
850 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
851 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
852 pcrLabel->operands[0] = dPC;
853 pcrLabel->operands[1] = mir->offset;
854 /* Insert the place holder to the growable list */
855 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
856 /* Branch to the PC reconstruction code */
857 branch->generic.target = (LIR *) pcrLabel;
860 static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
861 DecodedInstruction *dInsn,
865 unsigned int regMask = 0;
870 * Load arguments to r0..r4. Note that these registers may contain
871 * live values, so we clobber them immediately after loading to prevent
872 * them from being used as sources for subsequent loads.
874 dvmCompilerLockAllTemps(cUnit);
875 for (i = 0; i < dInsn->vA; i++) {
877 rlArg = dvmCompilerGetSrc(cUnit, mir, numDone++);
878 loadValueDirectFixed(cUnit, rlArg, i);
881 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
882 opRegRegImm(cUnit, kOpSub, r7, rFP,
883 sizeof(StackSaveArea) + (dInsn->vA << 2));
884 /* generate null check */
886 *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0,
889 storeMultiple(cUnit, r7, regMask);
893 static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
894 DecodedInstruction *dInsn,
897 int srcOffset = dInsn->vC << 2;
898 int numArgs = dInsn->vA;
902 * Note: here, all promoted registers will have been flushed
903 * back to the Dalvik base locations, so register usage restrictins
904 * are lifted. All parms loaded from original Dalvik register
905 * region - even though some might conceivably have valid copies
906 * cached in a preserved register.
908 dvmCompilerLockAllTemps(cUnit);
914 opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
915 /* load [r0 .. min(numArgs,4)] */
916 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
918 * Protect the loadMultiple instruction from being reordered with other
919 * Dalvik stack accesses.
921 loadMultiple(cUnit, r4PC, regMask);
923 opRegRegImm(cUnit, kOpSub, r7, rFP,
924 sizeof(StackSaveArea) + (numArgs << 2));
925 /* generate null check */
927 *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0,
932 * Handle remaining 4n arguments:
933 * store previously loaded 4 values and load the next 4 values
936 ArmLIR *loopLabel = NULL;
938 * r0 contains "this" and it will be used later, so push it to the stack
939 * first. Pushing r5 (rFP) is just for stack alignment purposes.
941 opImm(cUnit, kOpPush, (1 << r0 | 1 << rFP));
942 /* No need to generate the loop structure if numArgs <= 11 */
944 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
945 loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
946 loopLabel->defMask = ENCODE_ALL;
948 storeMultiple(cUnit, r7, regMask);
950 * Protect the loadMultiple instruction from being reordered with other
951 * Dalvik stack accesses.
953 loadMultiple(cUnit, r4PC, regMask);
954 /* No need to generate the loop structure if numArgs <= 11 */
956 opRegImm(cUnit, kOpSub, rFP, 4);
957 genConditionalBranch(cUnit, kArmCondNe, loopLabel);
961 /* Save the last batch of loaded values */
962 storeMultiple(cUnit, r7, regMask);
964 /* Generate the loop epilogue - don't use r0 */
965 if ((numArgs > 4) && (numArgs % 4)) {
966 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
968 * Protect the loadMultiple instruction from being reordered with other
969 * Dalvik stack accesses.
971 loadMultiple(cUnit, r4PC, regMask);
974 opImm(cUnit, kOpPop, (1 << r0 | 1 << rFP));
976 /* Save the modulo 4 arguments */
977 if ((numArgs > 4) && (numArgs % 4)) {
978 storeMultiple(cUnit, r7, regMask);
983 * Generate code to setup the call stack then jump to the chaining cell if it
984 * is not a native method.
986 static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
987 BasicBlock *bb, ArmLIR *labelList,
989 const Method *calleeMethod)
992 * Note: all Dalvik register state should be flushed to
993 * memory by the point, so register usage restrictions no
994 * longer apply. All temp & preserved registers may be used.
996 dvmCompilerLockAllTemps(cUnit);
997 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
999 /* r1 = &retChainingCell */
1000 dvmCompilerLockTemp(cUnit, r1);
1001 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
1002 /* r4PC = dalvikCallsite */
1003 loadConstant(cUnit, r4PC,
1004 (int) (cUnit->method->insns + mir->offset));
1005 addrRetChain->generic.target = (LIR *) retChainingCell;
1007 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
1008 * r1 = &ChainingCell
1009 * r4PC = callsiteDPC
1011 if (dvmIsNativeMethod(calleeMethod)) {
1012 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
1013 #if defined(INVOKE_STATS)
1014 gDvmJit.invokeNative++;
1017 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1018 #if defined(INVOKE_STATS)
1019 gDvmJit.invokeChain++;
1021 /* Branch to the chaining cell */
1022 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1024 /* Handle exceptions using the interpreter */
1025 genTrap(cUnit, mir->offset, pcrLabel);
1029 * Generate code to check the validity of a predicted chain and take actions
1030 * based on the result.
1032 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1033 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1034 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1035 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1036 * 0x426a99b2 : blx_2 see above --+
1037 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1038 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1039 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1040 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1041 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1042 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1043 * 0x426a99c0 : blx r7 --+
1044 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1045 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1046 * 0x426a99c6 : blx_2 see above --+
1048 static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1050 ArmLIR *retChainingCell,
1051 ArmLIR *predChainingCell,
1055 * Note: all Dalvik register state should be flushed to
1056 * memory by the point, so register usage restrictions no
1057 * longer apply. Lock temps to prevent them from being
1058 * allocated by utility routines.
1060 dvmCompilerLockAllTemps(cUnit);
1062 /* "this" is already left in r0 by genProcessArgs* */
1064 /* r4PC = dalvikCallsite */
1065 loadConstant(cUnit, r4PC,
1066 (int) (cUnit->method->insns + mir->offset));
1068 /* r1 = &retChainingCell */
1069 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
1070 addrRetChain->generic.target = (LIR *) retChainingCell;
1072 /* r2 = &predictedChainingCell */
1073 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
1074 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1076 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1078 /* return through lr - jump to the chaining cell */
1079 genUnconditionalBranch(cUnit, predChainingCell);
1082 * null-check on "this" may have been eliminated, but we still need a PC-
1083 * reconstruction label for stack overflow bailout.
1085 if (pcrLabel == NULL) {
1086 int dPC = (int) (cUnit->method->insns + mir->offset);
1087 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1088 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
1089 pcrLabel->operands[0] = dPC;
1090 pcrLabel->operands[1] = mir->offset;
1091 /* Insert the place holder to the growable list */
1092 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1095 /* return through lr+2 - punt to the interpreter */
1096 genUnconditionalBranch(cUnit, pcrLabel);
1099 * return through lr+4 - fully resolve the callee method.
1101 * r2 <- &predictedChainCell
1104 * r7 <- this->class->vtable
1107 /* r0 <- calleeMethod */
1108 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
1110 /* Check if rechain limit is reached */
1111 opRegImm(cUnit, kOpCmp, r1, 0);
1113 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
1115 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1116 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
1120 * r2 = &predictedChainingCell
1123 * &returnChainingCell has been loaded into r1 but is not needed
1124 * when patching the chaining cell and will be clobbered upon
1125 * returning so it will be reconstructed again.
1127 opReg(cUnit, kOpBlx, r7);
1129 /* r1 = &retChainingCell */
1130 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
1131 addrRetChain->generic.target = (LIR *) retChainingCell;
1133 bypassRechaining->generic.target = (LIR *) addrRetChain;
1135 * r0 = calleeMethod,
1136 * r1 = &ChainingCell,
1137 * r4PC = callsiteDPC,
1139 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1140 #if defined(INVOKE_STATS)
1141 gDvmJit.invokePredictedChain++;
1143 /* Handle exceptions using the interpreter */
1144 genTrap(cUnit, mir->offset, pcrLabel);
1148 * Up calling this function, "this" is stored in r0. The actual class will be
1149 * chased down off r0 and the predicted one will be retrieved through
1150 * predictedChainingCell then a comparison is performed to see whether the
1151 * previously established chaining is still valid.
1153 * The return LIR is a branch based on the comparison result. The actual branch
1154 * target will be setup in the caller.
1156 static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1157 ArmLIR *predChainingCell,
1158 ArmLIR *retChainingCell,
1162 * Note: all Dalvik register state should be flushed to
1163 * memory by the point, so register usage restrictions no
1164 * longer apply. All temp & preserved registers may be used.
1166 dvmCompilerLockAllTemps(cUnit);
1168 /* r3 now contains this->clazz */
1169 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1172 * r2 now contains predicted class. The starting offset of the
1173 * cached value is 4 bytes into the chaining cell.
1175 ArmLIR *getPredictedClass =
1176 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
1177 getPredictedClass->generic.target = (LIR *) predChainingCell;
1180 * r0 now contains predicted method. The starting offset of the
1181 * cached value is 8 bytes into the chaining cell.
1183 ArmLIR *getPredictedMethod =
1184 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
1185 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1187 /* Load the stats counter to see if it is time to unchain and refresh */
1188 ArmLIR *getRechainingRequestCount =
1189 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
1190 getRechainingRequestCount->generic.target =
1191 (LIR *) predChainingCell;
1193 /* r4PC = dalvikCallsite */
1194 loadConstant(cUnit, r4PC,
1195 (int) (cUnit->method->insns + mir->offset));
1197 /* r1 = &retChainingCell */
1198 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
1199 addrRetChain->generic.target = (LIR *) retChainingCell;
1201 /* Check if r2 (predicted class) == r3 (actual class) */
1202 opRegReg(cUnit, kOpCmp, r2, r3);
1204 return opCondBranch(cUnit, kArmCondEq);
1207 /* Geneate a branch to go back to the interpreter */
1208 static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1210 /* r0 = dalvik pc */
1211 dvmCompilerFlushAllRegs(cUnit);
1212 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
1213 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1214 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1215 jitToInterpEntries.dvmJitToInterpPunt), r1);
1216 opReg(cUnit, kOpBlx, r1);
1220 * Attempt to single step one instruction using the interpreter and return
1221 * to the compiled code for the next Dalvik instruction
1223 static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1225 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1226 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1229 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them
1230 dvmCompilerFlushAllRegs(cUnit);
1232 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1233 genPuntToInterp(cUnit, mir->offset);
1236 int entryAddr = offsetof(InterpState,
1237 jitToInterpEntries.dvmJitToInterpSingleStep);
1238 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
1239 /* r0 = dalvik pc */
1240 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1241 /* r1 = dalvik pc of following instruction */
1242 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
1243 opReg(cUnit, kOpBlx, r2);
1247 * To prevent a thread in a monitor wait from blocking the Jit from
1248 * resetting the code cache, heavyweight monitor lock will not
1249 * be allowed to return to an existing translation. Instead, we will
1250 * handle them by branching to a handler, which will in turn call the
1251 * runtime lock routine and then branch directly back to the
1252 * interpreter main loop. Given the high cost of the heavyweight
1253 * lock operation, this additional cost should be slight (especially when
1254 * considering that we expect the vast majority of lock operations to
1255 * use the fast-path thin lock bypass).
1257 static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir)
1259 bool isEnter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
1260 genExportPC(cUnit, mir);
1261 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
1262 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1263 loadValueDirectFixed(cUnit, rlSrc, r1);
1264 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
1265 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
1267 /* Get dPC of next insn */
1268 loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset +
1269 dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_ENTER)));
1270 #if defined(WITH_DEADLOCK_PREDICTION)
1271 genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER_DEBUG);
1273 genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER);
1276 loadConstant(cUnit, r2, (int)dvmUnlockObject);
1278 opReg(cUnit, kOpBlx, r2);
1279 opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */
1280 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
1281 loadConstant(cUnit, r0,
1282 (int) (cUnit->method->insns + mir->offset +
1283 dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_EXIT)));
1284 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1285 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1286 target->defMask = ENCODE_ALL;
1287 branchOver->generic.target = (LIR *) target;
1288 dvmCompilerClobberCallRegs(cUnit);
1293 * The following are the first-level codegen routines that analyze the format
1294 * of each bytecode then either dispatch special purpose codegen routines
1295 * or produce corresponding Thumb instructions directly.
1298 static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
1299 BasicBlock *bb, ArmLIR *labelList)
1301 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1302 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1306 static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1308 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1309 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1310 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EB))) {
1311 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1314 switch (dalvikOpCode) {
1315 case OP_RETURN_VOID:
1316 genReturnCommon(cUnit,mir);
1321 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1331 static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1334 RegLocation rlResult;
1335 if (mir->ssaRep->numDefs == 2) {
1336 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1338 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1341 switch (mir->dalvikInsn.opCode) {
1344 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1345 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1346 storeValue(cUnit, rlDest, rlResult);
1349 case OP_CONST_WIDE_32: {
1350 //TUNING: single routine to load constant pair for support doubles
1351 //TUNING: load 0/-1 separately to avoid load dependency
1352 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1353 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1354 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1355 rlResult.lowReg, 31);
1356 storeValueWide(cUnit, rlDest, rlResult);
1365 static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1368 RegLocation rlResult;
1369 if (mir->ssaRep->numDefs == 2) {
1370 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1372 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1374 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1376 switch (mir->dalvikInsn.opCode) {
1377 case OP_CONST_HIGH16: {
1378 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
1379 storeValue(cUnit, rlDest, rlResult);
1382 case OP_CONST_WIDE_HIGH16: {
1383 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1384 0, mir->dalvikInsn.vB << 16);
1385 storeValueWide(cUnit, rlDest, rlResult);
1394 static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1396 /* For OP_THROW_VERIFICATION_ERROR */
1397 genInterpSingleStep(cUnit, mir);
1401 static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1403 RegLocation rlResult;
1407 switch (mir->dalvikInsn.opCode) {
1408 case OP_CONST_STRING_JUMBO:
1409 case OP_CONST_STRING: {
1410 void *strPtr = (void*)
1411 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1412 assert(strPtr != NULL);
1413 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1414 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1415 loadConstantValue(cUnit, rlResult.lowReg, (int) strPtr );
1416 storeValue(cUnit, rlDest, rlResult);
1419 case OP_CONST_CLASS: {
1420 void *classPtr = (void*)
1421 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1422 assert(classPtr != NULL);
1423 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1424 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1425 loadConstantValue(cUnit, rlResult.lowReg, (int) classPtr );
1426 storeValue(cUnit, rlDest, rlResult);
1429 case OP_SGET_OBJECT:
1430 case OP_SGET_BOOLEAN:
1435 int valOffset = offsetof(StaticField, value);
1436 int tReg = dvmCompilerAllocTemp(cUnit);
1437 void *fieldPtr = (void*)
1438 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1439 assert(fieldPtr != NULL);
1440 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1441 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1442 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
1443 #if defined(WITH_SELF_VERIFICATION)
1444 cUnit->heapMemOp = true;
1446 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
1447 #if defined(WITH_SELF_VERIFICATION)
1448 cUnit->heapMemOp = false;
1450 storeValue(cUnit, rlDest, rlResult);
1453 case OP_SGET_WIDE: {
1454 int valOffset = offsetof(StaticField, value);
1455 void *fieldPtr = (void*)
1456 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1457 int tReg = dvmCompilerAllocTemp(cUnit);
1458 assert(fieldPtr != NULL);
1459 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1460 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1461 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
1462 #if defined(WITH_SELF_VERIFICATION)
1463 cUnit->heapMemOp = true;
1465 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
1466 #if defined(WITH_SELF_VERIFICATION)
1467 cUnit->heapMemOp = false;
1469 storeValueWide(cUnit, rlDest, rlResult);
1472 case OP_SPUT_OBJECT:
1473 case OP_SPUT_BOOLEAN:
1478 int valOffset = offsetof(StaticField, value);
1479 int tReg = dvmCompilerAllocTemp(cUnit);
1480 void *fieldPtr = (void*)
1481 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1483 assert(fieldPtr != NULL);
1484 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1485 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1486 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
1487 #if defined(WITH_SELF_VERIFICATION)
1488 cUnit->heapMemOp = true;
1490 storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
1491 #if defined(WITH_SELF_VERIFICATION)
1492 cUnit->heapMemOp = false;
1496 case OP_SPUT_WIDE: {
1497 int tReg = dvmCompilerAllocTemp(cUnit);
1498 int valOffset = offsetof(StaticField, value);
1499 void *fieldPtr = (void*)
1500 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1502 assert(fieldPtr != NULL);
1503 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1504 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1505 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
1506 #if defined(WITH_SELF_VERIFICATION)
1507 cUnit->heapMemOp = true;
1509 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
1510 #if defined(WITH_SELF_VERIFICATION)
1511 cUnit->heapMemOp = false;
1515 case OP_NEW_INSTANCE: {
1517 * Obey the calling convention and don't mess with the register
1520 ClassObject *classPtr = (void*)
1521 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1522 assert(classPtr != NULL);
1523 assert(classPtr->status & CLASS_INITIALIZED);
1525 * If it is going to throw, it should not make to the trace to begin
1526 * with. However, Alloc might throw, so we need to genExportPC()
1528 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
1529 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
1530 genExportPC(cUnit, mir);
1531 loadConstant(cUnit, r2, (int)dvmAllocObject);
1532 loadConstant(cUnit, r0, (int) classPtr);
1533 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
1534 opReg(cUnit, kOpBlx, r2);
1535 dvmCompilerClobberCallRegs(cUnit);
1536 /* generate a branch over if allocation is successful */
1537 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
1538 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
1540 * OOM exception needs to be thrown here and cannot re-execute
1542 loadConstant(cUnit, r0,
1543 (int) (cUnit->method->insns + mir->offset));
1544 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1547 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1548 target->defMask = ENCODE_ALL;
1549 branchOver->generic.target = (LIR *) target;
1550 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1551 rlResult = dvmCompilerGetReturn(cUnit);
1552 storeValue(cUnit, rlDest, rlResult);
1555 case OP_CHECK_CAST: {
1557 * Obey the calling convention and don't mess with the register
1560 ClassObject *classPtr =
1561 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1563 * Note: It is possible that classPtr is NULL at this point,
1564 * even though this instruction has been successfully interpreted.
1565 * If the previous interpretation had a null source, the
1566 * interpreter would not have bothered to resolve the clazz.
1567 * Bail out to the interpreter in this case, and log it
1568 * so that we can tell if it happens frequently.
1570 if (classPtr == NULL) {
1571 LOGD("null clazz in OP_CHECK_CAST, single-stepping");
1572 genInterpSingleStep(cUnit, mir);
1575 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
1576 loadConstant(cUnit, r1, (int) classPtr );
1577 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1578 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1579 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); /* Null? */
1580 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
1582 * rlSrc.lowReg now contains object->clazz. Note that
1583 * it could have been allocated r0, but we're okay so long
1584 * as we don't do anything desctructive until r0 is loaded
1587 /* r0 now contains object->clazz */
1588 loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
1589 loadConstant(cUnit, r2, (int)dvmInstanceofNonTrivial);
1590 opRegReg(cUnit, kOpCmp, r0, r1);
1591 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
1592 opReg(cUnit, kOpBlx, r2);
1593 dvmCompilerClobberCallRegs(cUnit);
1595 * If null, check cast failed - punt to the interpreter. Because
1596 * interpreter will be the one throwing, we don't need to
1597 * genExportPC() here.
1599 genZeroCheck(cUnit, r0, mir->offset, NULL);
1600 /* check cast passed - branch target here */
1601 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1602 target->defMask = ENCODE_ALL;
1603 branch1->generic.target = (LIR *)target;
1604 branch2->generic.target = (LIR *)target;
1613 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1615 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1616 RegLocation rlResult;
1617 switch (dalvikOpCode) {
1618 case OP_MOVE_EXCEPTION: {
1619 int offset = offsetof(InterpState, self);
1620 int exOffset = offsetof(Thread, exception);
1621 int selfReg = dvmCompilerAllocTemp(cUnit);
1622 int resetReg = dvmCompilerAllocTemp(cUnit);
1623 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1624 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1625 loadWordDisp(cUnit, rGLUE, offset, selfReg);
1626 loadConstant(cUnit, resetReg, 0);
1627 loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg);
1628 storeWordDisp(cUnit, selfReg, exOffset, resetReg);
1629 storeValue(cUnit, rlDest, rlResult);
1632 case OP_MOVE_RESULT:
1633 case OP_MOVE_RESULT_OBJECT: {
1634 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1635 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
1636 rlSrc.fp = rlDest.fp;
1637 storeValue(cUnit, rlDest, rlSrc);
1640 case OP_MOVE_RESULT_WIDE: {
1641 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1642 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
1643 rlSrc.fp = rlDest.fp;
1644 storeValueWide(cUnit, rlDest, rlSrc);
1647 case OP_RETURN_WIDE: {
1648 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1649 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
1650 rlDest.fp = rlSrc.fp;
1651 storeValueWide(cUnit, rlDest, rlSrc);
1652 genReturnCommon(cUnit,mir);
1656 case OP_RETURN_OBJECT: {
1657 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1658 RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
1659 rlDest.fp = rlSrc.fp;
1660 storeValue(cUnit, rlDest, rlSrc);
1661 genReturnCommon(cUnit,mir);
1664 case OP_MONITOR_EXIT:
1665 case OP_MONITOR_ENTER:
1666 #if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
1667 genMonitorPortable(cUnit, mir);
1669 genMonitor(cUnit, mir);
1673 genInterpSingleStep(cUnit, mir);
1682 static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1684 OpCode opCode = mir->dalvikInsn.opCode;
1687 RegLocation rlResult;
1689 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1690 return genArithOp( cUnit, mir );
1693 if (mir->ssaRep->numUses == 2)
1694 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
1696 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1697 if (mir->ssaRep->numDefs == 2)
1698 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1700 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1703 case OP_DOUBLE_TO_INT:
1704 case OP_INT_TO_FLOAT:
1705 case OP_FLOAT_TO_INT:
1706 case OP_DOUBLE_TO_FLOAT:
1707 case OP_FLOAT_TO_DOUBLE:
1708 case OP_INT_TO_DOUBLE:
1709 case OP_FLOAT_TO_LONG:
1710 case OP_LONG_TO_FLOAT:
1711 case OP_DOUBLE_TO_LONG:
1712 case OP_LONG_TO_DOUBLE:
1713 return genConversion(cUnit, mir);
1716 return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
1719 return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
1721 return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
1723 return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
1725 storeValueWide(cUnit, rlDest, rlSrc);
1727 case OP_INT_TO_LONG:
1728 rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
1729 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1730 //TUNING: shouldn't loadValueDirect already check for phys reg?
1731 if (rlSrc.location == kLocPhysReg) {
1732 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
1734 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
1736 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1737 rlResult.lowReg, 31);
1738 storeValueWide(cUnit, rlDest, rlResult);
1740 case OP_LONG_TO_INT:
1741 rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
1742 rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc);
1743 // Intentional fallthrough
1745 case OP_MOVE_OBJECT:
1746 storeValue(cUnit, rlDest, rlSrc);
1748 case OP_INT_TO_BYTE:
1749 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1750 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1751 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
1752 storeValue(cUnit, rlDest, rlResult);
1754 case OP_INT_TO_SHORT:
1755 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1756 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1757 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
1758 storeValue(cUnit, rlDest, rlResult);
1760 case OP_INT_TO_CHAR:
1761 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1762 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1763 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
1764 storeValue(cUnit, rlDest, rlResult);
1766 case OP_ARRAY_LENGTH: {
1767 int lenOffset = offsetof(ArrayObject, length);
1768 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1769 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
1771 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1772 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
1774 storeValue(cUnit, rlDest, rlResult);
1783 static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
1785 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1787 RegLocation rlResult;
1788 int BBBB = mir->dalvikInsn.vB;
1789 if (dalvikOpCode == OP_CONST_WIDE_16) {
1790 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1791 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1792 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
1793 //TUNING: do high separately to avoid load dependency
1794 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1795 storeValueWide(cUnit, rlDest, rlResult);
1796 } else if (dalvikOpCode == OP_CONST_16) {
1797 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1798 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
1799 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
1800 storeValue(cUnit, rlDest, rlResult);
1806 /* Compare agaist zero */
1807 static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
1810 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1811 ArmConditionCode cond;
1812 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1813 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1814 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
1816 //TUNING: break this out to allow use of Thumb2 CB[N]Z
1817 switch (dalvikOpCode) {
1838 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
1841 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1842 /* This mostly likely will be optimized away in a later phase */
1843 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1847 static bool isPowerOfTwo(int x)
1849 return (x & (x - 1)) == 0;
1852 // Returns true if no more than two bits are set in 'x'.
1853 static bool isPopCountLE2(unsigned int x)
1856 return (x & (x - 1)) == 0;
1859 // Returns the index of the lowest set bit in 'x'.
1860 static int lowestSetBit(unsigned int x) {
1862 while ((x & 0xf) == 0) {
1866 while ((x & 1) == 0) {
1873 // Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1874 // and store the result in 'rlDest'.
1875 static bool handleEasyMultiply(CompilationUnit *cUnit,
1876 RegLocation rlSrc, RegLocation rlDest, int lit)
1878 // Can we simplify this multiplication?
1879 bool powerOfTwo = false;
1880 bool popCountLE2 = false;
1881 bool powerOfTwoMinusOne = false;
1883 // Avoid special cases.
1885 } else if (isPowerOfTwo(lit)) {
1887 } else if (isPopCountLE2(lit)) {
1889 } else if (isPowerOfTwo(lit + 1)) {
1890 powerOfTwoMinusOne = true;
1894 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1895 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1898 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1900 } else if (popCountLE2) {
1901 // Shift and add and shift.
1902 int firstBit = lowestSetBit(lit);
1903 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1904 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1905 firstBit, secondBit);
1907 // Reverse subtract: (src << (shift + 1)) - src.
1908 assert(powerOfTwoMinusOne);
1909 // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1910 int tReg = dvmCompilerAllocTemp(cUnit);
1911 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1912 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1914 storeValue(cUnit, rlDest, rlResult);
1918 static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
1920 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1921 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1922 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1923 RegLocation rlResult;
1924 int lit = mir->dalvikInsn.vC;
1925 OpKind op = 0; /* Make gcc happy */
1926 int shiftOp = false;
1929 int __aeabi_idivmod(int op1, int op2);
1930 int __aeabi_idiv(int op1, int op2);
1932 switch (dalvikOpCode) {
1933 case OP_RSUB_INT_LIT8:
1936 //TUNING: add support for use of Arm rsub op
1937 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1938 tReg = dvmCompilerAllocTemp(cUnit);
1939 loadConstant(cUnit, tReg, lit);
1940 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1941 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1942 tReg, rlSrc.lowReg);
1943 storeValue(cUnit, rlDest, rlResult);
1948 case OP_ADD_INT_LIT8:
1949 case OP_ADD_INT_LIT16:
1952 case OP_MUL_INT_LIT8:
1953 case OP_MUL_INT_LIT16: {
1954 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1960 case OP_AND_INT_LIT8:
1961 case OP_AND_INT_LIT16:
1964 case OP_OR_INT_LIT8:
1965 case OP_OR_INT_LIT16:
1968 case OP_XOR_INT_LIT8:
1969 case OP_XOR_INT_LIT16:
1972 case OP_SHL_INT_LIT8:
1977 case OP_SHR_INT_LIT8:
1982 case OP_USHR_INT_LIT8:
1988 case OP_DIV_INT_LIT8:
1989 case OP_DIV_INT_LIT16:
1990 case OP_REM_INT_LIT8:
1991 case OP_REM_INT_LIT16:
1993 /* Let the interpreter deal with div by 0 */
1994 genInterpSingleStep(cUnit, mir);
1997 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
1998 loadValueDirectFixed(cUnit, rlSrc, r0);
1999 dvmCompilerClobber(cUnit, r0);
2000 if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
2001 (dalvikOpCode == OP_DIV_INT_LIT16)) {
2002 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2005 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2008 loadConstant(cUnit, r1, lit);
2009 opReg(cUnit, kOpBlx, r2);
2010 dvmCompilerClobberCallRegs(cUnit);
2012 rlResult = dvmCompilerGetReturn(cUnit);
2014 rlResult = dvmCompilerGetReturnAlt(cUnit);
2015 storeValue(cUnit, rlDest, rlResult);
2021 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2022 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2023 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2024 if (shiftOp && (lit == 0)) {
2025 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2027 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2029 storeValue(cUnit, rlDest, rlResult);
2033 static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2035 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2038 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2039 InstField *pInstField = (InstField *)
2040 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2042 assert(pInstField != NULL);
2043 fieldOffset = pInstField->byteOffset;
2045 /* Deliberately break the code while make the compiler happy */
2048 switch (dalvikOpCode) {
2049 case OP_NEW_ARRAY: {
2050 // Generates a call - use explicit registers
2051 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2052 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2053 RegLocation rlResult;
2054 void *classPtr = (void*)
2055 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2056 assert(classPtr != NULL);
2057 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
2058 genExportPC(cUnit, mir);
2059 loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */
2060 loadConstant(cUnit, r0, (int) classPtr );
2061 loadConstant(cUnit, r3, (int)dvmAllocArrayByClass);
2063 * "len < 0": bail to the interpreter to re-execute the
2067 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
2068 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2069 opReg(cUnit, kOpBlx, r3);
2070 dvmCompilerClobberCallRegs(cUnit);
2071 /* generate a branch over if allocation is successful */
2072 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2073 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
2075 * OOM exception needs to be thrown here and cannot re-execute
2077 loadConstant(cUnit, r0,
2078 (int) (cUnit->method->insns + mir->offset));
2079 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2082 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2083 target->defMask = ENCODE_ALL;
2084 branchOver->generic.target = (LIR *) target;
2085 rlResult = dvmCompilerGetReturn(cUnit);
2086 storeValue(cUnit, rlDest, rlResult);
2089 case OP_INSTANCE_OF: {
2090 // May generate a call - use explicit registers
2091 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2092 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2093 RegLocation rlResult;
2094 ClassObject *classPtr =
2095 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2097 * Note: It is possible that classPtr is NULL at this point,
2098 * even though this instruction has been successfully interpreted.
2099 * If the previous interpretation had a null source, the
2100 * interpreter would not have bothered to resolve the clazz.
2101 * Bail out to the interpreter in this case, and log it
2102 * so that we can tell if it happens frequently.
2104 if (classPtr == NULL) {
2105 LOGD("null clazz in OP_INSTANCE_OF, single-stepping");
2106 genInterpSingleStep(cUnit, mir);
2109 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
2110 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
2111 loadConstant(cUnit, r2, (int) classPtr );
2112 //TUNING: compare to 0 primative to allow use of CB[N]Z
2113 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2114 /* When taken r0 has NULL which can be used for store directly */
2115 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
2116 /* r1 now contains object->clazz */
2117 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
2118 /* r1 now contains object->clazz */
2119 loadConstant(cUnit, r3, (int)dvmInstanceofNonTrivial);
2120 loadConstant(cUnit, r0, 1); /* Assume true */
2121 opRegReg(cUnit, kOpCmp, r1, r2);
2122 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
2123 genRegCopy(cUnit, r0, r1);
2124 genRegCopy(cUnit, r1, r2);
2125 opReg(cUnit, kOpBlx, r3);
2126 dvmCompilerClobberCallRegs(cUnit);
2127 /* branch target here */
2128 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2129 target->defMask = ENCODE_ALL;
2130 rlResult = dvmCompilerGetReturn(cUnit);
2131 storeValue(cUnit, rlDest, rlResult);
2132 branch1->generic.target = (LIR *)target;
2133 branch2->generic.target = (LIR *)target;
2137 genIGetWide(cUnit, mir, fieldOffset);
2140 case OP_IGET_OBJECT:
2141 genIGet(cUnit, mir, kWord, fieldOffset);
2143 case OP_IGET_BOOLEAN:
2144 genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
2147 genIGet(cUnit, mir, kSignedByte, fieldOffset);
2150 genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
2153 genIGet(cUnit, mir, kSignedHalf, fieldOffset);
2156 genIPutWide(cUnit, mir, fieldOffset);
2159 case OP_IPUT_OBJECT:
2160 genIPut(cUnit, mir, kWord, fieldOffset);
2164 genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
2167 case OP_IPUT_BOOLEAN:
2168 genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
2176 static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2178 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2179 int fieldOffset = mir->dalvikInsn.vC;
2180 switch (dalvikOpCode) {
2182 case OP_IGET_OBJECT_QUICK:
2183 genIGet(cUnit, mir, kWord, fieldOffset);
2186 case OP_IPUT_OBJECT_QUICK:
2187 genIPut(cUnit, mir, kWord, fieldOffset);
2189 case OP_IGET_WIDE_QUICK:
2190 genIGetWide(cUnit, mir, fieldOffset);
2192 case OP_IPUT_WIDE_QUICK:
2193 genIPutWide(cUnit, mir, fieldOffset);
2202 /* Compare agaist zero */
2203 static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2206 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2207 ArmConditionCode cond;
2208 RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2209 RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
2211 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
2212 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
2213 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
2215 switch (dalvikOpCode) {
2236 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2239 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2240 /* This mostly likely will be optimized away in a later phase */
2241 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2245 static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2247 OpCode opCode = mir->dalvikInsn.opCode;
2251 case OP_MOVE_OBJECT_16:
2252 case OP_MOVE_FROM16:
2253 case OP_MOVE_OBJECT_FROM16: {
2254 storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0),
2255 dvmCompilerGetSrc(cUnit, mir, 0));
2258 case OP_MOVE_WIDE_16:
2259 case OP_MOVE_WIDE_FROM16: {
2260 storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1),
2261 dvmCompilerGetSrcWide(cUnit, mir, 0, 1));
2270 static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2272 OpCode opCode = mir->dalvikInsn.opCode;
2277 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2278 return genArithOp( cUnit, mir );
2281 /* APUTs have 3 sources and no targets */
2282 if (mir->ssaRep->numDefs == 0) {
2283 if (mir->ssaRep->numUses == 3) {
2284 rlDest = dvmCompilerGetSrc(cUnit, mir, 0);
2285 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1);
2286 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
2288 assert(mir->ssaRep->numUses == 4);
2289 rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2290 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2);
2291 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3);
2294 /* Two sources and 1 dest. Deduce the operand sizes */
2295 if (mir->ssaRep->numUses == 4) {
2296 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2297 rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
2299 assert(mir->ssaRep->numUses == 2);
2300 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2301 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
2303 if (mir->ssaRep->numDefs == 2) {
2304 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
2306 assert(mir->ssaRep->numDefs == 1);
2307 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
2315 case OP_CMPL_DOUBLE:
2316 case OP_CMPG_DOUBLE:
2317 return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2319 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2322 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
2325 case OP_AGET_OBJECT:
2326 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
2328 case OP_AGET_BOOLEAN:
2329 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
2332 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
2335 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2338 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2341 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
2344 case OP_APUT_OBJECT:
2345 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
2349 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
2352 case OP_APUT_BOOLEAN:
2353 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
2362 * Find the matching case.
2365 * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
2366 * including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
2367 * r1 (high 32-bit): the branch offset of the matching case (only for indexes
2368 * above MAX_CHAINED_SWITCH_CASES).
2370 * Instructions around the call are:
2373 * blx &findPackedSwitchIndex
2376 * chaining cell for case 0 [8 bytes]
2377 * chaining cell for case 1 [8 bytes]
2379 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [8 bytes]
2380 * chaining cell for case default [8 bytes]
2383 s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
2390 int caseDPCOffset = 0;
2391 /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
2392 int chainingPC = (pc + 4) & ~3;
2395 * Packed switch data format:
2396 * ushort ident = 0x0100 magic value
2397 * ushort size number of entries in the table
2398 * int first_key first (and lowest) switch case value
2399 * int targets[size] branch targets, relative to switch opcode
2401 * Total size is (4+size*2) 16-bit code units.
2403 size = switchData[1];
2406 firstKey = switchData[2];
2407 firstKey |= switchData[3] << 16;
2410 /* The entries are guaranteed to be aligned on a 32-bit boundary;
2411 * we can treat them as a native int array.
2413 entries = (const int*) &switchData[4];
2414 assert(((u4)entries & 0x3) == 0);
2416 index = testVal - firstKey;
2418 /* Jump to the default cell */
2419 if (index < 0 || index >= size) {
2420 jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
2421 /* Jump to the non-chaining exit point */
2422 } else if (index >= MAX_CHAINED_SWITCH_CASES) {
2423 jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
2424 caseDPCOffset = entries[index];
2425 /* Jump to the inline chaining cell */
2430 chainingPC += jumpIndex * 8;
2431 return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
2434 /* See comments for findPackedSwitchIndex */
2435 s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
2440 int chainingPC = (pc + 4) & ~3;
2444 * Sparse switch data format:
2445 * ushort ident = 0x0200 magic value
2446 * ushort size number of entries in the table; > 0
2447 * int keys[size] keys, sorted low-to-high; 32-bit aligned
2448 * int targets[size] branch targets, relative to switch opcode
2450 * Total size is (2+size*4) 16-bit code units.
2453 size = switchData[1];
2456 /* The keys are guaranteed to be aligned on a 32-bit boundary;
2457 * we can treat them as a native int array.
2459 keys = (const int*) &switchData[2];
2460 assert(((u4)keys & 0x3) == 0);
2462 /* The entries are guaranteed to be aligned on a 32-bit boundary;
2463 * we can treat them as a native int array.
2465 entries = keys + size;
2466 assert(((u4)entries & 0x3) == 0);
2469 * Run through the list of keys, which are guaranteed to
2470 * be sorted low-to-high.
2472 * Most tables have 3-4 entries. Few have more than 10. A binary
2473 * search here is probably not useful.
2475 for (i = 0; i < size; i++) {
2478 /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
2479 int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
2480 i : MAX_CHAINED_SWITCH_CASES + 1;
2481 chainingPC += jumpIndex * 8;
2482 return (((s8) entries[i]) << 32) | (u8) chainingPC;
2483 } else if (k > testVal) {
2487 return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 8;
2490 static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2492 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2493 switch (dalvikOpCode) {
2494 case OP_FILL_ARRAY_DATA: {
2495 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2496 // Making a call - use explicit registers
2497 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
2498 genExportPC(cUnit, mir);
2499 loadValueDirectFixed(cUnit, rlSrc, r0);
2500 loadConstant(cUnit, r2, (int)dvmInterpHandleFillArrayData);
2501 loadConstant(cUnit, r1,
2502 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
2503 opReg(cUnit, kOpBlx, r2);
2504 dvmCompilerClobberCallRegs(cUnit);
2505 /* generate a branch over if successful */
2506 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2507 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
2508 loadConstant(cUnit, r0,
2509 (int) (cUnit->method->insns + mir->offset));
2510 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2511 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2512 target->defMask = ENCODE_ALL;
2513 branchOver->generic.target = (LIR *) target;
2517 * Compute the goto target of up to
2518 * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
2519 * See the comment before findPackedSwitchIndex for the code layout.
2521 case OP_PACKED_SWITCH:
2522 case OP_SPARSE_SWITCH: {
2523 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2524 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
2525 loadValueDirectFixed(cUnit, rlSrc, r1);
2526 dvmCompilerLockAllTemps(cUnit);
2527 const u2 *switchData =
2528 cUnit->method->insns + mir->offset + mir->dalvikInsn.vB;
2529 u2 size = switchData[1];
2531 if (dalvikOpCode == OP_PACKED_SWITCH) {
2532 loadConstant(cUnit, r4PC, (int)findPackedSwitchIndex);
2534 loadConstant(cUnit, r4PC, (int)findSparseSwitchIndex);
2536 /* r0 <- Addr of the switch data */
2537 loadConstant(cUnit, r0,
2538 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
2539 /* r2 <- pc of the instruction following the blx */
2540 opRegReg(cUnit, kOpMov, r2, rpc);
2541 opReg(cUnit, kOpBlx, r4PC);
2542 dvmCompilerClobberCallRegs(cUnit);
2543 /* pc <- computed goto target */
2544 opRegReg(cUnit, kOpMov, rpc, r0);
2553 static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2556 ArmLIR *retChainingCell = NULL;
2557 ArmLIR *pcrLabel = NULL;
2559 if (bb->fallThrough != NULL)
2560 retChainingCell = &labelList[bb->fallThrough->id];
2562 DecodedInstruction *dInsn = &mir->dalvikInsn;
2563 switch (mir->dalvikInsn.opCode) {
2565 * calleeMethod = this->clazz->vtable[
2566 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2569 case OP_INVOKE_VIRTUAL:
2570 case OP_INVOKE_VIRTUAL_RANGE: {
2571 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2573 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2576 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2577 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2579 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2581 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2588 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2589 * ->pResMethods[BBBB]->methodIndex]
2591 /* TODO - not excersized in RunPerf.jar */
2592 case OP_INVOKE_SUPER:
2593 case OP_INVOKE_SUPER_RANGE: {
2594 int mIndex = cUnit->method->clazz->pDvmDex->
2595 pResMethods[dInsn->vB]->methodIndex;
2596 const Method *calleeMethod =
2597 cUnit->method->clazz->super->vtable[mIndex];
2599 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2600 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2602 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2604 /* r0 = calleeMethod */
2605 loadConstant(cUnit, r0, (int) calleeMethod);
2607 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2611 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2612 case OP_INVOKE_DIRECT:
2613 case OP_INVOKE_DIRECT_RANGE: {
2614 const Method *calleeMethod =
2615 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2617 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2618 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2620 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2622 /* r0 = calleeMethod */
2623 loadConstant(cUnit, r0, (int) calleeMethod);
2625 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2629 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2630 case OP_INVOKE_STATIC:
2631 case OP_INVOKE_STATIC_RANGE: {
2632 const Method *calleeMethod =
2633 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2635 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2636 genProcessArgsNoRange(cUnit, mir, dInsn,
2637 NULL /* no null check */);
2639 genProcessArgsRange(cUnit, mir, dInsn,
2640 NULL /* no null check */);
2642 /* r0 = calleeMethod */
2643 loadConstant(cUnit, r0, (int) calleeMethod);
2645 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2650 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2651 * BBBB, method, method->clazz->pDvmDex)
2653 * Given "invoke-interface {v0}", the following is the generated code:
2655 * 0x426a9abe : ldr r0, [r5, #0] --+
2656 * 0x426a9ac0 : mov r7, r5 |
2657 * 0x426a9ac2 : sub r7, #24 |
2658 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
2659 * 0x426a9ac6 : beq 0x426a9afe |
2660 * 0x426a9ac8 : stmia r7, <r0> --+
2661 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2662 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
2663 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
2664 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
2665 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
2666 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
2667 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
2668 * 0x426a9ad8 : mov r8, r1 --+
2669 * 0x426a9ada : mov r9, r2 |
2670 * 0x426a9adc : mov r10, r3 |
2671 * 0x426a9ade : mov r0, r3 |
2672 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
2673 * 0x426a9ae2 : ldr r2, [pc, #76] |
2674 * 0x426a9ae4 : ldr r3, [pc, #68] |
2675 * 0x426a9ae6 : ldr r7, [pc, #64] |
2676 * 0x426a9ae8 : blx r7 --+
2677 * 0x426a9aea : mov r1, r8 --> r1 <- rechain count
2678 * 0x426a9aec : cmp r1, #0 --> compare against 0
2679 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
2680 * 0x426a9af0 : ldr r7, [r6, #96] --+
2681 * 0x426a9af2 : mov r2, r9 | dvmJitToPatchPredictedChain
2682 * 0x426a9af4 : mov r3, r10 |
2683 * 0x426a9af6 : blx r7 --+
2684 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
2685 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2686 * 0x426a9afc : blx_2 see above --+
2687 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
2688 * 0x426a9afe (0042): ldr r0, [pc, #52]
2689 * Exception_Handling:
2690 * 0x426a9b00 (0044): ldr r1, [r6, #84]
2691 * 0x426a9b02 (0046): blx r1
2692 * 0x426a9b04 (0048): .align4
2693 * -------- chaining cell (hot): 0x0021
2694 * 0x426a9b04 (0048): ldr r0, [r6, #92]
2695 * 0x426a9b06 (004a): blx r0
2696 * 0x426a9b08 (004c): data 0x7872(30834)
2697 * 0x426a9b0a (004e): data 0x428b(17035)
2698 * 0x426a9b0c (0050): .align4
2699 * -------- chaining cell (predicted)
2700 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
2701 * 0x426a9b0e (0052): data 0x0000(0)
2702 * 0x426a9b10 (0054): data 0x0000(0) --> class
2703 * 0x426a9b12 (0056): data 0x0000(0)
2704 * 0x426a9b14 (0058): data 0x0000(0) --> method
2705 * 0x426a9b16 (005a): data 0x0000(0)
2706 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
2707 * 0x426a9b1a (005e): data 0x0000(0)
2708 * 0x426a9b28 (006c): .word (0xad0392a5)
2709 * 0x426a9b2c (0070): .word (0x6e750)
2710 * 0x426a9b30 (0074): .word (0x4109a618)
2711 * 0x426a9b34 (0078): .word (0x428b786c)
2713 case OP_INVOKE_INTERFACE:
2714 case OP_INVOKE_INTERFACE_RANGE: {
2715 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2716 int methodIndex = dInsn->vB;
2718 /* Ensure that nothing is both live and dirty */
2719 dvmCompilerFlushAllRegs(cUnit);
2721 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2722 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2724 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2726 /* "this" is already left in r0 by genProcessArgs* */
2728 /* r4PC = dalvikCallsite */
2729 loadConstant(cUnit, r4PC,
2730 (int) (cUnit->method->insns + mir->offset));
2732 /* r1 = &retChainingCell */
2733 ArmLIR *addrRetChain =
2734 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
2735 addrRetChain->generic.target = (LIR *) retChainingCell;
2737 /* r2 = &predictedChainingCell */
2738 ArmLIR *predictedChainingCell =
2739 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
2740 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2742 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2744 /* return through lr - jump to the chaining cell */
2745 genUnconditionalBranch(cUnit, predChainingCell);
2748 * null-check on "this" may have been eliminated, but we still need
2749 * a PC-reconstruction label for stack overflow bailout.
2751 if (pcrLabel == NULL) {
2752 int dPC = (int) (cUnit->method->insns + mir->offset);
2753 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
2754 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
2755 pcrLabel->operands[0] = dPC;
2756 pcrLabel->operands[1] = mir->offset;
2757 /* Insert the place holder to the growable list */
2758 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2761 /* return through lr+2 - punt to the interpreter */
2762 genUnconditionalBranch(cUnit, pcrLabel);
2765 * return through lr+4 - fully resolve the callee method.
2767 * r2 <- &predictedChainCell
2770 * r7 <- this->class->vtable
2773 /* Save count, &predictedChainCell, and class to high regs first */
2774 genRegCopy(cUnit, r8, r1);
2775 genRegCopy(cUnit, r9, r2);
2776 genRegCopy(cUnit, r10, r3);
2778 /* r0 now contains this->clazz */
2779 genRegCopy(cUnit, r0, r3);
2782 loadConstant(cUnit, r1, dInsn->vB);
2784 /* r2 = method (caller) */
2785 loadConstant(cUnit, r2, (int) cUnit->method);
2788 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
2790 loadConstant(cUnit, r7,
2791 (intptr_t) dvmFindInterfaceMethodInCache);
2792 opReg(cUnit, kOpBlx, r7);
2794 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
2796 genRegCopy(cUnit, r1, r8);
2798 /* Check if rechain limit is reached */
2799 opRegImm(cUnit, kOpCmp, r1, 0);
2801 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
2803 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2804 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
2806 genRegCopy(cUnit, r2, r9);
2807 genRegCopy(cUnit, r3, r10);
2811 * r2 = &predictedChainingCell
2814 * &returnChainingCell has been loaded into r1 but is not needed
2815 * when patching the chaining cell and will be clobbered upon
2816 * returning so it will be reconstructed again.
2818 opReg(cUnit, kOpBlx, r7);
2820 /* r1 = &retChainingCell */
2821 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
2822 addrRetChain->generic.target = (LIR *) retChainingCell;
2824 bypassRechaining->generic.target = (LIR *) addrRetChain;
2827 * r0 = this, r1 = calleeMethod,
2828 * r1 = &ChainingCell,
2829 * r4PC = callsiteDPC,
2831 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2832 #if defined(INVOKE_STATS)
2833 gDvmJit.invokePredictedChain++;
2835 /* Handle exceptions using the interpreter */
2836 genTrap(cUnit, mir->offset, pcrLabel);
2840 case OP_INVOKE_DIRECT_EMPTY: {
2843 case OP_FILLED_NEW_ARRAY:
2844 case OP_FILLED_NEW_ARRAY_RANGE: {
2845 /* Just let the interpreter deal with these */
2846 genInterpSingleStep(cUnit, mir);
2855 static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
2856 BasicBlock *bb, ArmLIR *labelList)
2858 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
2859 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2860 ArmLIR *pcrLabel = NULL;
2862 DecodedInstruction *dInsn = &mir->dalvikInsn;
2863 switch (mir->dalvikInsn.opCode) {
2864 /* calleeMethod = this->clazz->vtable[BBBB] */
2865 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
2866 case OP_INVOKE_VIRTUAL_QUICK: {
2867 int methodIndex = dInsn->vB;
2868 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
2869 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2871 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2873 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2879 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2880 case OP_INVOKE_SUPER_QUICK:
2881 case OP_INVOKE_SUPER_QUICK_RANGE: {
2882 const Method *calleeMethod =
2883 cUnit->method->clazz->super->vtable[dInsn->vB];
2885 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
2886 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2888 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2890 /* r0 = calleeMethod */
2891 loadConstant(cUnit, r0, (int) calleeMethod);
2893 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2895 /* Handle exceptions using the interpreter */
2896 genTrap(cUnit, mir->offset, pcrLabel);
2906 * This operation is complex enough that we'll do it partly inline
2907 * and partly with a handler. NOTE: the handler uses hardcoded
2908 * values for string object offsets and must be revisitied if the
2911 static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
2913 #if defined(USE_GLOBAL_STRING_DEFS)
2917 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
2918 RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1);
2920 loadValueDirectFixed(cUnit, rlThis, r0);
2921 loadValueDirectFixed(cUnit, rlComp, r1);
2922 /* Test objects for NULL */
2923 rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
2924 genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback);
2926 * TUNING: we could check for object pointer equality before invoking
2927 * handler. Unclear whether the gain would be worth the added code size
2930 genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
2931 storeValue(cUnit, inlinedTarget(cUnit, mir, false),
2932 dvmCompilerGetReturn(cUnit));
2937 static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
2939 #if defined(USE_GLOBAL_STRING_DEFS)
2942 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
2943 RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1);
2945 loadValueDirectFixed(cUnit, rlThis, r0);
2946 loadValueDirectFixed(cUnit, rlChar, r1);
2948 RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
2949 loadValueDirectFixed(cUnit, rlStart, r2);
2951 loadConstant(cUnit, r2, 0);
2953 /* Test objects for NULL */
2954 genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
2955 genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
2956 storeValue(cUnit, inlinedTarget(cUnit, mir, false),
2957 dvmCompilerGetReturn(cUnit));
2962 static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
2964 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
2965 RegLocation rlDest = inlinedTarget(cUnit, mir, false);
2966 rlObj = loadValue(cUnit, rlObj, kCoreReg);
2967 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2968 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
2969 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
2971 storeValue(cUnit, rlDest, rlResult);
2975 static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
2977 int contents = offsetof(ArrayObject, contents);
2978 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
2979 RegLocation rlIdx = dvmCompilerGetSrc(cUnit, mir, 1);
2980 RegLocation rlDest = inlinedTarget(cUnit, mir, false);
2981 RegLocation rlResult;
2982 rlObj = loadValue(cUnit, rlObj, kCoreReg);
2983 rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
2984 int regMax = dvmCompilerAllocTemp(cUnit);
2985 int regOff = dvmCompilerAllocTemp(cUnit);
2986 int regPtr = dvmCompilerAllocTemp(cUnit);
2987 ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
2989 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
2990 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
2991 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
2992 genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
2993 dvmCompilerFreeTemp(cUnit, regMax);
2994 opRegImm(cUnit, kOpAdd, regPtr, contents);
2995 opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
2996 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2997 loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
2998 storeValue(cUnit, rlDest, rlResult);
3002 static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
3004 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
3005 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
3006 RegLocation rlDest = inlinedTarget(cUnit, mir, false);;
3007 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3008 int signReg = dvmCompilerAllocTemp(cUnit);
3010 * abs(x) = y<=x>>31, (x+y)^y.
3011 * Thumb2's IT block also yields 3 instructions, but imposes
3012 * scheduling constraints.
3014 opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
3015 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
3016 opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
3017 storeValue(cUnit, rlDest, rlResult);
3021 static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
3023 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
3024 RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
3025 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
3026 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3027 int signReg = dvmCompilerAllocTemp(cUnit);
3029 * abs(x) = y<=x>>31, (x+y)^y.
3030 * Thumb2 IT block allows slightly shorter sequence,
3031 * but introduces a scheduling barrier. Stick with this
3032 * mechanism for now.
3034 opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
3035 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
3036 opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg);
3037 opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
3038 opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
3039 storeValueWide(cUnit, rlDest, rlResult);
3044 * NOTE: Handles both range and non-range versions (arguments
3045 * have already been normalized by this point).
3047 static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
3049 DecodedInstruction *dInsn = &mir->dalvikInsn;
3050 switch( mir->dalvikInsn.opCode) {
3051 case OP_EXECUTE_INLINE_RANGE:
3052 case OP_EXECUTE_INLINE: {
3054 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
3055 int offset = offsetof(InterpState, retval);
3056 int operation = dInsn->vB;
3059 switch (operation) {
3060 case INLINE_EMPTYINLINEMETHOD:
3061 return false; /* Nop */
3062 case INLINE_STRING_LENGTH:
3063 return genInlinedStringLength(cUnit, mir);
3064 case INLINE_MATH_ABS_INT:
3065 return genInlinedAbsInt(cUnit, mir);
3066 case INLINE_MATH_ABS_LONG:
3067 return genInlinedAbsLong(cUnit, mir);
3068 case INLINE_MATH_MIN_INT:
3069 return genInlinedMinMaxInt(cUnit, mir, true);
3070 case INLINE_MATH_MAX_INT:
3071 return genInlinedMinMaxInt(cUnit, mir, false);
3072 case INLINE_STRING_CHARAT:
3073 return genInlinedStringCharAt(cUnit, mir);
3074 case INLINE_MATH_SQRT:
3075 if (genInlineSqrt(cUnit, mir))
3078 break; /* Handle with C routine */
3079 case INLINE_MATH_ABS_FLOAT:
3080 if (genInlinedAbsFloat(cUnit, mir))
3084 case INLINE_MATH_ABS_DOUBLE:
3085 if (genInlinedAbsDouble(cUnit, mir))
3089 case INLINE_STRING_COMPARETO:
3090 if (genInlinedCompareTo(cUnit, mir))
3094 case INLINE_STRING_INDEXOF_I:
3095 if (genInlinedIndexOf(cUnit, mir, true /* I */))
3099 case INLINE_STRING_INDEXOF_II:
3100 if (genInlinedIndexOf(cUnit, mir, false /* I */))
3104 case INLINE_STRING_EQUALS:
3105 case INLINE_MATH_COS:
3106 case INLINE_MATH_SIN:
3107 break; /* Handle with C routine */
3111 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
3112 dvmCompilerClobberCallRegs(cUnit);
3113 dvmCompilerClobber(cUnit, r4PC);
3114 dvmCompilerClobber(cUnit, r7);
3115 opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
3116 opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
3117 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3118 genExportPC(cUnit, mir);
3119 for (i=0; i < dInsn->vA; i++) {
3120 loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i);
3122 opReg(cUnit, kOpBlx, r4PC);
3123 opRegImm(cUnit, kOpAdd, r13, 8);
3124 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3125 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
3126 loadConstant(cUnit, r0,
3127 (int) (cUnit->method->insns + mir->offset));
3128 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3129 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3130 target->defMask = ENCODE_ALL;
3131 branchOver->generic.target = (LIR *) target;
3140 static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3142 //TUNING: We're using core regs here - not optimal when target is a double
3143 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
3144 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3145 loadConstantValue(cUnit, rlResult.lowReg,
3146 mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3147 loadConstantValue(cUnit, rlResult.highReg,
3148 (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3149 storeValueWide(cUnit, rlDest, rlResult);
3154 * The following are special processing routines that handle transfer of
3155 * controls between compiled code and the interpreter. Certain VM states like
3156 * Dalvik PC and special-purpose registers are reconstructed here.
3159 /* Chaining cell for code that may need warmup. */
3160 static void handleNormalChainingCell(CompilationUnit *cUnit,
3161 unsigned int offset)
3163 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3164 jitToInterpEntries.dvmJitToInterpNormal), r0);
3165 opReg(cUnit, kOpBlx, r0);
3166 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3170 * Chaining cell for instructions that immediately following already translated
3173 static void handleHotChainingCell(CompilationUnit *cUnit,
3174 unsigned int offset)
3176 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3177 jitToInterpEntries.dvmJitToInterpTraceSelect), r0);
3178 opReg(cUnit, kOpBlx, r0);
3179 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3182 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
3183 /* Chaining cell for branches that branch back into the same basic block */
3184 static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3185 unsigned int offset)
3187 #if defined(WITH_SELF_VERIFICATION)
3188 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
3189 offsetof(InterpState,
3190 jitToInterpEntries.dvmJitToInterpBackwardBranch) >> 2);
3192 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
3193 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3195 newLIR1(cUnit, kThumbBlxR, r0);
3196 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3200 /* Chaining cell for monomorphic method invocations. */
3201 static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3202 const Method *callee)
3204 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3205 jitToInterpEntries.dvmJitToInterpTraceSelect), r0);
3206 opReg(cUnit, kOpBlx, r0);
3207 addWordData(cUnit, (int) (callee->insns), true);
3210 /* Chaining cell for monomorphic method invocations. */
3211 static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3214 /* Should not be executed in the initial state */
3215 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3216 /* To be filled: class */
3217 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3218 /* To be filled: method */
3219 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3221 * Rechain count. The initial value of 0 here will trigger chaining upon
3222 * the first invocation of this callsite.
3224 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3227 /* Load the Dalvik PC into r0 and jump to the specified target */
3228 static void handlePCReconstruction(CompilationUnit *cUnit,
3229 ArmLIR *targetLabel)
3232 (ArmLIR **) cUnit->pcReconstructionList.elemList;
3233 int numElems = cUnit->pcReconstructionList.numUsed;
3235 for (i = 0; i < numElems; i++) {
3236 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3237 /* r0 = dalvik PC */
3238 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3239 genUnconditionalBranch(cUnit, targetLabel);
3243 static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
3245 "kMirOpNullNRangeUpCheck",
3246 "kMirOpNullNRangeDownCheck",
3254 * vC = endConditionReg;
3257 * arg[2] = loopBranchConditionCode
3259 static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3262 * NOTE: these synthesized blocks don't have ssa names assigned
3263 * for Dalvik registers. However, because they dominate the following
3264 * blocks we can simply use the Dalvik name w/ subscript 0 as the
3267 DecodedInstruction *dInsn = &mir->dalvikInsn;
3268 const int lenOffset = offsetof(ArrayObject, length);
3269 const int maxC = dInsn->arg[0];
3270 const int minC = dInsn->arg[1];
3272 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3273 RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
3275 /* regArray <- arrayRef */
3276 rlArray = loadValue(cUnit, rlArray, kCoreReg);
3277 rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
3278 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
3279 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3281 /* regLength <- len(arrayRef) */
3282 regLength = dvmCompilerAllocTemp(cUnit);
3283 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
3287 * If the loop end condition is ">=" instead of ">", then the largest value
3288 * of the index is "endCondition - 1".
3290 if (dInsn->arg[2] == OP_IF_GE) {
3295 int tReg = dvmCompilerAllocTemp(cUnit);
3296 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
3297 rlIdxEnd.lowReg = tReg;
3298 dvmCompilerFreeTemp(cUnit, tReg);
3300 /* Punt if "regIdxEnd < len(Array)" is false */
3301 genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
3302 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3308 * vC = endConditionReg;
3311 * arg[2] = loopBranchConditionCode
3313 static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3315 DecodedInstruction *dInsn = &mir->dalvikInsn;
3316 const int lenOffset = offsetof(ArrayObject, length);
3317 const int regLength = dvmCompilerAllocTemp(cUnit);
3318 const int maxC = dInsn->arg[0];
3319 const int minC = dInsn->arg[1];
3320 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3321 RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
3323 /* regArray <- arrayRef */
3324 rlArray = loadValue(cUnit, rlArray, kCoreReg);
3325 rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
3326 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
3327 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3329 /* regLength <- len(arrayRef) */
3330 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
3333 int tReg = dvmCompilerAllocTemp(cUnit);
3334 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
3335 rlIdxInit.lowReg = tReg;
3336 dvmCompilerFreeTemp(cUnit, tReg);
3339 /* Punt if "regIdxInit < len(Array)" is false */
3340 genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
3341 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3348 static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3350 DecodedInstruction *dInsn = &mir->dalvikInsn;
3351 const int minC = dInsn->vB;
3352 RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
3354 /* regIdx <- initial index value */
3355 rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
3357 /* Punt if "regIdxInit + minC >= 0" is false */
3358 genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
3359 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3362 /* Extended MIR instructions like PHI */
3363 static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3365 int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
3366 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3368 strcpy(msg, extendedMIROpNames[opOffset]);
3369 newLIR1(cUnit, kArmPseudoExtended, (int) msg);
3371 switch (mir->dalvikInsn.opCode) {
3373 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3374 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
3377 case kMirOpNullNRangeUpCheck: {
3378 genHoistedChecksForCountUpLoop(cUnit, mir);
3381 case kMirOpNullNRangeDownCheck: {
3382 genHoistedChecksForCountDownLoop(cUnit, mir);
3385 case kMirOpLowerBound: {
3386 genHoistedLowerBoundCheck(cUnit, mir);
3390 genUnconditionalBranch(cUnit,
3391 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3400 * Create a PC-reconstruction cell for the starting offset of this trace.
3401 * Since the PCR cell is placed near the end of the compiled code which is
3402 * usually out of range for a conditional branch, we put two branches (one
3403 * branch over to the loop body and one layover branch to the actual PCR) at the
3404 * end of the entry block.
3406 static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3409 /* Set up the place holder to reconstruct this Dalvik PC */
3410 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3411 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
3412 pcrLabel->operands[0] =
3413 (int) (cUnit->method->insns + entry->startOffset);
3414 pcrLabel->operands[1] = entry->startOffset;
3415 /* Insert the place holder to the growable list */
3416 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3419 * Next, create two branches - one branch over to the loop body and the
3420 * other branch to the PCR cell to punt.
3422 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
3423 branchToBody->opCode = kThumbBUncond;
3424 branchToBody->generic.target = (LIR *) bodyLabel;
3425 setupResourceMasks(branchToBody);
3426 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3428 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
3429 branchToPCR->opCode = kThumbBUncond;
3430 branchToPCR->generic.target = (LIR *) pcrLabel;
3431 setupResourceMasks(branchToPCR);
3432 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3435 void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3437 /* Used to hold the labels of each block */
3439 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
3440 GrowableList chainingListByType[kChainingCellGap];
3444 * Initialize various types chaining lists.
3446 for (i = 0; i < kChainingCellGap; i++) {
3447 dvmInitGrowableList(&chainingListByType[i], 2);
3450 BasicBlock **blockList = cUnit->blockList;
3452 if (cUnit->executionCount) {
3454 * Reserve 6 bytes at the beginning of the trace
3455 * +----------------------------+
3456 * | execution count (4 bytes) |
3457 * +----------------------------+
3458 * | chain cell offset (2 bytes)|
3459 * +----------------------------+
3460 * ...and then code to increment the execution
3462 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3463 * sub r0, #10 @ back up to addr of executionCount
3468 newLIR1(cUnit, kArm16BitData, 0);
3469 newLIR1(cUnit, kArm16BitData, 0);
3470 cUnit->chainCellOffsetLIR =
3471 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
3472 cUnit->headerSize = 6;
3473 /* Thumb instruction used directly here to ensure correct size */
3474 newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc);
3475 newLIR2(cUnit, kThumbSubRI8, r0, 10);
3476 newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
3477 newLIR2(cUnit, kThumbAddRI8, r1, 1);
3478 newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
3480 /* Just reserve 2 bytes for the chain cell offset */
3481 cUnit->chainCellOffsetLIR =
3482 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
3483 cUnit->headerSize = 2;
3486 /* Handle the content in each basic block */
3487 for (i = 0; i < cUnit->numBlocks; i++) {
3488 blockList[i]->visited = true;
3491 labelList[i].operands[0] = blockList[i]->startOffset;
3493 if (blockList[i]->blockType >= kChainingCellGap) {
3495 * Append the label pseudo LIR first. Chaining cells will be handled
3496 * separately afterwards.
3498 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3501 if (blockList[i]->blockType == kEntryBlock) {
3502 labelList[i].opCode = ARM_PSEUDO_kEntryBlock;
3503 if (blockList[i]->firstMIRInsn == NULL) {
3506 setupLoopEntryBlock(cUnit, blockList[i],
3507 &labelList[blockList[i]->fallThrough->id]);
3509 } else if (blockList[i]->blockType == kExitBlock) {
3510 labelList[i].opCode = ARM_PSEUDO_kExitBlock;
3511 goto gen_fallthrough;
3512 } else if (blockList[i]->blockType == kDalvikByteCode) {
3513 labelList[i].opCode = kArmPseudoNormalBlockLabel;
3514 /* Reset the register state */
3515 dvmCompilerResetRegPool(cUnit);
3516 dvmCompilerClobberAllRegs(cUnit);
3517 dvmCompilerResetNullCheck(cUnit);
3519 switch (blockList[i]->blockType) {
3520 case kChainingCellNormal:
3521 labelList[i].opCode = ARM_PSEUDO_kChainingCellNormal;
3522 /* handle the codegen later */
3523 dvmInsertGrowableList(
3524 &chainingListByType[kChainingCellNormal], (void *) i);
3526 case kChainingCellInvokeSingleton:
3527 labelList[i].opCode =
3528 ARM_PSEUDO_kChainingCellInvokeSingleton;
3529 labelList[i].operands[0] =
3530 (int) blockList[i]->containingMethod;
3531 /* handle the codegen later */
3532 dvmInsertGrowableList(
3533 &chainingListByType[kChainingCellInvokeSingleton],
3536 case kChainingCellInvokePredicted:
3537 labelList[i].opCode =
3538 ARM_PSEUDO_kChainingCellInvokePredicted;
3539 /* handle the codegen later */
3540 dvmInsertGrowableList(
3541 &chainingListByType[kChainingCellInvokePredicted],
3544 case kChainingCellHot:
3545 labelList[i].opCode =
3546 ARM_PSEUDO_kChainingCellHot;
3547 /* handle the codegen later */
3548 dvmInsertGrowableList(
3549 &chainingListByType[kChainingCellHot],
3552 case kPCReconstruction:
3553 /* Make sure exception handling block is next */
3554 labelList[i].opCode =
3555 ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL;
3556 assert (i == cUnit->numBlocks - 2);
3557 handlePCReconstruction(cUnit, &labelList[i+1]);
3559 case kExceptionHandling:
3560 labelList[i].opCode = kArmPseudoEHBlockLabel;
3561 if (cUnit->pcReconstructionList.numUsed) {
3562 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3563 jitToInterpEntries.dvmJitToInterpPunt),
3565 opReg(cUnit, kOpBlx, r1);
3568 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
3569 case kChainingCellBackwardBranch:
3570 labelList[i].opCode =
3571 ARM_PSEUDO_kChainingCellBackwardBranch;
3572 /* handle the codegen later */
3573 dvmInsertGrowableList(
3574 &chainingListByType[kChainingCellBackwardBranch],
3584 ArmLIR *headLIR = NULL;
3586 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
3588 dvmCompilerResetRegPool(cUnit);
3589 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
3590 dvmCompilerClobberAllRegs(cUnit);
3593 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
3594 dvmCompilerResetDefTracking(cUnit);
3597 if (mir->dalvikInsn.opCode >= kMirOpFirst) {
3598 handleExtendedMIR(cUnit, mir);
3603 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3604 InstructionFormat dalvikFormat =
3605 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
3606 ArmLIR *boundaryLIR =
3607 newLIR2(cUnit, ARM_PSEUDO_kDalvikByteCode_BOUNDARY,
3609 (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
3612 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3613 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
3616 /* Remember the first LIR for this block */
3617 if (headLIR == NULL) {
3618 headLIR = boundaryLIR;
3619 /* Set the first boundaryLIR as a scheduling barrier */
3620 headLIR->defMask = ENCODE_ALL;
3625 * Debugging: screen the opcode first to see if it is in the
3626 * do[-not]-compile list
3629 gDvmJit.includeSelectedOp !=
3630 ((gDvmJit.opList[dalvikOpCode >> 3] &
3631 (1 << (dalvikOpCode & 0x7))) !=
3633 if (singleStepMe || cUnit->allSingleStep) {
3635 genInterpSingleStep(cUnit, mir);
3637 opcodeCoverage[dalvikOpCode]++;
3638 switch (dalvikFormat) {
3642 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3643 mir, blockList[i], labelList);
3646 notHandled = handleFmt10x(cUnit, mir);
3650 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3653 notHandled = handleFmt11x(cUnit, mir);
3656 notHandled = handleFmt12x(cUnit, mir);
3659 notHandled = handleFmt20bc(cUnit, mir);
3663 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3666 notHandled = handleFmt21h(cUnit, mir);
3669 notHandled = handleFmt21s(cUnit, mir);
3672 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3677 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3680 notHandled = handleFmt22c(cUnit, mir);
3683 notHandled = handleFmt22cs(cUnit, mir);
3686 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3691 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3694 notHandled = handleFmt23x(cUnit, mir);
3697 notHandled = handleFmt31t(cUnit, mir);
3701 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3706 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3711 notHandled = handleExecuteInline(cUnit, mir);
3714 notHandled = handleFmt51l(cUnit, mir);
3722 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3724 dalvikOpCode, getOpcodeName(dalvikOpCode),
3731 if (blockList[i]->blockType == kEntryBlock) {
3732 dvmCompilerAppendLIR(cUnit,
3733 (LIR *) cUnit->loopAnalysis->branchToBody);
3734 dvmCompilerAppendLIR(cUnit,
3735 (LIR *) cUnit->loopAnalysis->branchToPCR);
3740 * Eliminate redundant loads/stores and delay stores into later
3743 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3744 cUnit->lastLIRInsn);
3749 * Check if the block is terminated due to trace length constraint -
3750 * insert an unconditional branch to the chaining cell.
3752 if (blockList[i]->needFallThroughBranch) {
3753 genUnconditionalBranch(cUnit,
3754 &labelList[blockList[i]->fallThrough->id]);
3759 /* Handle the chaining cells in predefined order */
3760 for (i = 0; i < kChainingCellGap; i++) {
3762 int *blockIdList = (int *) chainingListByType[i].elemList;
3764 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3766 /* No chaining cells of this type */
3767 if (cUnit->numChainingCells[i] == 0)
3770 /* Record the first LIR for a new type of chaining cell */
3771 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3773 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3774 int blockId = blockIdList[j];
3776 /* Align this chaining cell first */
3777 newLIR0(cUnit, kArmPseudoPseudoAlign4);
3779 /* Insert the pseudo chaining instruction */
3780 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3783 switch (blockList[blockId]->blockType) {
3784 case kChainingCellNormal:
3785 handleNormalChainingCell(cUnit,
3786 blockList[blockId]->startOffset);
3788 case kChainingCellInvokeSingleton:
3789 handleInvokeSingletonChainingCell(cUnit,
3790 blockList[blockId]->containingMethod);
3792 case kChainingCellInvokePredicted:
3793 handleInvokePredictedChainingCell(cUnit);
3795 case kChainingCellHot:
3796 handleHotChainingCell(cUnit,
3797 blockList[blockId]->startOffset);
3799 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
3800 case kChainingCellBackwardBranch:
3801 handleBackwardBranchChainingCell(cUnit,
3802 blockList[blockId]->startOffset);
3806 LOGE("Bad blocktype %d", blockList[blockId]->blockType);
3813 /* Mark the bottom of chaining cells */
3814 cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kArmChainingCellBottom);
3817 * Generate the branch to the dvmJitToInterpNoChain entry point at the end
3818 * of all chaining cells for the overflow cases.
3820 if (cUnit->switchOverflowPad) {
3821 loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad);
3822 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3823 jitToInterpEntries.dvmJitToInterpNoChain), r2);
3824 opRegReg(cUnit, kOpAdd, r1, r1);
3825 opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
3826 #if defined(EXIT_STATS)
3827 loadConstant(cUnit, r0, kSwitchOverflow);
3829 opReg(cUnit, kOpBlx, r2);
3832 dvmCompilerApplyGlobalOptimizations(cUnit);
3834 #if defined(WITH_SELF_VERIFICATION)
3835 selfVerificationBranchInsertPass(cUnit);
3839 /* Accept the work and start compiling */
3840 bool dvmCompilerDoWork(CompilerWorkOrder *work)
3844 if (gDvmJit.codeCacheFull) {
3848 switch (work->kind) {
3849 case kWorkOrderMethod:
3850 res = dvmCompileMethod(work->info, &work->result);
3852 case kWorkOrderTrace:
3853 /* Start compilation with maximally allowed trace length */
3854 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
3856 case kWorkOrderTraceDebug: {
3857 bool oldPrintMe = gDvmJit.printMe;
3858 gDvmJit.printMe = true;
3859 /* Start compilation with maximally allowed trace length */
3860 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
3861 gDvmJit.printMe = oldPrintMe;;
3871 /* Architectural-specific debugging helpers go here */
3872 void dvmCompilerArchDump(void)
3874 /* Print compiled opcode in this VM instance */
3875 int i, start, streak;
3880 while (opcodeCoverage[i] == 0 && i < 256) {
3886 for (start = i++, streak = 1; i < 256; i++) {
3887 if (opcodeCoverage[i]) {
3891 sprintf(buf+strlen(buf), "%x,", start);
3893 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3896 while (opcodeCoverage[i] == 0 && i < 256) {
3907 sprintf(buf+strlen(buf), "%x", start);
3909 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3913 LOGD("dalvik.vm.jit.op = %s", buf);
3917 /* Common initialization routine for an architecture family */
3918 bool dvmCompilerArchInit()
3922 for (i = 0; i < kArmLast; i++) {
3923 if (EncodingMap[i].opCode != i) {
3924 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
3925 EncodingMap[i].name, i, EncodingMap[i].opCode);
3930 return dvmCompilerArchVariantInit();
3933 void *dvmCompilerGetInterpretTemplate()
3935 return (void*) ((int)gDvmJit.codeCache +
3936 templateEntryOffsets[TEMPLATE_INTERPRET]);
3939 /* Needed by the ld/st optmizatons */
3940 ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
3942 return genRegCopyNoInsert(cUnit, rDest, rSrc);
3945 /* Needed by the register allocator */
3946 ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
3948 return genRegCopy(cUnit, rDest, rSrc);
3951 /* Needed by the register allocator */
3952 void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
3953 int srcLo, int srcHi)
3955 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
3958 void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
3959 int displacement, int rSrc, OpSize size)
3961 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
3964 void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
3965 int displacement, int rSrcLo, int rSrcHi)
3967 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);