зеркало из https://github.com/mozilla/gecko-dev.git
Transform RegExp.exec to RegExp.test in native call IC, bug 645889. r=dmandelin
This commit is contained in:
Родитель
95aaffbddc
Коммит
92e44bf5eb
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче