Bug 636820: Use new |this| computation in mjit implementation of callgname, r=dvander,gal, a=blocking

This commit is contained in:
David Mandelin 2011-02-25 19:07:32 -08:00
parent ccbfde2165
commit 8e2207d22a
7 changed files with 138 additions and 7 deletions

View File

@ -0,0 +1,14 @@
// |jit-test| mjitalways;
this.name = "outer";
var sb = evalcx('');
sb.name = "inner";
sb.parent = this;
function f() { return this.name; }
assertEq(evalcx('this.f = parent.f;\n' +
'var s = "";\n' +
'for (i = 0; i < 10; ++i)\n' +
' s += f();\n' +
's',
sb),
"innerinnerinnerinnerinnerinnerinnerinnerinnerinner");

View File

@ -1889,7 +1889,7 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_CALLGNAME)
jsop_getgname(fullAtomIndex(PC));
if (op == JSOP_CALLGNAME)
frame.push(UndefinedValue());
jsop_callgname_epilogue();
END_CASE(JSOP_GETGNAME)
BEGIN_CASE(JSOP_SETGNAME)
@ -4368,6 +4368,77 @@ mjit::Compiler::jsop_getgname(uint32 index)
#endif
}
/*
* Generate just the epilogue code that is specific to callgname. The rest
* is shared with getgname.
*/
void
mjit::Compiler::jsop_callgname_epilogue()
{
/*
* This slow path does the same thing as the interpreter.
*/
if (!script->compileAndGo) {
prepareStubCall(Uses(1));
INLINE_STUBCALL(stubs::PushImplicitThisForGlobal);
frame.pushSynced();
return;
}
/* Fast path for known-not-an-object callee. */
FrameEntry *fval = frame.peek(-1);
if (fval->isNotType(JSVAL_TYPE_OBJECT)) {
frame.push(UndefinedValue());
return;
}
/*
* Optimized version. This inlines the common case, calling a
* (non-proxied) function that has the same global as the current
* script. To make the code simpler, we:
* 1. test the stronger property that the callee's parent is
* equal to the global of the current script, and
* 2. bake in the global of the current script, which is why
* this optimized path requires compile-and-go.
*/
/* If the callee is not an object, jump to the inline fast path. */
MaybeRegisterID typeReg = frame.maybePinType(fval);
RegisterID objReg = frame.copyDataIntoReg(fval);
MaybeJump isNotObj;
if (!fval->isType(JSVAL_TYPE_OBJECT)) {
isNotObj = frame.testObject(Assembler::NotEqual, fval);
frame.maybeUnpinReg(typeReg);
}
/*
* If the callee is not a function, jump to OOL slow path.
*/
Jump notFunction = masm.testFunction(Assembler::NotEqual, objReg);
stubcc.linkExit(notFunction, Uses(1));
/*
* If the callee's parent is not equal to the global, jump to
* OOL slow path.
*/
masm.loadPtr(Address(objReg, offsetof(JSObject, parent)), objReg);
Jump globalMismatch = masm.branchPtr(Assembler::NotEqual, objReg, ImmPtr(globalObj));
stubcc.linkExit(globalMismatch, Uses(1));
frame.freeReg(objReg);
/* OOL stub call path. */
stubcc.leave();
OOL_STUBCALL(stubs::PushImplicitThisForGlobal);
/* Fast path. */
if (isNotObj.isSet())
isNotObj.getJump().linkTo(masm.label(), &masm);
frame.pushUntypedValue(UndefinedValue());
stubcc.rejoin(Changes(1));
}
void
mjit::Compiler::jsop_setgname_slow(JSAtom *atom, bool usePropertyCache)
{

View File

@ -446,6 +446,7 @@ class Compiler : public BaseCompiler
void jsop_eleminc(JSOp op, VoidStub);
void jsop_getgname(uint32 index);
void jsop_getgname_slow(uint32 index);
void jsop_callgname_epilogue();
void jsop_setgname(JSAtom *atom, bool usePropertyCache);
void jsop_setgname_slow(JSAtom *atom, bool usePropertyCache);
void jsop_bindgname();

View File

@ -375,6 +375,26 @@ FrameState::pushUntypedPayload(JSValueType type, RegisterID payload)
regstate[payload].associate(fe, RematInfo::DATA);
}
inline void
FrameState::pushUntypedValue(Value &v)
{
FrameEntry *fe = rawPush();
fe->clear();
masm.storeValue(v, addressOf(fe));
/* The forceful type sync will assert otherwise. */
#ifdef DEBUG
fe->type.unsync();
#endif
fe->type.setMemory();
fe->data.unsync();
fe->data.setMemory();
fe->setNotCopied();
fe->setCopyOf(NULL);
}
inline JSC::MacroAssembler::RegisterID
FrameState::tempRegForType(FrameEntry *fe, RegisterID fallback)
{

View File

@ -288,6 +288,13 @@ class FrameState
*/
inline void pushUntypedPayload(JSValueType type, RegisterID payload);
/*
* Pushes a value onto the operation stack. This must be used when the
* value is known, but its type cannot be propagated because it is not
* known to be correct at a slow-path merge point.
*/
inline void pushUntypedValue(Value &value);
/*
* Pushes a number onto the operation stack.
*

View File

@ -319,6 +319,16 @@ stubs::SetGlobalName(VMFrame &f, JSAtom *atom)
template void JS_FASTCALL stubs::SetGlobalName<true>(VMFrame &f, JSAtom *atom);
template void JS_FASTCALL stubs::SetGlobalName<false>(VMFrame &f, JSAtom *atom);
static inline void
PushImplicitThis(VMFrame &f, JSObject *obj, Value &rval)
{
Value thisv;
if (!ComputeImplicitThis(f.cx, obj, rval, &thisv))
return;
*f.regs.sp++ = thisv;
}
static JSObject *
NameOp(VMFrame &f, JSObject *obj, bool callname = false)
{
@ -377,13 +387,9 @@ NameOp(VMFrame &f, JSObject *obj, bool callname = false)
*f.regs.sp++ = rval;
if (callname) {
Value thisv;
if (callname)
PushImplicitThis(f, obj, rval);
if (!ComputeImplicitThis(cx, obj, rval, &thisv))
return NULL;
*f.regs.sp++ = thisv;
}
return obj;
}
@ -579,6 +585,17 @@ stubs::CallName(VMFrame &f)
THROW();
}
/*
* Push the implicit this value, with the assumption that the callee
* (which is on top of the stack) was read as a property from the
* global object.
*/
void JS_FASTCALL
stubs::PushImplicitThisForGlobal(VMFrame &f)
{
return PushImplicitThis(f, f.fp()->scopeChain().getGlobal(), f.regs.sp[-1]);
}
void JS_FASTCALL
stubs::BitOr(VMFrame &f)
{

View File

@ -136,6 +136,7 @@ void JS_FASTCALL CallElem(VMFrame &f);
template<JSBool strict> void JS_FASTCALL SetElem(VMFrame &f);
void JS_FASTCALL Length(VMFrame &f);
void JS_FASTCALL CallName(VMFrame &f);
void JS_FASTCALL PushImplicitThisForGlobal(VMFrame &f);
void JS_FASTCALL GetUpvar(VMFrame &f, uint32 index);
void JS_FASTCALL GetGlobalName(VMFrame &f);