Loading js/src/builtin/RegExp.cpp +21 −31 Original line number Diff line number Diff line Loading @@ -561,12 +561,17 @@ GetSharedForGreedyStar(JSContext *cx, JSAtom *source, RegExpFlag flags, RegExpGu return cx->compartment->regExps.getHack(cx, source, hackedSource, flags, g); } bool js::ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp, HandleString string, MutableHandleValue rval) /* * ES5 15.10.6.2 (and 15.10.6.3, which calls 15.10.6.2). * * RegExp.prototype.test doesn't need to create a results array, and we use * |execType| to perform this optimization. */ static bool ExecuteRegExp(JSContext *cx, RegExpExecType execType, CallArgs args) { /* Step 1 (b) was performed by CallNonGenericMethod. */ Rooted<RegExpObject*> reobj(cx, ®exp->asRegExp()); /* Step 1 was performed by CallNonGenericMethod. */ Rooted<RegExpObject*> reobj(cx, &args.thisv().toObject().asRegExp()); RegExpGuard re; if (StartsWithGreedyStar(reobj->getSource())) { Loading @@ -579,8 +584,13 @@ js::ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp, RegExpStatics *res = cx->regExpStatics(); /* Step 2. */ JSString *input = ToString(cx, (args.length() > 0) ? args[0] : UndefinedValue()); if (!input) return false; /* Step 3. */ Rooted<JSLinearString*> linearInput(cx, string->ensureLinear(cx)); Rooted<JSLinearString*> linearInput(cx, input->ensureLinear(cx)); if (!linearInput) return false; Loading @@ -602,20 +612,20 @@ js::ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp, /* Step 9a. */ if (i < 0 || i > length) { reobj->zeroLastIndex(); rval.setNull(); args.rval().setNull(); return true; } /* Steps 8-21. */ size_t lastIndexInt(i); if (!ExecuteRegExp(cx, res, *re, linearInput.get(), chars, length, &lastIndexInt, execType, rval.address())) { if (!ExecuteRegExp(cx, res, *re, linearInput, chars, length, &lastIndexInt, execType, args.rval().address())) { return false; } /* Step 11 (with sticky extension). */ if (re->global() || (!rval.isNull() && re->sticky())) { if (rval.isNull()) if (re->global() || (!args.rval().isNull() && re->sticky())) { if (args.rval().isNull()) reobj->zeroLastIndex(); else reobj->setLastIndex(lastIndexInt); Loading @@ -624,26 +634,6 @@ js::ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp, return true; } /* * ES5 15.10.6.2 (and 15.10.6.3, which calls 15.10.6.2). * * RegExp.prototype.test doesn't need to create a results array, and we use * |execType| to perform this optimization. */ static bool ExecuteRegExp(JSContext *cx, RegExpExecType execType, CallArgs args) { /* Step 1 (a) was performed by CallNonGenericMethod. */ RootedObject regexp(cx, &args.thisv().toObject()); /* Step 2. */ RootedString string(cx, ToString(cx, (args.length() > 0) ? args[0] : UndefinedValue())); if (!string) return false; return ExecuteRegExp(cx, execType, regexp, string, args.rval()); } /* ES5 15.10.6.2. */ static bool regexp_exec_impl(JSContext *cx, CallArgs args) Loading js/src/builtin/RegExp.h +0 −4 Original line number Diff line number Diff line Loading @@ -35,10 +35,6 @@ ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpShared &shared, JSLinearString *input, const jschar *chars, size_t length, size_t *lastIndex, RegExpExecType type, Value *rval); bool ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp, HandleString string, MutableHandleValue rval); extern JSBool regexp_exec(JSContext *cx, unsigned argc, Value *vp); Loading js/src/ion/CodeGenerator.cpp +0 −24 Original line number Diff line number Diff line Loading @@ -233,30 +233,6 @@ CodeGenerator::visitRegExp(LRegExp *lir) return callVM(CloneRegExpObjectInfo, lir); } bool CodeGenerator::visitRegExpTest(LRegExpTest *lir) { typedef bool (*pf)(JSContext *cx, RegExpExecType type, HandleObject regexp, HandleString string, MutableHandleValue rval); static const VMFunction ExecuteRegExpInfo = FunctionInfo<pf>(ExecuteRegExp); pushArg(ToRegister(lir->string())); pushArg(ToRegister(lir->regexp())); pushArg(Imm32(RegExpTest)); if (!callVM(ExecuteRegExpInfo, lir)) return false; Register output = ToRegister(lir->output()); Label notBool, end; masm.branchTestBoolean(Assembler::NotEqual, JSReturnOperand, ¬Bool); masm.unboxBoolean(JSReturnOperand, output); masm.jump(&end); masm.bind(¬Bool); masm.mov(Imm32(0), output); masm.bind(&end); return true; } bool CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton *lir) { Loading js/src/ion/CodeGenerator.h +0 −1 Original line number Diff line number Diff line Loading @@ -62,7 +62,6 @@ class CodeGenerator : public CodeGeneratorSpecific bool visitIntToString(LIntToString *lir); bool visitInteger(LInteger *lir); bool visitRegExp(LRegExp *lir); bool visitRegExpTest(LRegExpTest *lir); bool visitLambda(LLambda *lir); bool visitLambdaForSingleton(LLambdaForSingleton *lir); bool visitPointer(LPointer *lir); Loading js/src/ion/IonBuilder.cpp +49 −0 Original line number Diff line number Diff line Loading @@ -3676,6 +3676,41 @@ IonBuilder::jsop_funapply(uint32 argc) return pushTypeBarrier(apply, types, barrier); } // Get the builtin RegExp.prototype.test function. static bool GetBuiltinRegExpTest(JSContext *cx, JSScript *script, JSFunction **result) { JS_ASSERT(*result == NULL); // Get the builtin RegExp.prototype object. RootedObject proto(cx, script->global().getOrCreateRegExpPrototype(cx)); if (!proto) return false; // Get the |test| property. Note that we use lookupProperty, not getProperty, // to avoid calling a getter. RootedShape shape(cx); RootedObject holder(cx); if (!JSObject::lookupProperty(cx, proto, cx->names().test, &holder, &shape)) return false; if (proto != holder || !shape || !shape->hasDefaultGetter() || !shape->hasSlot()) return true; // The RegExp.prototype.test property is writable, so we have to ensure // we got the builtin function. Value val = holder->getSlot(shape->slot()); if (!val.isObject()) return true; JSObject *obj = &val.toObject(); if (!obj->isFunction() || obj->toFunction()->maybeNative() != regexp_test) return true; *result = obj->toFunction(); return true; } bool IonBuilder::jsop_call(uint32 argc, bool constructing) { Loading Loading @@ -3705,6 +3740,20 @@ IonBuilder::jsop_call(uint32 argc, bool constructing) } RootedFunction target(cx, NULL); if (numTargets == 1) { target = targets[0]->toFunction(); // Call RegExp.test instead of RegExp.exec if the result will not be used // or will only be used to test for existence. if (target->maybeNative() == regexp_exec && !CallResultEscapes(pc)) { JSFunction *newTarget = NULL; if (!GetBuiltinRegExpTest(cx, script_, &newTarget)) return false; if (newTarget) target = newTarget; } } return makeCallBarrier(target, argc, constructing, types, barrier); } Loading Loading
js/src/builtin/RegExp.cpp +21 −31 Original line number Diff line number Diff line Loading @@ -561,12 +561,17 @@ GetSharedForGreedyStar(JSContext *cx, JSAtom *source, RegExpFlag flags, RegExpGu return cx->compartment->regExps.getHack(cx, source, hackedSource, flags, g); } bool js::ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp, HandleString string, MutableHandleValue rval) /* * ES5 15.10.6.2 (and 15.10.6.3, which calls 15.10.6.2). * * RegExp.prototype.test doesn't need to create a results array, and we use * |execType| to perform this optimization. */ static bool ExecuteRegExp(JSContext *cx, RegExpExecType execType, CallArgs args) { /* Step 1 (b) was performed by CallNonGenericMethod. */ Rooted<RegExpObject*> reobj(cx, ®exp->asRegExp()); /* Step 1 was performed by CallNonGenericMethod. */ Rooted<RegExpObject*> reobj(cx, &args.thisv().toObject().asRegExp()); RegExpGuard re; if (StartsWithGreedyStar(reobj->getSource())) { Loading @@ -579,8 +584,13 @@ js::ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp, RegExpStatics *res = cx->regExpStatics(); /* Step 2. */ JSString *input = ToString(cx, (args.length() > 0) ? args[0] : UndefinedValue()); if (!input) return false; /* Step 3. */ Rooted<JSLinearString*> linearInput(cx, string->ensureLinear(cx)); Rooted<JSLinearString*> linearInput(cx, input->ensureLinear(cx)); if (!linearInput) return false; Loading @@ -602,20 +612,20 @@ js::ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp, /* Step 9a. */ if (i < 0 || i > length) { reobj->zeroLastIndex(); rval.setNull(); args.rval().setNull(); return true; } /* Steps 8-21. */ size_t lastIndexInt(i); if (!ExecuteRegExp(cx, res, *re, linearInput.get(), chars, length, &lastIndexInt, execType, rval.address())) { if (!ExecuteRegExp(cx, res, *re, linearInput, chars, length, &lastIndexInt, execType, args.rval().address())) { return false; } /* Step 11 (with sticky extension). */ if (re->global() || (!rval.isNull() && re->sticky())) { if (rval.isNull()) if (re->global() || (!args.rval().isNull() && re->sticky())) { if (args.rval().isNull()) reobj->zeroLastIndex(); else reobj->setLastIndex(lastIndexInt); Loading @@ -624,26 +634,6 @@ js::ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp, return true; } /* * ES5 15.10.6.2 (and 15.10.6.3, which calls 15.10.6.2). * * RegExp.prototype.test doesn't need to create a results array, and we use * |execType| to perform this optimization. */ static bool ExecuteRegExp(JSContext *cx, RegExpExecType execType, CallArgs args) { /* Step 1 (a) was performed by CallNonGenericMethod. */ RootedObject regexp(cx, &args.thisv().toObject()); /* Step 2. */ RootedString string(cx, ToString(cx, (args.length() > 0) ? args[0] : UndefinedValue())); if (!string) return false; return ExecuteRegExp(cx, execType, regexp, string, args.rval()); } /* ES5 15.10.6.2. */ static bool regexp_exec_impl(JSContext *cx, CallArgs args) Loading
js/src/builtin/RegExp.h +0 −4 Original line number Diff line number Diff line Loading @@ -35,10 +35,6 @@ ExecuteRegExp(JSContext *cx, RegExpStatics *res, RegExpShared &shared, JSLinearString *input, const jschar *chars, size_t length, size_t *lastIndex, RegExpExecType type, Value *rval); bool ExecuteRegExp(JSContext *cx, RegExpExecType execType, HandleObject regexp, HandleString string, MutableHandleValue rval); extern JSBool regexp_exec(JSContext *cx, unsigned argc, Value *vp); Loading
js/src/ion/CodeGenerator.cpp +0 −24 Original line number Diff line number Diff line Loading @@ -233,30 +233,6 @@ CodeGenerator::visitRegExp(LRegExp *lir) return callVM(CloneRegExpObjectInfo, lir); } bool CodeGenerator::visitRegExpTest(LRegExpTest *lir) { typedef bool (*pf)(JSContext *cx, RegExpExecType type, HandleObject regexp, HandleString string, MutableHandleValue rval); static const VMFunction ExecuteRegExpInfo = FunctionInfo<pf>(ExecuteRegExp); pushArg(ToRegister(lir->string())); pushArg(ToRegister(lir->regexp())); pushArg(Imm32(RegExpTest)); if (!callVM(ExecuteRegExpInfo, lir)) return false; Register output = ToRegister(lir->output()); Label notBool, end; masm.branchTestBoolean(Assembler::NotEqual, JSReturnOperand, ¬Bool); masm.unboxBoolean(JSReturnOperand, output); masm.jump(&end); masm.bind(¬Bool); masm.mov(Imm32(0), output); masm.bind(&end); return true; } bool CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton *lir) { Loading
js/src/ion/CodeGenerator.h +0 −1 Original line number Diff line number Diff line Loading @@ -62,7 +62,6 @@ class CodeGenerator : public CodeGeneratorSpecific bool visitIntToString(LIntToString *lir); bool visitInteger(LInteger *lir); bool visitRegExp(LRegExp *lir); bool visitRegExpTest(LRegExpTest *lir); bool visitLambda(LLambda *lir); bool visitLambdaForSingleton(LLambdaForSingleton *lir); bool visitPointer(LPointer *lir); Loading
js/src/ion/IonBuilder.cpp +49 −0 Original line number Diff line number Diff line Loading @@ -3676,6 +3676,41 @@ IonBuilder::jsop_funapply(uint32 argc) return pushTypeBarrier(apply, types, barrier); } // Get the builtin RegExp.prototype.test function. static bool GetBuiltinRegExpTest(JSContext *cx, JSScript *script, JSFunction **result) { JS_ASSERT(*result == NULL); // Get the builtin RegExp.prototype object. RootedObject proto(cx, script->global().getOrCreateRegExpPrototype(cx)); if (!proto) return false; // Get the |test| property. Note that we use lookupProperty, not getProperty, // to avoid calling a getter. RootedShape shape(cx); RootedObject holder(cx); if (!JSObject::lookupProperty(cx, proto, cx->names().test, &holder, &shape)) return false; if (proto != holder || !shape || !shape->hasDefaultGetter() || !shape->hasSlot()) return true; // The RegExp.prototype.test property is writable, so we have to ensure // we got the builtin function. Value val = holder->getSlot(shape->slot()); if (!val.isObject()) return true; JSObject *obj = &val.toObject(); if (!obj->isFunction() || obj->toFunction()->maybeNative() != regexp_test) return true; *result = obj->toFunction(); return true; } bool IonBuilder::jsop_call(uint32 argc, bool constructing) { Loading Loading @@ -3705,6 +3740,20 @@ IonBuilder::jsop_call(uint32 argc, bool constructing) } RootedFunction target(cx, NULL); if (numTargets == 1) { target = targets[0]->toFunction(); // Call RegExp.test instead of RegExp.exec if the result will not be used // or will only be used to test for existence. if (target->maybeNative() == regexp_exec && !CallResultEscapes(pc)) { JSFunction *newTarget = NULL; if (!GetBuiltinRegExpTest(cx, script_, &newTarget)) return false; if (newTarget) target = newTarget; } } return makeCallBarrier(target, argc, constructing, types, barrier); } Loading