Transform RegExp.exec to RegExp.test in native call IC, bug 645889. r=dmandelin

This commit is contained in:
Brian Hackett 2011-03-30 17:43:36 -07:00
Родитель 95aaffbddc
Коммит 92e44bf5eb
4 изменённых файлов: 62 добавлений и 36 удалений

Просмотреть файл

@ -5553,3 +5553,39 @@ ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,
#undef LOCAL_ASSERT
#undef LOCAL_ASSERT_RV
namespace js {
bool
CallResultEscapes(jsbytecode *pc)
{
/*
* If we see any of these sequences, the result is unused:
* - call / pop
* - call / trace / pop
*
* If we see any of these sequences, the result is only tested for nullness:
* - call / ifeq
* - call / trace / ifeq
* - call / not / ifeq
* - call / trace / not / ifeq
*/
if (*pc != JSOP_CALL)
return true;
pc += JSOP_CALL_LENGTH;
if (*pc == JSOP_TRACE)
pc += JSOP_TRACE_LENGTH;
if (*pc == JSOP_POP)
return false;
if (*pc == JSOP_NOT)
pc += JSOP_NOT_LENGTH;
return (*pc != JSOP_IFEQ);
}
} // namespace js

Просмотреть файл

@ -516,6 +516,9 @@ SprintString(Sprinter *sp, JSString *str);
extern ptrdiff_t
Sprint(Sprinter *sp, const char *format, ...);
extern bool
CallResultEscapes(jsbytecode *pc);
}
#endif

Просмотреть файл

@ -11440,47 +11440,24 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
}
} else if (vp[2].isString() && mode == JSOP_CALL) {
if (native == js_regexp_exec) {
jsbytecode *pc = cx->regs->pc;
/*
* If we see any of these sequences, the result is unused:
* - call / pop
* - call / trace / pop
*
* If we see any of these sequences, the result is only tested for nullness:
* - call / ifeq
* - call / trace / ifeq
* - call / not / ifeq
* - call / trace / not / ifeq
*
* In either case, we replace the call to RegExp.exec() on the
* If the result of the call will be unused or only tested against
* nullness, we replace the call to RegExp.exec() on the
* stack with a call to RegExp.test() because "r.exec(s) !=
* null" is equivalent to "r.test(s)". This avoids building
* the result array, which can be expensive. This requires
* that RegExp.prototype.test() hasn't been changed; we check this.
*/
if (pc[0] == JSOP_CALL) {
if ((pc[JSOP_CALL_LENGTH] == JSOP_POP) ||
(pc[JSOP_CALL_LENGTH] == JSOP_TRACE &&
pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH] == JSOP_POP) ||
(pc[JSOP_CALL_LENGTH] == JSOP_IFEQ) ||
(pc[JSOP_CALL_LENGTH] == JSOP_TRACE &&
pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH] == JSOP_IFEQ) ||
(pc[JSOP_CALL_LENGTH] == JSOP_NOT &&
pc[JSOP_CALL_LENGTH + JSOP_NOT_LENGTH] == JSOP_IFEQ) ||
(pc[JSOP_CALL_LENGTH] == JSOP_TRACE &&
pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH] == JSOP_NOT &&
pc[JSOP_CALL_LENGTH + JSOP_TRACE_LENGTH + JSOP_NOT_LENGTH] == JSOP_IFEQ))
{
JSObject* proto;
jsid id = ATOM_TO_JSID(cx->runtime->atomState.testAtom);
/* Get RegExp.prototype.test() and check it hasn't been changed. */
if (js_GetClassPrototype(cx, NULL, JSProto_RegExp, &proto)) {
if (JSObject *tmp = HasNativeMethod(proto, id, js_regexp_test)) {
vp[0] = ObjectValue(*tmp);
funobj = tmp;
fun = tmp->getFunctionPrivate();
native = js_regexp_test;
}
if (!CallResultEscapes(cx->regs->pc)) {
JSObject* proto;
jsid id = ATOM_TO_JSID(cx->runtime->atomState.testAtom);
/* Get RegExp.prototype.test() and check it hasn't been changed. */
if (js_GetClassPrototype(cx, NULL, JSProto_RegExp, &proto)) {
if (JSObject *tmp = HasNativeMethod(proto, id, js_regexp_test)) {
vp[0] = ObjectValue(*tmp);
funobj = tmp;
fun = tmp->getFunctionPrivate();
native = js_regexp_test;
}
}
}

Просмотреть файл

@ -900,7 +900,17 @@ class CallCompiler : public BaseCompiler
else
masm.storeArg(1, argcReg.reg());
masm.storeArg(0, cxReg);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, fun->u.n.native), false);
js::Native native = fun->u.n.native;
/*
* Call RegExp.test instead of exec if the result will not be used or
* will only be used to test for existence.
*/
if (native == js_regexp_exec && !CallResultEscapes(f.regs.pc))
native = js_regexp_test;
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, native), false);
Jump hasException = masm.branchTest32(Assembler::Zero, Registers::ReturnReg,
Registers::ReturnReg);