From 1b114e176da38cf25767f1a42598a4230375c86f Mon Sep 17 00:00:00 2001 From: Sean Stangl Date: Tue, 17 Dec 2013 15:24:47 -0800 Subject: [PATCH] Bug 951439 - Use CallVM for RegExp.exec(). r=h4writer --- js/src/builtin/RegExp.cpp | 20 ++++++++++----- js/src/builtin/RegExp.h | 3 +++ js/src/jit/CodeGenerator.cpp | 12 +++++++++ js/src/jit/CodeGenerator.h | 1 + js/src/jit/IonBuilder.h | 1 + js/src/jit/LIR-Common.h | 23 +++++++++++++++++ js/src/jit/LOpcodes.h | 1 + js/src/jit/Lowering.cpp | 11 ++++++++ js/src/jit/Lowering.h | 1 + js/src/jit/MCallOptimize.cpp | 30 ++++++++++++++++++++++ js/src/jit/MIR.h | 37 +++++++++++++++++++++++++++ js/src/jit/MOpcodes.h | 1 + js/src/jit/ParallelSafetyAnalysis.cpp | 1 + 13 files changed, 136 insertions(+), 6 deletions(-) diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index c7d3fadb428..bc111a242e6 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -611,8 +611,8 @@ ExecuteRegExp(JSContext *cx, CallArgs args, MatchConduit &matches) /* ES5 15.10.6.2. */ static bool -regexp_exec_impl(JSContext *cx, CallArgs args, HandleObject regexp, HandleString string, - RegExpStaticsUpdate staticsUpdate) +regexp_exec_impl(JSContext *cx, HandleObject regexp, HandleString string, + RegExpStaticsUpdate staticsUpdate, MutableHandleValue rval) { /* Execute regular expression and gather matches. */ ScopedMatchPairs matches(&cx->tempLifoAlloc()); @@ -624,11 +624,11 @@ regexp_exec_impl(JSContext *cx, CallArgs args, HandleObject regexp, HandleString return false; if (status == RegExpRunStatus_Success_NotFound) { - args.rval().setNull(); + rval.setNull(); return true; } - return CreateRegExpMatchResult(cx, string, matches, args.rval()); + return CreateRegExpMatchResult(cx, string, matches, rval); } static bool @@ -639,7 +639,7 @@ regexp_exec_impl(JSContext *cx, CallArgs args) if (!string) return false; - return regexp_exec_impl(cx, args, regexp, string, UpdateRegExpStatics); + return regexp_exec_impl(cx, regexp, string, UpdateRegExpStatics, args.rval()); } bool @@ -649,6 +649,14 @@ js::regexp_exec(JSContext *cx, unsigned argc, Value *vp) return CallNonGenericMethod(cx, IsRegExp, regexp_exec_impl, args); } +/* Separate interface for use by IonMonkey. */ +bool +js::regexp_exec_raw(JSContext *cx, HandleObject regexp, HandleString input, Value *vp) +{ + MutableHandleValue vpHandle = MutableHandleValue::fromMarkedLocation(vp); + return regexp_exec_impl(cx, regexp, input, UpdateRegExpStatics, vpHandle); +} + bool js::regexp_exec_no_statics(JSContext *cx, unsigned argc, Value *vp) { @@ -660,7 +668,7 @@ js::regexp_exec_no_statics(JSContext *cx, unsigned argc, Value *vp) RootedObject regexp(cx, &args[0].toObject()); RootedString string(cx, args[1].toString()); - return regexp_exec_impl(cx, args, regexp, string, DontUpdateRegExpStatics); + return regexp_exec_impl(cx, regexp, string, DontUpdateRegExpStatics, args.rval()); } /* ES5 15.10.6.3. */ diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h index fd2337ca7d2..cf15f9e5a28 100644 --- a/js/src/builtin/RegExp.h +++ b/js/src/builtin/RegExp.h @@ -48,6 +48,9 @@ bool CreateRegExpMatchResult(JSContext *cx, HandleString input, const jschar *chars, size_t length, MatchPairs &matches, MutableHandleValue rval); +extern bool +regexp_exec_raw(JSContext *cx, HandleObject regexp, HandleString input, Value *vp); + extern bool regexp_exec(JSContext *cx, unsigned argc, Value *vp); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 6f6d5e6a313..56f0c3c4d34 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -767,6 +767,18 @@ CodeGenerator::visitRegExp(LRegExp *lir) return callVM(CloneRegExpObjectInfo, lir); } +typedef bool (*RegExpExecRawFn)(JSContext *cx, HandleObject regexp, + HandleString input, Value *vp); +static const VMFunction RegExpExecRawInfo = FunctionInfo(regexp_exec_raw); + +bool +CodeGenerator::visitRegExpExec(LRegExpExec *lir) +{ + pushArg(ToRegister(lir->string())); + pushArg(ToRegister(lir->regexp())); + return callVM(RegExpExecRawInfo, lir); +} + typedef bool (*RegExpTestRawFn)(JSContext *cx, HandleObject regexp, HandleString input, bool *result); static const VMFunction RegExpTestRawInfo = FunctionInfo(regexp_test_raw); diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index e640e044ae2..599485c3abe 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -90,6 +90,7 @@ class CodeGenerator : public CodeGeneratorSpecific bool visitDoubleToString(LDoubleToString *lir); bool visitInteger(LInteger *lir); bool visitRegExp(LRegExp *lir); + bool visitRegExpExec(LRegExpExec *lir); bool visitRegExpTest(LRegExpTest *lir); bool visitLambda(LLambda *lir); bool visitLambdaForSingleton(LLambdaForSingleton *lir); diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index ebd31b3fb62..a4ef63dfbfb 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -630,6 +630,7 @@ class IonBuilder : public MIRGenerator InliningStatus inlineStrCharAt(CallInfo &callInfo); // RegExp natives. + InliningStatus inlineRegExpExec(CallInfo &callInfo); InliningStatus inlineRegExpTest(CallInfo &callInfo); // Array intrinsics. diff --git a/js/src/jit/LIR-Common.h b/js/src/jit/LIR-Common.h index 8587bc6575d..701c4116eba 100644 --- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -3215,6 +3215,29 @@ class LRegExp : public LCallInstructionHelper<1, 0, 0> } }; +class LRegExpExec : public LCallInstructionHelper<1, 2, 0> +{ + public: + LIR_HEADER(RegExpExec) + + LRegExpExec(const LAllocation ®exp, const LAllocation &string) + { + setOperand(0, regexp); + setOperand(1, string); + } + + const LAllocation *regexp() { + return getOperand(0); + } + const LAllocation *string() { + return getOperand(1); + } + + const MRegExpExec *mir() const { + return mir_->toRegExpExec(); + } +}; + class LRegExpTest : public LCallInstructionHelper<1, 2, 0> { public: diff --git a/js/src/jit/LOpcodes.h b/js/src/jit/LOpcodes.h index 678f90aa314..c4139a7c105 100644 --- a/js/src/jit/LOpcodes.h +++ b/js/src/jit/LOpcodes.h @@ -149,6 +149,7 @@ _(OsrReturnValue) \ _(OsrArgumentsObject) \ _(RegExp) \ + _(RegExpExec) \ _(RegExpTest) \ _(Lambda) \ _(LambdaForSingleton) \ diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 66902b44761..5d492819b98 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -1945,6 +1945,17 @@ LIRGenerator::visitRegExp(MRegExp *ins) return defineReturn(lir, ins) && assignSafepoint(lir, ins); } +bool +LIRGenerator::visitRegExpExec(MRegExpExec *ins) +{ + JS_ASSERT(ins->regexp()->type() == MIRType_Object); + JS_ASSERT(ins->string()->type() == MIRType_String); + + LRegExpExec *lir = new(alloc()) LRegExpExec(useRegisterAtStart(ins->regexp()), + useRegisterAtStart(ins->string())); + return defineReturn(lir, ins) && assignSafepoint(lir, ins); +} + bool LIRGenerator::visitRegExpTest(MRegExpTest *ins) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index 2170307c14e..00de4d44a1f 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -162,6 +162,7 @@ class LIRGenerator : public LIRGeneratorSpecific bool visitTruncateToInt32(MTruncateToInt32 *truncate); bool visitToString(MToString *convert); bool visitRegExp(MRegExp *ins); + bool visitRegExpExec(MRegExpExec *ins); bool visitRegExpTest(MRegExpTest *ins); bool visitLambda(MLambda *ins); bool visitLambdaPar(MLambdaPar *ins); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 3e2b5d4976a..8924210bf55 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -119,6 +119,8 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native) return inlineStrCharAt(callInfo); // RegExp natives. + if (native == regexp_exec && CallResultEscapes(pc)) + return inlineRegExpExec(callInfo); if (native == regexp_exec && !CallResultEscapes(pc)) return inlineRegExpTest(callInfo); if (native == regexp_test) @@ -1066,6 +1068,34 @@ IonBuilder::inlineStrCharAt(CallInfo &callInfo) return InliningStatus_Inlined; } +IonBuilder::InliningStatus +IonBuilder::inlineRegExpExec(CallInfo &callInfo) +{ + if (callInfo.argc() != 1 || callInfo.constructing()) + return InliningStatus_NotInlined; + + if (callInfo.thisArg()->type() != MIRType_Object) + return InliningStatus_NotInlined; + + types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet(); + const Class *clasp = thisTypes ? thisTypes->getKnownClass() : nullptr; + if (clasp != &RegExpObject::class_) + return InliningStatus_NotInlined; + + if (callInfo.getArg(0)->type() != MIRType_String) + return InliningStatus_NotInlined; + + callInfo.unwrapArgs(); + + MInstruction *exec = MRegExpExec::New(alloc(), callInfo.thisArg(), callInfo.getArg(0)); + current->add(exec); + current->push(exec); + if (!resumeAfter(exec)) + return InliningStatus_Error; + + return InliningStatus_Inlined; +} + IonBuilder::InliningStatus IonBuilder::inlineRegExpTest(CallInfo &callInfo) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 0267c32d937..ed78f697e38 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -4892,6 +4892,43 @@ class MRegExp : public MNullaryInstruction } }; +class MRegExpExec + : public MBinaryInstruction, + public MixPolicy, StringPolicy<0> > +{ + private: + + MRegExpExec(MDefinition *regexp, MDefinition *string) + : MBinaryInstruction(string, regexp) + { + // May be object or null. + setResultType(MIRType_Value); + } + + public: + INSTRUCTION_HEADER(RegExpExec) + + static MRegExpExec *New(TempAllocator &alloc, MDefinition *regexp, MDefinition *string) { + return new(alloc) MRegExpExec(regexp, string); + } + + MDefinition *string() const { + return getOperand(0); + } + + MDefinition *regexp() const { + return getOperand(1); + } + + TypePolicy *typePolicy() { + return this; + } + + bool possiblyCalls() const { + return true; + } +}; + class MRegExpTest : public MBinaryInstruction, public MixPolicy, StringPolicy<0> > diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index b02f79ded8a..1cc1376d138 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -100,6 +100,7 @@ namespace jit { _(OsrEntry) \ _(Nop) \ _(RegExp) \ + _(RegExpExec) \ _(RegExpTest) \ _(Lambda) \ _(ImplicitThis) \ diff --git a/js/src/jit/ParallelSafetyAnalysis.cpp b/js/src/jit/ParallelSafetyAnalysis.cpp index 74a58b39d6c..d358d77ad87 100644 --- a/js/src/jit/ParallelSafetyAnalysis.cpp +++ b/js/src/jit/ParallelSafetyAnalysis.cpp @@ -281,6 +281,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor UNSAFE_OP(Pow) UNSAFE_OP(PowHalf) UNSAFE_OP(RegExpTest) + UNSAFE_OP(RegExpExec) UNSAFE_OP(CallInstanceOf) UNSAFE_OP(FunctionBoundary) UNSAFE_OP(GuardString)