From fd023aaec5f2b0df61d1702ea2f29a70abe90158 Mon Sep 17 00:00:00 2001 From: Bill Buzbee Date: Mon, 2 Nov 2009 09:23:49 -0800 Subject: [PATCH] Jit - optimized inline string compareto, indexof; fill_array_data bug fix Added flushAllRegs() prior to C handlers in preparation for upcoming support for holding live/dirty values in physical registers. --- vm/compiler/codegen/arm/Codegen.c | 103 ++++++++++- vm/compiler/template/armv5te-vfp/TemplateOpList.h | 2 + .../template/armv5te/TEMPLATE_STRING_COMPARETO.S | 93 ++++++++++ .../template/armv5te/TEMPLATE_STRING_INDEXOF.S | 100 ++++++++++ vm/compiler/template/armv5te/TemplateOpList.h | 2 + vm/compiler/template/armv7-a/TemplateOpList.h | 2 + vm/compiler/template/config-armv5te-vfp | 2 + vm/compiler/template/config-armv7-a | 2 + .../template/out/CompilerTemplateAsm-armv5te-vfp.S | 205 +++++++++++++++++++++ .../template/out/CompilerTemplateAsm-armv5te.S | 205 +++++++++++++++++++++ .../template/out/CompilerTemplateAsm-armv7-a.S | 205 +++++++++++++++++++++ vm/mterp/common/asm-constants.h | 6 + 12 files changed, 920 insertions(+), 7 deletions(-) create mode 100644 vm/compiler/template/armv5te/TEMPLATE_STRING_COMPARETO.S create mode 100644 vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S diff --git a/vm/compiler/codegen/arm/Codegen.c b/vm/compiler/codegen/arm/Codegen.c index 9563df176..863158019 100644 --- a/vm/compiler/codegen/arm/Codegen.c +++ b/vm/compiler/codegen/arm/Codegen.c @@ -1440,6 +1440,7 @@ bool handleArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir, default: return true; } + flushAllRegs(cUnit); /* Send everything to home location */ loadValueDirectFixed(cUnit, rlSrc1, r0); loadValueDirectFixed(cUnit, rlSrc2, r1); loadConstant(cUnit, r2, (int)funct); @@ -1492,6 +1493,7 @@ bool handleArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir, default: return true; } + flushAllRegs(cUnit); /* Send everything to home location */ loadConstant(cUnit, rlr, (int)funct); loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); @@ -1584,6 +1586,7 @@ static bool handleArithOpLong(CompilationUnit *cUnit, MIR *mir, genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2); } else { // Adjust return regs in to handle case of rem returning r2/r3 + flushAllRegs(cUnit); /* Send everything to home location */ loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1); loadConstant(cUnit, rlr, (int) callTgt); loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3); @@ -1694,6 +1697,7 @@ static bool handleArithOpInt(CompilationUnit *cUnit, MIR *mir, storeValue(cUnit, rlDest, rlResult); } else { RegLocation rlResult; + flushAllRegs(cUnit); /* Send everything to home location */ loadValueDirectFixed(cUnit, rlSrc2, r1); loadConstant(cUnit, r2, (int) callTgt); loadValueDirectFixed(cUnit, rlSrc1, r0); @@ -1828,6 +1832,7 @@ static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct, */ RegLocation rlSrc; RegLocation rlDest; + flushAllRegs(cUnit); /* Send everything to home location */ if (srcSize == 1) { rlSrc = getSrcLoc(cUnit, mir, 0); loadValueDirectFixed(cUnit, rlSrc, r0); @@ -2240,6 +2245,7 @@ static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir) static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir) { + flushAllRegs(cUnit); /* Send everything to home location */ genExportPC(cUnit, mir); RegLocation rlSrc = getSrcLoc(cUnit, mir, 0); loadValueDirectFixed(cUnit, rlSrc, r1); @@ -2513,6 +2519,7 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir) * with. However, Alloc might throw, so we need to genExportPC() */ assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0); + flushAllRegs(cUnit); /* Send everything to home location */ genExportPC(cUnit, mir); loadConstant(cUnit, r2, (int)dvmAllocObject); loadConstant(cUnit, r0, (int) classPtr); @@ -2545,6 +2552,7 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir) */ ClassObject *classPtr = (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]); + flushAllRegs(cUnit); /* Send everything to home location */ loadConstant(cUnit, r1, (int) classPtr ); rlSrc = getSrcLoc(cUnit, mir, 0); rlSrc = loadValue(cUnit, rlSrc, kCoreReg); @@ -2925,6 +2933,7 @@ static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir) genInterpSingleStep(cUnit, mir); return false; } + flushAllRegs(cUnit); /* Send everything to home location */ loadValueDirectFixed(cUnit, rlSrc, r0); clobberReg(cUnit, r0); if ((dalvikOpCode == OP_DIV_INT_LIT8) || @@ -2984,6 +2993,7 @@ static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir) void *classPtr = (void*) (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]); assert(classPtr != NULL); + flushAllRegs(cUnit); /* Send everything to home location */ genExportPC(cUnit, mir); loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */ loadConstant(cUnit, r0, (int) classPtr ); @@ -3023,6 +3033,7 @@ static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir) ClassObject *classPtr = (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]); assert(classPtr != NULL); + flushAllRegs(cUnit); /* Send everything to home location */ loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */ loadConstant(cUnit, r2, (int) classPtr ); //TUNING: compare to 0 primative to allow use of CB[N]Z @@ -3281,14 +3292,23 @@ static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir) case OP_FILL_ARRAY_DATA: { RegLocation rlSrc = getSrcLoc(cUnit, mir, 0); // Making a call - use explicit registers + flushAllRegs(cUnit); /* Send everything to home location */ genExportPC(cUnit, mir); loadValueDirectFixed(cUnit, rlSrc, r0); - loadConstant(cUnit, r3, (int)dvmInterpHandleFillArrayData); + loadConstant(cUnit, r2, (int)dvmInterpHandleFillArrayData); loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) + (int) (cUnit->method->insns + mir->offset)); opReg(cUnit, kOpBlx, r2); clobberCallRegs(cUnit); - genZeroCheck(cUnit, r0, mir->offset, NULL); + /* generate a branch over if successful */ + opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */ + ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe); + loadConstant(cUnit, r0, + (int) (cUnit->method->insns + mir->offset)); + genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); + ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); + target->defMask = ENCODE_ALL; + branchOver->generic.target = (LIR *) target; break; } /* @@ -3301,6 +3321,7 @@ static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir) case OP_PACKED_SWITCH: case OP_SPARSE_SWITCH: { RegLocation rlSrc = getSrcLoc(cUnit, mir, 0); + flushAllRegs(cUnit); /* Send everything to home location */ loadValueDirectFixed(cUnit, rlSrc, r1); lockAllTemps(cUnit); // Exit to the interpreter, setting up r4PC @@ -3681,6 +3702,62 @@ static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir, } /* + * This operation is complex enough that we'll do it partly inline + * and partly with a handler. NOTE: the handler uses hardcoded + * values for string object offsets and must be revisitied if the + * layout changes. + */ +static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir) +{ +#if defined(USE_GLOBAL_STRING_DEFS) + return false; +#else + ArmLIR *rollback; + RegLocation rlThis = getSrcLoc(cUnit, mir, 0); + RegLocation rlComp = getSrcLoc(cUnit, mir, 1); + + loadValueDirectFixed(cUnit, rlThis, r0); + loadValueDirectFixed(cUnit, rlComp, r1); + /* Test objects for NULL */ + rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL); + genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback); + /* + * TUNING: we could check for object pointer equality before invoking + * handler. Unclear whether the gain would be worth the added code size + * expansion. + */ + genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO); + storeValue(cUnit, inlinedTarget(cUnit, mir, false), getReturnLoc(cUnit)); + return true; +#endif +} + +static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI) +{ +#if defined(USE_GLOBAL_STRING_DEFS) + return false; +#else + RegLocation rlThis = getSrcLoc(cUnit, mir, 0); + RegLocation rlChar = getSrcLoc(cUnit, mir, 1); + + loadValueDirectFixed(cUnit, rlThis, r0); + loadValueDirectFixed(cUnit, rlChar, r1); + if (!singleI) { + RegLocation rlStart = getSrcLoc(cUnit, mir, 2); + loadValueDirectFixed(cUnit, rlStart, r2); + } else { + loadConstant(cUnit, r2, 0); + } + /* Test objects for NULL */ + genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL); + genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF); + storeValue(cUnit, inlinedTarget(cUnit, mir, false), getReturnLoc(cUnit)); + return true; +#endif +} + + +/* * NOTE: We assume here that the special native inline routines * are side-effect free. By making this assumption, we can safely * re-execute the routine from the interpreter if it decides it @@ -3717,9 +3794,6 @@ static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir) return false; else break; /* Handle with C routine */ - case INLINE_MATH_COS: - case INLINE_MATH_SIN: - break; /* Handle with C routine */ case INLINE_MATH_ABS_FLOAT: if (genInlinedAbsFloat(cUnit, mir)) return false; @@ -3731,13 +3805,28 @@ static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir) else break; case INLINE_STRING_COMPARETO: - case INLINE_STRING_EQUALS: + if (genInlinedCompareTo(cUnit, 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: - break; + if (genInlinedIndexOf(cUnit, mir, false /* I */)) + return false; + else + break; + case INLINE_STRING_EQUALS: + case INLINE_MATH_COS: + case INLINE_MATH_SIN: + break; /* Handle with C routine */ default: dvmAbort(); } + flushAllRegs(cUnit); /* Send everything to home location */ clobberCallRegs(cUnit); clobberReg(cUnit, r4PC); clobberReg(cUnit, r7); diff --git a/vm/compiler/template/armv5te-vfp/TemplateOpList.h b/vm/compiler/template/armv5te-vfp/TemplateOpList.h index 8b687d71e..1608920b8 100644 --- a/vm/compiler/template/armv5te-vfp/TemplateOpList.h +++ b/vm/compiler/template/armv5te-vfp/TemplateOpList.h @@ -53,3 +53,5 @@ JIT_TEMPLATE(SQRT_DOUBLE_VFP) JIT_TEMPLATE(THROW_EXCEPTION_COMMON) JIT_TEMPLATE(SAVE_STATE) JIT_TEMPLATE(RESTORE_STATE) +JIT_TEMPLATE(STRING_COMPARETO) +JIT_TEMPLATE(STRING_INDEXOF) diff --git a/vm/compiler/template/armv5te/TEMPLATE_STRING_COMPARETO.S b/vm/compiler/template/armv5te/TEMPLATE_STRING_COMPARETO.S new file mode 100644 index 000000000..85b2a9f8a --- /dev/null +++ b/vm/compiler/template/armv5te/TEMPLATE_STRING_COMPARETO.S @@ -0,0 +1,93 @@ + /* + * String's compareTo. + * + * Requires r0/r1 to have been previously checked for null. Will + * return negative if this's string is < comp, 0 if they are the + * same and positive if >. + * + * IMPORTANT NOTE: + * + * This code relies on hard-coded offsets for string objects, and must be + * kept in sync with definitions in UtfString.h. See asm-constants.h + * + * On entry: + * r0: this object pointer + * r1: comp object pointer + * + */ + + mov r2, r0 @ this to r2, opening up r0 for return value + subs r0, r2, r1 @ Same? + bxeq lr + + ldr r4, [r2, #STRING_FIELDOFF_OFFSET] + ldr r9, [r1, #STRING_FIELDOFF_OFFSET] + ldr r7, [r2, #STRING_FIELDOFF_COUNT] + ldr r10, [r1, #STRING_FIELDOFF_COUNT] + ldr r2, [r2, #STRING_FIELDOFF_VALUE] + ldr r1, [r1, #STRING_FIELDOFF_VALUE] + + /* + * At this point, we have: + * value: r2/r1 + * offset: r4/r9 + * count: r7/r10 + * We're going to compute + * r11 <- countDiff + * r10 <- minCount + */ + subs r11, r7, r10 + movls r10, r7 + + /* Now, build pointers to the string data */ + add r2, r2, r4, lsl #1 + add r1, r1, r9, lsl #1 + /* + * Note: data pointers point to previous element so we can use pre-index + * mode with base writeback. + */ + add r2, #16-2 @ offset to contents[-1] + add r1, #16-2 @ offset to contents[-1] + + /* + * At this point we have: + * r2: *this string data + * r1: *comp string data + * r10: iteration count for comparison + * r11: value to return if the first part of the string is equal + * r0: reserved for result + * r3, r4, r7, r8, r9, r12 available for loading string data + */ + + cmp r10, #3 + blt do_remainder +loopback_triple: + ldrh r3, [r2, #2]! + ldrh r4, [r1, #2]! + ldrh r7, [r2, #2]! + ldrh r8, [r1, #2]! + ldrh r9, [r2, #2]! + ldrh r12,[r1, #2]! + subs r0, r3, r4 + subeqs r0, r7, r8 + subeqs r0, r9, r12 + bxne lr + subs r10, #3 + bgt loopback_triple + +do_remainder: + cmp r10, #0 + beq returnDiff + +loopback_single: + ldrh r3, [r2, #2]! + ldrh r4, [r1, #2]! + subs r0, r3, r4 + bxne lr + subs r10, #1 + bne loopback_single + +returnDiff: + mov r0, r11 + bx lr + diff --git a/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S b/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S new file mode 100644 index 000000000..685ccc68b --- /dev/null +++ b/vm/compiler/template/armv5te/TEMPLATE_STRING_INDEXOF.S @@ -0,0 +1,100 @@ + /* + * String's indexOf. + * + * Requires r0 to have been previously checked for null. Will + * return index of match of r1 in r0. + * + * IMPORTANT NOTE: + * + * This code relies on hard-coded offsets for string objects, and must be + * kept in sync wth definitions in UtfString.h See asm-constants.h + * + * On entry: + * r0: string object pointer + * r1: char to match + * r2: Starting offset in string data + */ + + ldr r7, [r0, #STRING_FIELDOFF_OFFSET] + ldr r8, [r0, #STRING_FIELDOFF_COUNT] + ldr r0, [r0, #STRING_FIELDOFF_VALUE] + + /* + * At this point, we have: + * value: r0 + * offset: r7 + * count: r8 + */ + + /* Clamp start to [0..count] */ + cmp r2, #0 + movlt r2, #0 + cmp r2, r8 + movgt r2, r0 + + /* Fold start & offset, and set data pointer to contents[-1] */ + add r2, r7 + add r0, r0, r2, lsl #1 + add r0, #16-2 @ offset to contents[-1] + add r2, r0, #2 @ remember true start of data + + /* + * At this point we have: + * r0: *next[-1] char to test + * r2: *start + * r1: char to compare + * r8: max count + * r3, r4, r7, r9, r12 available for loading string data + */ + + /* Unroll x 4 */ + + cmp r8, #4 + blt do_rest +loopback_quad: + ldrh r3, [r0, #2]! + ldrh r4, [r0, #2]! + ldrh r7, [r0, #2]! + ldrh r9, [r0, #2]! + cmp r3, r1 + beq match_0 + cmp r4, r1 + beq match_1 + cmp r7, r1 + beq match_2 + cmp r9, r1 + beq match_3 + subs r8, #4 + bgt loopback_quad + +do_rest: + cmp r8, #0 + beq no_match + +loopback_indexof: + ldrh r3, [r0, #2]! + cmp r3, r1 + beq match_3 + subs r8, #1 + bne loopback_indexof + +no_match: + mov r0, #-1 + bx lr + +match_0: + sub r0, #6 + sub r0, r2 + bx lr +match_1: + sub r0, #4 + sub r0, r2 + bx lr +match_2: + sub r0, #2 + sub r0, r2 + bx lr +match_3: + sub r0, r2 + bx lr + diff --git a/vm/compiler/template/armv5te/TemplateOpList.h b/vm/compiler/template/armv5te/TemplateOpList.h index 899c5116d..88cc60a36 100644 --- a/vm/compiler/template/armv5te/TemplateOpList.h +++ b/vm/compiler/template/armv5te/TemplateOpList.h @@ -38,3 +38,5 @@ JIT_TEMPLATE(USHR_LONG) JIT_TEMPLATE(THROW_EXCEPTION_COMMON) JIT_TEMPLATE(SAVE_STATE) JIT_TEMPLATE(RESTORE_STATE) +JIT_TEMPLATE(STRING_COMPARETO) +JIT_TEMPLATE(STRING_INDEXOF) diff --git a/vm/compiler/template/armv7-a/TemplateOpList.h b/vm/compiler/template/armv7-a/TemplateOpList.h index 8b687d71e..1608920b8 100644 --- a/vm/compiler/template/armv7-a/TemplateOpList.h +++ b/vm/compiler/template/armv7-a/TemplateOpList.h @@ -53,3 +53,5 @@ JIT_TEMPLATE(SQRT_DOUBLE_VFP) JIT_TEMPLATE(THROW_EXCEPTION_COMMON) JIT_TEMPLATE(SAVE_STATE) JIT_TEMPLATE(RESTORE_STATE) +JIT_TEMPLATE(STRING_COMPARETO) +JIT_TEMPLATE(STRING_INDEXOF) diff --git a/vm/compiler/template/config-armv5te-vfp b/vm/compiler/template/config-armv5te-vfp index ab3ff9014..b5ca397c1 100644 --- a/vm/compiler/template/config-armv5te-vfp +++ b/vm/compiler/template/config-armv5te-vfp @@ -43,6 +43,8 @@ op-start armv5te-vfp op TEMPLATE_SHR_LONG armv5te op TEMPLATE_USHR_LONG armv5te op TEMPLATE_THROW_EXCEPTION_COMMON armv5te + op TEMPLATE_STRING_COMPARETO armv5te + op TEMPLATE_STRING_INDEXOF armv5te op-end diff --git a/vm/compiler/template/config-armv7-a b/vm/compiler/template/config-armv7-a index aed0fa73e..1d3d331ba 100644 --- a/vm/compiler/template/config-armv7-a +++ b/vm/compiler/template/config-armv7-a @@ -43,6 +43,8 @@ op-start armv5te-vfp op TEMPLATE_SHR_LONG armv5te op TEMPLATE_USHR_LONG armv5te op TEMPLATE_THROW_EXCEPTION_COMMON armv5te + op TEMPLATE_STRING_COMPARETO armv5te + op TEMPLATE_STRING_INDEXOF armv5te op-end diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S index 64a050bc2..797a2fcd0 100644 --- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S +++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S @@ -1072,6 +1072,211 @@ dvmCompiler_TEMPLATE_RESTORE_STATE: ldmia r0, {r0-r12} bx lr +/* ------------------------------ */ + .balign 4 + .global dvmCompiler_TEMPLATE_STRING_COMPARETO +dvmCompiler_TEMPLATE_STRING_COMPARETO: +/* File: armv5te/TEMPLATE_STRING_COMPARETO.S */ + /* + * String's compareTo. + * + * Requires r0/r1 to have been previously checked for null. Will + * return negative if this's string is < comp, 0 if they are the + * same and positive if >. + * + * IMPORTANT NOTE: + * + * This code relies on hard-coded offsets for string objects, and must be + * kept in sync with definitions in UtfString.h. See asm-constants.h + * + * On entry: + * r0: this object pointer + * r1: comp object pointer + * + */ + + mov r2, r0 @ this to r2, opening up r0 for return value + subs r0, r2, r1 @ Same? + bxeq lr + + ldr r4, [r2, #STRING_FIELDOFF_OFFSET] + ldr r9, [r1, #STRING_FIELDOFF_OFFSET] + ldr r7, [r2, #STRING_FIELDOFF_COUNT] + ldr r10, [r1, #STRING_FIELDOFF_COUNT] + ldr r2, [r2, #STRING_FIELDOFF_VALUE] + ldr r1, [r1, #STRING_FIELDOFF_VALUE] + + /* + * At this point, we have: + * value: r2/r1 + * offset: r4/r9 + * count: r7/r10 + * We're going to compute + * r11 <- countDiff + * r10 <- minCount + */ + subs r11, r7, r10 + movls r10, r7 + + /* Now, build pointers to the string data */ + add r2, r2, r4, lsl #1 + add r1, r1, r9, lsl #1 + /* + * Note: data pointers point to previous element so we can use pre-index + * mode with base writeback. + */ + add r2, #16-2 @ offset to contents[-1] + add r1, #16-2 @ offset to contents[-1] + + /* + * At this point we have: + * r2: *this string data + * r1: *comp string data + * r10: iteration count for comparison + * r11: value to return if the first part of the string is equal + * r0: reserved for result + * r3, r4, r7, r8, r9, r12 available for loading string data + */ + + cmp r10, #3 + blt do_remainder +loopback_triple: + ldrh r3, [r2, #2]! + ldrh r4, [r1, #2]! + ldrh r7, [r2, #2]! + ldrh r8, [r1, #2]! + ldrh r9, [r2, #2]! + ldrh r12,[r1, #2]! + subs r0, r3, r4 + subeqs r0, r7, r8 + subeqs r0, r9, r12 + bxne lr + subs r10, #3 + bgt loopback_triple + +do_remainder: + cmp r10, #0 + beq returnDiff + +loopback_single: + ldrh r3, [r2, #2]! + ldrh r4, [r1, #2]! + subs r0, r3, r4 + bxne lr + subs r10, #1 + bne loopback_single + +returnDiff: + mov r0, r11 + bx lr + + +/* ------------------------------ */ + .balign 4 + .global dvmCompiler_TEMPLATE_STRING_INDEXOF +dvmCompiler_TEMPLATE_STRING_INDEXOF: +/* File: armv5te/TEMPLATE_STRING_INDEXOF.S */ + /* + * String's indexOf. + * + * Requires r0 to have been previously checked for null. Will + * return index of match of r1 in r0. + * + * IMPORTANT NOTE: + * + * This code relies on hard-coded offsets for string objects, and must be + * kept in sync wth definitions in UtfString.h See asm-constants.h + * + * On entry: + * r0: string object pointer + * r1: char to match + * r2: Starting offset in string data + */ + + ldr r7, [r0, #STRING_FIELDOFF_OFFSET] + ldr r8, [r0, #STRING_FIELDOFF_COUNT] + ldr r0, [r0, #STRING_FIELDOFF_VALUE] + + /* + * At this point, we have: + * value: r0 + * offset: r7 + * count: r8 + */ + + /* Clamp start to [0..count] */ + cmp r2, #0 + movlt r2, #0 + cmp r2, r8 + movgt r2, r0 + + /* Fold start & offset, and set data pointer to contents[-1] */ + add r2, r7 + add r0, r0, r2, lsl #1 + add r0, #16-2 @ offset to contents[-1] + add r2, r0, #2 @ remember true start of data + + /* + * At this point we have: + * r0: *next[-1] char to test + * r2: *start + * r1: char to compare + * r8: max count + * r3, r4, r7, r9, r12 available for loading string data + */ + + /* Unroll x 4 */ + + cmp r8, #4 + blt do_rest +loopback_quad: + ldrh r3, [r0, #2]! + ldrh r4, [r0, #2]! + ldrh r7, [r0, #2]! + ldrh r9, [r0, #2]! + cmp r3, r1 + beq match_0 + cmp r4, r1 + beq match_1 + cmp r7, r1 + beq match_2 + cmp r9, r1 + beq match_3 + subs r8, #4 + bgt loopback_quad + +do_rest: + cmp r8, #0 + beq no_match + +loopback_indexof: + ldrh r3, [r0, #2]! + cmp r3, r1 + beq match_3 + subs r8, #1 + bne loopback_indexof + +no_match: + mov r0, #-1 + bx lr + +match_0: + sub r0, #6 + sub r0, r2 + bx lr +match_1: + sub r0, #4 + sub r0, r2 + bx lr +match_2: + sub r0, #2 + sub r0, r2 + bx lr +match_3: + sub r0, r2 + bx lr + + .size dvmCompilerTemplateStart, .-dvmCompilerTemplateStart /* File: armv5te/footer.S */ /* diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S index 803f53bc7..340b05d3f 100644 --- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S +++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S @@ -797,6 +797,211 @@ dvmCompiler_TEMPLATE_RESTORE_STATE: ldmia r0, {r0-r12} bx lr +/* ------------------------------ */ + .balign 4 + .global dvmCompiler_TEMPLATE_STRING_COMPARETO +dvmCompiler_TEMPLATE_STRING_COMPARETO: +/* File: armv5te/TEMPLATE_STRING_COMPARETO.S */ + /* + * String's compareTo. + * + * Requires r0/r1 to have been previously checked for null. Will + * return negative if this's string is < comp, 0 if they are the + * same and positive if >. + * + * IMPORTANT NOTE: + * + * This code relies on hard-coded offsets for string objects, and must be + * kept in sync with definitions in UtfString.h. See asm-constants.h + * + * On entry: + * r0: this object pointer + * r1: comp object pointer + * + */ + + mov r2, r0 @ this to r2, opening up r0 for return value + subs r0, r2, r1 @ Same? + bxeq lr + + ldr r4, [r2, #STRING_FIELDOFF_OFFSET] + ldr r9, [r1, #STRING_FIELDOFF_OFFSET] + ldr r7, [r2, #STRING_FIELDOFF_COUNT] + ldr r10, [r1, #STRING_FIELDOFF_COUNT] + ldr r2, [r2, #STRING_FIELDOFF_VALUE] + ldr r1, [r1, #STRING_FIELDOFF_VALUE] + + /* + * At this point, we have: + * value: r2/r1 + * offset: r4/r9 + * count: r7/r10 + * We're going to compute + * r11 <- countDiff + * r10 <- minCount + */ + subs r11, r7, r10 + movls r10, r7 + + /* Now, build pointers to the string data */ + add r2, r2, r4, lsl #1 + add r1, r1, r9, lsl #1 + /* + * Note: data pointers point to previous element so we can use pre-index + * mode with base writeback. + */ + add r2, #16-2 @ offset to contents[-1] + add r1, #16-2 @ offset to contents[-1] + + /* + * At this point we have: + * r2: *this string data + * r1: *comp string data + * r10: iteration count for comparison + * r11: value to return if the first part of the string is equal + * r0: reserved for result + * r3, r4, r7, r8, r9, r12 available for loading string data + */ + + cmp r10, #3 + blt do_remainder +loopback_triple: + ldrh r3, [r2, #2]! + ldrh r4, [r1, #2]! + ldrh r7, [r2, #2]! + ldrh r8, [r1, #2]! + ldrh r9, [r2, #2]! + ldrh r12,[r1, #2]! + subs r0, r3, r4 + subeqs r0, r7, r8 + subeqs r0, r9, r12 + bxne lr + subs r10, #3 + bgt loopback_triple + +do_remainder: + cmp r10, #0 + beq returnDiff + +loopback_single: + ldrh r3, [r2, #2]! + ldrh r4, [r1, #2]! + subs r0, r3, r4 + bxne lr + subs r10, #1 + bne loopback_single + +returnDiff: + mov r0, r11 + bx lr + + +/* ------------------------------ */ + .balign 4 + .global dvmCompiler_TEMPLATE_STRING_INDEXOF +dvmCompiler_TEMPLATE_STRING_INDEXOF: +/* File: armv5te/TEMPLATE_STRING_INDEXOF.S */ + /* + * String's indexOf. + * + * Requires r0 to have been previously checked for null. Will + * return index of match of r1 in r0. + * + * IMPORTANT NOTE: + * + * This code relies on hard-coded offsets for string objects, and must be + * kept in sync wth definitions in UtfString.h See asm-constants.h + * + * On entry: + * r0: string object pointer + * r1: char to match + * r2: Starting offset in string data + */ + + ldr r7, [r0, #STRING_FIELDOFF_OFFSET] + ldr r8, [r0, #STRING_FIELDOFF_COUNT] + ldr r0, [r0, #STRING_FIELDOFF_VALUE] + + /* + * At this point, we have: + * value: r0 + * offset: r7 + * count: r8 + */ + + /* Clamp start to [0..count] */ + cmp r2, #0 + movlt r2, #0 + cmp r2, r8 + movgt r2, r0 + + /* Fold start & offset, and set data pointer to contents[-1] */ + add r2, r7 + add r0, r0, r2, lsl #1 + add r0, #16-2 @ offset to contents[-1] + add r2, r0, #2 @ remember true start of data + + /* + * At this point we have: + * r0: *next[-1] char to test + * r2: *start + * r1: char to compare + * r8: max count + * r3, r4, r7, r9, r12 available for loading string data + */ + + /* Unroll x 4 */ + + cmp r8, #4 + blt do_rest +loopback_quad: + ldrh r3, [r0, #2]! + ldrh r4, [r0, #2]! + ldrh r7, [r0, #2]! + ldrh r9, [r0, #2]! + cmp r3, r1 + beq match_0 + cmp r4, r1 + beq match_1 + cmp r7, r1 + beq match_2 + cmp r9, r1 + beq match_3 + subs r8, #4 + bgt loopback_quad + +do_rest: + cmp r8, #0 + beq no_match + +loopback_indexof: + ldrh r3, [r0, #2]! + cmp r3, r1 + beq match_3 + subs r8, #1 + bne loopback_indexof + +no_match: + mov r0, #-1 + bx lr + +match_0: + sub r0, #6 + sub r0, r2 + bx lr +match_1: + sub r0, #4 + sub r0, r2 + bx lr +match_2: + sub r0, #2 + sub r0, r2 + bx lr +match_3: + sub r0, r2 + bx lr + + .size dvmCompilerTemplateStart, .-dvmCompilerTemplateStart /* File: armv5te/footer.S */ /* diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S index b5979052c..fca0d671d 100644 --- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S +++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S @@ -1072,6 +1072,211 @@ dvmCompiler_TEMPLATE_RESTORE_STATE: ldmia r0, {r0-r12} bx lr +/* ------------------------------ */ + .balign 4 + .global dvmCompiler_TEMPLATE_STRING_COMPARETO +dvmCompiler_TEMPLATE_STRING_COMPARETO: +/* File: armv5te/TEMPLATE_STRING_COMPARETO.S */ + /* + * String's compareTo. + * + * Requires r0/r1 to have been previously checked for null. Will + * return negative if this's string is < comp, 0 if they are the + * same and positive if >. + * + * IMPORTANT NOTE: + * + * This code relies on hard-coded offsets for string objects, and must be + * kept in sync with definitions in UtfString.h. See asm-constants.h + * + * On entry: + * r0: this object pointer + * r1: comp object pointer + * + */ + + mov r2, r0 @ this to r2, opening up r0 for return value + subs r0, r2, r1 @ Same? + bxeq lr + + ldr r4, [r2, #STRING_FIELDOFF_OFFSET] + ldr r9, [r1, #STRING_FIELDOFF_OFFSET] + ldr r7, [r2, #STRING_FIELDOFF_COUNT] + ldr r10, [r1, #STRING_FIELDOFF_COUNT] + ldr r2, [r2, #STRING_FIELDOFF_VALUE] + ldr r1, [r1, #STRING_FIELDOFF_VALUE] + + /* + * At this point, we have: + * value: r2/r1 + * offset: r4/r9 + * count: r7/r10 + * We're going to compute + * r11 <- countDiff + * r10 <- minCount + */ + subs r11, r7, r10 + movls r10, r7 + + /* Now, build pointers to the string data */ + add r2, r2, r4, lsl #1 + add r1, r1, r9, lsl #1 + /* + * Note: data pointers point to previous element so we can use pre-index + * mode with base writeback. + */ + add r2, #16-2 @ offset to contents[-1] + add r1, #16-2 @ offset to contents[-1] + + /* + * At this point we have: + * r2: *this string data + * r1: *comp string data + * r10: iteration count for comparison + * r11: value to return if the first part of the string is equal + * r0: reserved for result + * r3, r4, r7, r8, r9, r12 available for loading string data + */ + + cmp r10, #3 + blt do_remainder +loopback_triple: + ldrh r3, [r2, #2]! + ldrh r4, [r1, #2]! + ldrh r7, [r2, #2]! + ldrh r8, [r1, #2]! + ldrh r9, [r2, #2]! + ldrh r12,[r1, #2]! + subs r0, r3, r4 + subeqs r0, r7, r8 + subeqs r0, r9, r12 + bxne lr + subs r10, #3 + bgt loopback_triple + +do_remainder: + cmp r10, #0 + beq returnDiff + +loopback_single: + ldrh r3, [r2, #2]! + ldrh r4, [r1, #2]! + subs r0, r3, r4 + bxne lr + subs r10, #1 + bne loopback_single + +returnDiff: + mov r0, r11 + bx lr + + +/* ------------------------------ */ + .balign 4 + .global dvmCompiler_TEMPLATE_STRING_INDEXOF +dvmCompiler_TEMPLATE_STRING_INDEXOF: +/* File: armv5te/TEMPLATE_STRING_INDEXOF.S */ + /* + * String's indexOf. + * + * Requires r0 to have been previously checked for null. Will + * return index of match of r1 in r0. + * + * IMPORTANT NOTE: + * + * This code relies on hard-coded offsets for string objects, and must be + * kept in sync wth definitions in UtfString.h See asm-constants.h + * + * On entry: + * r0: string object pointer + * r1: char to match + * r2: Starting offset in string data + */ + + ldr r7, [r0, #STRING_FIELDOFF_OFFSET] + ldr r8, [r0, #STRING_FIELDOFF_COUNT] + ldr r0, [r0, #STRING_FIELDOFF_VALUE] + + /* + * At this point, we have: + * value: r0 + * offset: r7 + * count: r8 + */ + + /* Clamp start to [0..count] */ + cmp r2, #0 + movlt r2, #0 + cmp r2, r8 + movgt r2, r0 + + /* Fold start & offset, and set data pointer to contents[-1] */ + add r2, r7 + add r0, r0, r2, lsl #1 + add r0, #16-2 @ offset to contents[-1] + add r2, r0, #2 @ remember true start of data + + /* + * At this point we have: + * r0: *next[-1] char to test + * r2: *start + * r1: char to compare + * r8: max count + * r3, r4, r7, r9, r12 available for loading string data + */ + + /* Unroll x 4 */ + + cmp r8, #4 + blt do_rest +loopback_quad: + ldrh r3, [r0, #2]! + ldrh r4, [r0, #2]! + ldrh r7, [r0, #2]! + ldrh r9, [r0, #2]! + cmp r3, r1 + beq match_0 + cmp r4, r1 + beq match_1 + cmp r7, r1 + beq match_2 + cmp r9, r1 + beq match_3 + subs r8, #4 + bgt loopback_quad + +do_rest: + cmp r8, #0 + beq no_match + +loopback_indexof: + ldrh r3, [r0, #2]! + cmp r3, r1 + beq match_3 + subs r8, #1 + bne loopback_indexof + +no_match: + mov r0, #-1 + bx lr + +match_0: + sub r0, #6 + sub r0, r2 + bx lr +match_1: + sub r0, #4 + sub r0, r2 + bx lr +match_2: + sub r0, #2 + sub r0, r2 + bx lr +match_3: + sub r0, r2 + bx lr + + .size dvmCompilerTemplateStart, .-dvmCompilerTemplateStart /* File: armv5te/footer.S */ /* diff --git a/vm/mterp/common/asm-constants.h b/vm/mterp/common/asm-constants.h index 9dbf6e80e..bb6246b0d 100644 --- a/vm/mterp/common/asm-constants.h +++ b/vm/mterp/common/asm-constants.h @@ -229,6 +229,12 @@ MTERP_OFFSET(offArrayObject_contents, ArrayObject, contents, 16) MTERP_OFFSET(offArrayObject_contents, ArrayObject, contents, 12) #endif +/* String fields */ +MTERP_CONSTANT(STRING_FIELDOFF_VALUE, 8) +MTERP_CONSTANT(STRING_FIELDOFF_HASHCODE, 12) +MTERP_CONSTANT(STRING_FIELDOFF_OFFSET, 16) +MTERP_CONSTANT(STRING_FIELDOFF_COUNT, 20) + /* ClassObject fields */ MTERP_OFFSET(offClassObject_descriptor, ClassObject, descriptor, 24) MTERP_OFFSET(offClassObject_accessFlags, ClassObject, accessFlags, 32) -- 2.11.0