aboutsummaryrefslogtreecommitdiff
path: root/vm/compiler/codegen/arm/CodegenDriver.c
diff options
context:
space:
mode:
Diffstat (limited to 'vm/compiler/codegen/arm/CodegenDriver.c')
-rw-r--r--vm/compiler/codegen/arm/CodegenDriver.c301
1 files changed, 183 insertions, 118 deletions
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index e9f00dda1..f625771ec 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -197,7 +197,6 @@ static void selfVerificationBranchInsert(LIR *currentLIR, ArmOpCode opCode,
static void selfVerificationBranchInsertPass(CompilationUnit *cUnit)
{
ArmLIR *thisLIR;
- ArmLIR *branchLIR = dvmCompilerNew(sizeof(ArmLIR), true);
TemplateOpCode opCode = TEMPLATE_MEM_OP_DECODE;
for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn;
@@ -237,7 +236,6 @@ static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
/* Load a wide field from an object instance */
static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
{
- DecodedInstruction *dInsn = &mir->dalvikInsn;
RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
RegLocation rlResult;
@@ -262,7 +260,6 @@ static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
/* Store a wide field to an object instance */
static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
{
- DecodedInstruction *dInsn = &mir->dalvikInsn;
RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 2);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
@@ -287,9 +284,7 @@ static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
int fieldOffset)
{
- int regPtr;
RegLocation rlResult;
- DecodedInstruction *dInsn = &mir->dalvikInsn;
RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
@@ -312,12 +307,10 @@ static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
int fieldOffset)
{
- DecodedInstruction *dInsn = &mir->dalvikInsn;
RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 1);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
- int regPtr;
genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
NULL);/* null object? */
@@ -872,7 +865,7 @@ static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
{
genDispatchToHandler(cUnit, TEMPLATE_RETURN);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.returnOp++;
#endif
int dPC = (int) (cUnit->method->insns + mir->offset);
@@ -1042,12 +1035,12 @@ static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
*/
if (dvmIsNativeMethod(calleeMethod)) {
genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.invokeNative++;
#endif
} else {
genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.invokeMonomorphic++;
#endif
/* Branch to the chaining cell */
@@ -1147,6 +1140,8 @@ static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
+ genRegCopy(cUnit, r1, rGLUE);
+
/*
* r0 = calleeMethod
* r2 = &predictedChainingCell
@@ -1169,73 +1164,13 @@ static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
* r4PC = callsiteDPC,
*/
genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.invokePolymorphic++;
#endif
/* Handle exceptions using the interpreter */
genTrap(cUnit, mir->offset, pcrLabel);
}
-/*
- * Up calling this function, "this" is stored in r0. The actual class will be
- * chased down off r0 and the predicted one will be retrieved through
- * predictedChainingCell then a comparison is performed to see whether the
- * previously established chaining is still valid.
- *
- * The return LIR is a branch based on the comparison result. The actual branch
- * target will be setup in the caller.
- */
-static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
- ArmLIR *predChainingCell,
- ArmLIR *retChainingCell,
- MIR *mir)
-{
- /*
- * Note: all Dalvik register state should be flushed to
- * memory by the point, so register usage restrictions no
- * longer apply. All temp & preserved registers may be used.
- */
- dvmCompilerLockAllTemps(cUnit);
-
- /* r3 now contains this->clazz */
- loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
-
- /*
- * r2 now contains predicted class. The starting offset of the
- * cached value is 4 bytes into the chaining cell.
- */
- ArmLIR *getPredictedClass =
- loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
- getPredictedClass->generic.target = (LIR *) predChainingCell;
-
- /*
- * r0 now contains predicted method. The starting offset of the
- * cached value is 8 bytes into the chaining cell.
- */
- ArmLIR *getPredictedMethod =
- loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
- getPredictedMethod->generic.target = (LIR *) predChainingCell;
-
- /* Load the stats counter to see if it is time to unchain and refresh */
- ArmLIR *getRechainingRequestCount =
- loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
- getRechainingRequestCount->generic.target =
- (LIR *) predChainingCell;
-
- /* r4PC = dalvikCallsite */
- loadConstant(cUnit, r4PC,
- (int) (cUnit->method->insns + mir->offset));
-
- /* r1 = &retChainingCell */
- ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
- addrRetChain->generic.target = (LIR *) retChainingCell;
-
- /* Check if r2 (predicted class) == r3 (actual class) */
- opRegReg(cUnit, kOpCmp, r2, r3);
-
- return opCondBranch(cUnit, kArmCondEq);
-}
-
/* Geneate a branch to go back to the interpreter */
static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
{
@@ -1343,7 +1278,7 @@ static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
{
OpCode dalvikOpCode = mir->dalvikInsn.opCode;
if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
- ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EB))) {
+ ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_E7))) {
LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
return true;
}
@@ -1446,7 +1381,12 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
case OP_CONST_STRING: {
void *strPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
- assert(strPtr != NULL);
+
+ if (strPtr == NULL) {
+ LOGE("Unexpected null string");
+ dvmAbort();
+ }
+
rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr );
@@ -1456,7 +1396,12 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
case OP_CONST_CLASS: {
void *classPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
- assert(classPtr != NULL);
+
+ if (classPtr == NULL) {
+ LOGE("Unexpected null class");
+ dvmAbort();
+ }
+
rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr );
@@ -1473,7 +1418,12 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
int tReg = dvmCompilerAllocTemp(cUnit);
void *fieldPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
- assert(fieldPtr != NULL);
+
+ if (fieldPtr == NULL) {
+ LOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
rlDest = dvmCompilerGetDest(cUnit, mir, 0);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
@@ -1489,8 +1439,13 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
int valOffset = offsetof(StaticField, value);
void *fieldPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+ if (fieldPtr == NULL) {
+ LOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
int tReg = dvmCompilerAllocTemp(cUnit);
- assert(fieldPtr != NULL);
rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
@@ -1513,7 +1468,11 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
void *fieldPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
- assert(fieldPtr != NULL);
+ if (fieldPtr == NULL) {
+ LOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
@@ -1530,7 +1489,11 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
void *fieldPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
- assert(fieldPtr != NULL);
+ if (fieldPtr == NULL) {
+ LOGE("Unexpected null static field");
+ dvmAbort();
+ }
+
rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
@@ -1547,8 +1510,12 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
*/
ClassObject *classPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
- assert(classPtr != NULL);
- assert(classPtr->status & CLASS_INITIALIZED);
+
+ if (classPtr == NULL) {
+ LOGE("Unexpected null class");
+ dvmAbort();
+ }
+
/*
* If it is going to throw, it should not make to the trace to begin
* with. However, Alloc might throw, so we need to genExportPC()
@@ -1898,6 +1865,57 @@ static int lowestSetBit(unsigned int x) {
return bit_posn;
}
+// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
+// and store the result in 'rlDest'.
+static bool handleEasyDivide(CompilationUnit *cUnit, OpCode dalvikOpCode,
+ RegLocation rlSrc, RegLocation rlDest, int lit)
+{
+ if (lit < 2 || !isPowerOfTwo(lit)) {
+ return false;
+ }
+ int k = lowestSetBit(lit);
+ if (k >= 30) {
+ // Avoid special cases.
+ return false;
+ }
+ bool div = (dalvikOpCode == OP_DIV_INT_LIT8 || dalvikOpCode == OP_DIV_INT_LIT16);
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
+ if (div) {
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ if (lit == 2) {
+ // Division by 2 is by far the most common division by constant.
+ opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
+ opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
+ } else {
+ opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
+ opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
+ opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
+ }
+ } else {
+ int cReg = dvmCompilerAllocTemp(cUnit);
+ loadConstant(cUnit, cReg, lit - 1);
+ int tReg1 = dvmCompilerAllocTemp(cUnit);
+ int tReg2 = dvmCompilerAllocTemp(cUnit);
+ if (lit == 2) {
+ opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
+ opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
+ opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
+ } else {
+ opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
+ opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
+ opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
+ opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
+ opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
+ }
+ }
+ storeValue(cUnit, rlDest, rlResult);
+ return true;
+}
+
// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
// and store the result in 'rlDest'.
static bool handleEasyMultiply(CompilationUnit *cUnit,
@@ -2019,6 +2037,9 @@ static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
genInterpSingleStep(cUnit, mir);
return false;
}
+ if (handleEasyDivide(cUnit, dalvikOpCode, rlSrc, rlDest, lit)) {
+ return false;
+ }
dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
loadValueDirectFixed(cUnit, rlSrc, r0);
dvmCompilerClobber(cUnit, r0);
@@ -2064,7 +2085,11 @@ static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
InstField *pInstField = (InstField *)
cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
- assert(pInstField != NULL);
+ if (pInstField == NULL) {
+ LOGE("Unexpected null instance field");
+ dvmAbort();
+ }
+
fieldOffset = pInstField->byteOffset;
} else {
/* Deliberately break the code while make the compiler happy */
@@ -2078,7 +2103,12 @@ static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
RegLocation rlResult;
void *classPtr = (void*)
(cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
- assert(classPtr != NULL);
+
+ if (classPtr == NULL) {
+ LOGE("Unexpected null class");
+ dvmAbort();
+ }
+
dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
genExportPC(cUnit, mir);
loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */
@@ -2088,8 +2118,7 @@ static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
* "len < 0": bail to the interpreter to re-execute the
* instruction
*/
- ArmLIR *pcrLabel =
- genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
+ genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
opReg(cUnit, kOpBlx, r3);
dvmCompilerClobberCallRegs(cUnit);
@@ -2192,6 +2221,12 @@ static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
case OP_IPUT_BOOLEAN:
genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
break;
+ case OP_IGET_WIDE_VOLATILE:
+ case OP_IPUT_WIDE_VOLATILE:
+ case OP_SGET_WIDE_VOLATILE:
+ case OP_SPUT_WIDE_VOLATILE:
+ genInterpSingleStep(cUnit, mir);
+ break;
default:
return true;
}
@@ -2400,10 +2435,10 @@ static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
* blx &findPackedSwitchIndex
* mov pc, r0
* .align4
- * chaining cell for case 0 [8 bytes]
- * chaining cell for case 1 [8 bytes]
+ * chaining cell for case 0 [12 bytes]
+ * chaining cell for case 1 [12 bytes]
* :
- * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [8 bytes]
+ * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [12 bytes]
* chaining cell for case default [8 bytes]
* noChain exit
*/
@@ -2454,7 +2489,7 @@ static s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
jumpIndex = index;
}
- chainingPC += jumpIndex * 8;
+ chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE;
return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
}
@@ -2505,13 +2540,14 @@ static s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
/* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
i : MAX_CHAINED_SWITCH_CASES + 1;
- chainingPC += jumpIndex * 8;
+ chainingPC += jumpIndex * CHAIN_CELL_NORMAL_SIZE;
return (((s8) entries[i]) << 32) | (u8) chainingPC;
} else if (k > testVal) {
break;
}
}
- return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 8;
+ return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) *
+ CHAIN_CELL_NORMAL_SIZE;
}
static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
@@ -2551,10 +2587,6 @@ static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
loadValueDirectFixed(cUnit, rlSrc, r1);
dvmCompilerLockAllTemps(cUnit);
- const u2 *switchData =
- cUnit->method->insns + mir->offset + mir->dalvikInsn.vB;
- u2 size = switchData[1];
-
if (dalvikOpCode == OP_PACKED_SWITCH) {
LOAD_FUNC_ADDR(cUnit, r4PC, (int)findPackedSwitchIndex);
} else {
@@ -2746,7 +2778,6 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
case OP_INVOKE_INTERFACE:
case OP_INVOKE_INTERFACE_RANGE: {
ArmLIR *predChainingCell = &labelList[bb->taken->id];
- int methodIndex = dInsn->vB;
/* Ensure that nothing is both live and dirty */
dvmCompilerFlushAllRegs(cUnit);
@@ -2851,6 +2882,7 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
+ genRegCopy(cUnit, r1, rGLUE);
genRegCopy(cUnit, r2, r9);
genRegCopy(cUnit, r3, r10);
@@ -2877,7 +2909,7 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
* r4PC = callsiteDPC,
*/
genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
gDvmJit.invokePolymorphic++;
#endif
/* Handle exceptions using the interpreter */
@@ -2982,7 +3014,7 @@ static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
#endif
}
-static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
+static bool genInlinedFastIndexOf(CompilationUnit *cUnit, MIR *mir)
{
#if defined(USE_GLOBAL_STRING_DEFS)
return false;
@@ -2992,12 +3024,8 @@ static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
loadValueDirectFixed(cUnit, rlThis, r0);
loadValueDirectFixed(cUnit, rlChar, r1);
- if (!singleI) {
- RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
- loadValueDirectFixed(cUnit, rlStart, r2);
- } else {
- loadConstant(cUnit, r2, 0);
- }
+ RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
+ loadValueDirectFixed(cUnit, rlStart, r2);
/* Test objects for NULL */
genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
@@ -3007,8 +3035,11 @@ static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
#endif
}
-static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
+// Generates an inlined String.isEmpty or String.length.
+static bool genInlinedStringIsEmptyOrLength(CompilationUnit *cUnit, MIR *mir,
+ bool isEmpty)
{
+ // dst = src.length();
RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
RegLocation rlDest = inlinedTarget(cUnit, mir, false);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
@@ -3016,10 +3047,26 @@ static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
rlResult.lowReg);
+ if (isEmpty) {
+ // dst = (dst == 0);
+ int tReg = dvmCompilerAllocTemp(cUnit);
+ opRegReg(cUnit, kOpNeg, tReg, rlResult.lowReg);
+ opRegRegReg(cUnit, kOpAdc, rlResult.lowReg, rlResult.lowReg, tReg);
+ }
storeValue(cUnit, rlDest, rlResult);
return false;
}
+static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
+{
+ return genInlinedStringIsEmptyOrLength(cUnit, mir, false);
+}
+
+static bool genInlinedStringIsEmpty(CompilationUnit *cUnit, MIR *mir)
+{
+ return genInlinedStringIsEmptyOrLength(cUnit, mir, true);
+}
+
static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
{
int contents = offsetof(ArrayObject, contents);
@@ -3102,13 +3149,13 @@ static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
const InlineOperation* inLineTable = dvmGetInlineOpsTable();
int offset = offsetof(InterpState, retval);
int operation = dInsn->vB;
- int tReg1;
- int tReg2;
switch (operation) {
case INLINE_EMPTYINLINEMETHOD:
return false; /* Nop */
case INLINE_STRING_LENGTH:
return genInlinedStringLength(cUnit, mir);
+ case INLINE_STRING_IS_EMPTY:
+ return genInlinedStringIsEmpty(cUnit, mir);
case INLINE_MATH_ABS_INT:
return genInlinedAbsInt(cUnit, mir);
case INLINE_MATH_ABS_LONG:
@@ -3139,13 +3186,8 @@ static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
return false;
else
break;
- case INLINE_STRING_INDEXOF_I:
- if (genInlinedIndexOf(cUnit, mir, true /* I */))
- return false;
- else
- break;
- case INLINE_STRING_INDEXOF_II:
- if (genInlinedIndexOf(cUnit, mir, false /* I */))
+ case INLINE_STRING_FASTINDEXOF_II:
+ if (genInlinedFastIndexOf(cUnit, mir))
return false;
else
break;
@@ -3204,6 +3246,27 @@ static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
* Dalvik PC and special-purpose registers are reconstructed here.
*/
+/*
+ * Insert a
+ * b .+4
+ * nop
+ * pair at the beginning of a chaining cell. This serves as the
+ * switch branch that selects between reverting to the interpreter or
+ * not. Once the cell is chained to a translation, the cell will
+ * contain a 32-bit branch. Subsequent chain/unchain operations will
+ * then only alter that first 16-bits - the "b .+4" for unchaining,
+ * and the restoration of the first half of the 32-bit branch for
+ * rechaining.
+ */
+static void insertChainingSwitch(CompilationUnit *cUnit)
+{
+ ArmLIR *branch = newLIR0(cUnit, kThumbBUncond);
+ newLIR2(cUnit, kThumbOrr, r0, r0);
+ ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branch->generic.target = (LIR *) target;
+}
+
/* Chaining cell for code that may need warmup. */
static void handleNormalChainingCell(CompilationUnit *cUnit,
unsigned int offset)
@@ -3212,6 +3275,7 @@ static void handleNormalChainingCell(CompilationUnit *cUnit,
* Use raw instruction constructors to guarantee that the generated
* instructions fit the predefined cell size.
*/
+ insertChainingSwitch(cUnit);
newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
offsetof(InterpState,
jitToInterpEntries.dvmJitToInterpNormal) >> 2);
@@ -3230,6 +3294,7 @@ static void handleHotChainingCell(CompilationUnit *cUnit,
* Use raw instruction constructors to guarantee that the generated
* instructions fit the predefined cell size.
*/
+ insertChainingSwitch(cUnit);
newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
offsetof(InterpState,
jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2);
@@ -3246,6 +3311,7 @@ static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
* Use raw instruction constructors to guarantee that the generated
* instructions fit the predefined cell size.
*/
+ insertChainingSwitch(cUnit);
#if defined(WITH_SELF_VERIFICATION)
newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
offsetof(InterpState,
@@ -3267,6 +3333,7 @@ static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
* Use raw instruction constructors to guarantee that the generated
* instructions fit the predefined cell size.
*/
+ insertChainingSwitch(cUnit);
newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
offsetof(InterpState,
jitToInterpEntries.dvmJitToInterpTraceSelect) >> 2);
@@ -3334,7 +3401,6 @@ static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
DecodedInstruction *dInsn = &mir->dalvikInsn;
const int lenOffset = offsetof(ArrayObject, length);
const int maxC = dInsn->arg[0];
- const int minC = dInsn->arg[1];
int regLength;
RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
@@ -3383,7 +3449,6 @@ static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
const int lenOffset = offsetof(ArrayObject, length);
const int regLength = dvmCompilerAllocTemp(cUnit);
const int maxC = dInsn->arg[0];
- const int minC = dInsn->arg[1];
RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
@@ -3914,7 +3979,7 @@ gen_fallthrough:
jitToInterpEntries.dvmJitToInterpNoChain), r2);
opRegReg(cUnit, kOpAdd, r1, r1);
opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
-#if defined(JIT_STATS)
+#if defined(WITH_JIT_TUNING)
loadConstant(cUnit, r0, kSwitchOverflow);
#endif
opReg(cUnit, kOpBlx, r2);
@@ -3951,13 +4016,13 @@ bool dvmCompilerDoWork(CompilerWorkOrder *work)
/* Start compilation with maximally allowed trace length */
res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
work->bailPtr);
- gDvmJit.printMe = oldPrintMe;;
+ gDvmJit.printMe = oldPrintMe;
break;
}
default:
res = false;
LOGE("Jit: unknown work order type");
- assert(0); // Bail if debug build, discard oteherwise
+ assert(0); // Bail if debug build, discard otherwise
}
return res;
}