Bug 951439 - Use CallVM for RegExp.exec(). r=h4writer

This commit is contained in:
Sean Stangl 2014-01-06 11:24:50 -08:00
parent e3e7849089
commit df96ea1bab
13 changed files with 136 additions and 6 deletions

View File

@ -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. */

View File

@ -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);

View File

@ -764,6 +764,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<RegExpExecRawFn>(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<RegExpTestRawFn>(regexp_test_raw);

View File

@ -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);

View File

@ -631,6 +631,7 @@ class IonBuilder : public MIRGenerator
InliningStatus inlineStrCharAt(CallInfo &callInfo);
// RegExp natives.
InliningStatus inlineRegExpExec(CallInfo &callInfo);
InliningStatus inlineRegExpTest(CallInfo &callInfo);
// Array intrinsics.

View File

@ -3216,6 +3216,29 @@ class LRegExp : public LCallInstructionHelper<1, 0, 0>
}
};
class LRegExpExec : public LCallInstructionHelper<BOX_PIECES, 2, 0>
{
public:
LIR_HEADER(RegExpExec)
LRegExpExec(const LAllocation &regexp, 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:

View File

@ -149,6 +149,7 @@
_(OsrReturnValue) \
_(OsrArgumentsObject) \
_(RegExp) \
_(RegExpExec) \
_(RegExpTest) \
_(Lambda) \
_(LambdaForSingleton) \

View File

@ -1916,6 +1916,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)
{

View File

@ -145,6 +145,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);

View File

@ -121,6 +121,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)
@ -1108,6 +1110,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)
{

View File

@ -4807,6 +4807,43 @@ class MRegExp : public MNullaryInstruction
}
};
class MRegExpExec
: public MBinaryInstruction,
public MixPolicy<ObjectPolicy<1>, 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<ObjectPolicy<1>, StringPolicy<0> >

View File

@ -98,6 +98,7 @@ namespace jit {
_(OsrEntry) \
_(Nop) \
_(RegExp) \
_(RegExpExec) \
_(RegExpTest) \
_(Lambda) \
_(ImplicitThis) \

View File

@ -279,6 +279,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)