diff options
Diffstat (limited to 'vm/compiler/codegen/arm/CodegenDriver.c')
| -rw-r--r-- | vm/compiler/codegen/arm/CodegenDriver.c | 219 |
1 files changed, 179 insertions, 40 deletions
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c index e9f00dda1..515e8afa9 100644 --- a/vm/compiler/codegen/arm/CodegenDriver.c +++ b/vm/compiler/codegen/arm/CodegenDriver.c @@ -872,7 +872,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 +1042,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 */ @@ -1169,7 +1169,7 @@ 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 */ @@ -1343,7 +1343,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 +1446,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 +1461,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 +1483,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 +1504,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 +1533,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 +1554,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 +1575,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 +1930,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 +2102,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 +2150,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 +2168,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 */ @@ -2192,6 +2287,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 +2501,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 +2555,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 +2606,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) @@ -2877,7 +2979,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 +3084,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 +3094,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 +3105,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 +3117,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); @@ -3109,6 +3226,8 @@ static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir) 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 +3258,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 +3318,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 +3347,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 +3366,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 +3383,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 +3405,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); @@ -3914,7 +4053,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 +4090,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; } |
