Add call scope to JSFunction, bug 693754.

This commit is contained in:
Brian Hackett 2011-10-13 12:10:52 -07:00
Родитель c90a77a4aa
Коммит def71d2001
9 изменённых файлов: 44 добавлений и 46 удалений

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

@ -2053,13 +2053,15 @@ fun_bind(JSContext *cx, uintN argc, Value *vp)
/* Step 4-6, 10-11. */
JSAtom *name = target->isFunction() ? target->toFunction()->atom : NULL;
/* NB: Bound functions abuse |parent| to store their target. */
JSObject *funobj =
js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length,
JSFUN_CONSTRUCTOR, target, name);
if (!funobj)
return false;
/* NB: Bound functions abuse |parent| to store their target. */
funobj->setParent(target);
/* Steps 7-9. */
Value thisArg = args.length() >= 1 ? args[0] : UndefinedValue();
if (!funobj->initBoundFunction(cx, thisArg, boundArgs, argslen))
@ -2317,9 +2319,9 @@ js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
if (funobj) {
JS_ASSERT(funobj->isFunction());
funobj->setParent(parent);
JS_ASSERT(funobj->getParent() == parent);
} else {
funobj = NewFunction(cx, parent);
funobj = NewFunction(cx, parent ? parent->getGlobal() : NULL);
if (!funobj)
return NULL;
if (native && !funobj->setSingletonType(cx))
@ -2335,6 +2337,7 @@ js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
JS_ASSERT(nargs == 0);
fun->u.i.skipmin = 0;
fun->u.i.script = NULL;
fun->setCallScope(parent);
} else {
fun->u.n.clasp = NULL;
if (flags & JSFUN_TRCINFO) {
@ -2364,7 +2367,7 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
JS_ASSERT(parent);
JS_ASSERT(proto);
JSFunction *clone = NewFunction(cx, parent);
JSFunction *clone = NewFunction(cx, parent->getGlobal());
if (!clone)
return NULL;
@ -2373,6 +2376,9 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
clone->u = fun->toFunction()->u;
clone->atom = fun->atom;
if (clone->isInterpreted())
clone->setCallScope(parent);
if (cx->compartment == fun->compartment()) {
/*
* We can use the same type as the original function provided that (a)

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

@ -163,7 +163,15 @@ struct JSFunction : public JSObject_Slots2
return flags & JSFUN_JOINABLE;
}
/*
* Accessors for the scope chain to use when calling an interpreted
* function. The parent link for such functions points to the scope chain's
* global object.
*/
inline JSObject *callScope() const;
inline void setCallScope(JSObject *obj);
static inline size_t offsetOfCallScope() { return offsetof(JSFunction, u.i.scope); }
/*
* FunctionClass reserves two slots, which are free in JSObject::fslots

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

@ -53,8 +53,14 @@ inline JSObject *
JSFunction::callScope() const
{
JS_ASSERT(isInterpreted());
return getParent();
//return u.i.scope;
return u.i.scope;
}
inline void
JSFunction::setCallScope(JSObject *obj)
{
JS_ASSERT(isInterpreted());
u.i.scope = obj;
}
inline void
@ -249,7 +255,7 @@ CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
*/
if (ignoreSingletonClone && fun->hasSingletonType()) {
JS_ASSERT(fun->getProto() == proto);
fun->setParent(parent);
fun->setCallScope(parent);
return fun;
}
@ -271,7 +277,7 @@ CloneFunctionObject(JSContext *cx, JSFunction *fun)
if (fun->hasSingletonType())
return fun;
return js_CloneFunctionObject(cx, fun, fun->getParent(), fun->getProto());
return js_CloneFunctionObject(cx, fun, fun->callScope(), fun->getProto());
}
} /* namespace js */

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

@ -324,7 +324,7 @@ TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
JSFunction *fun = callee->toFunction();
if (fun->isInterpreted()) {
JSScript *script = fun->script();
if (!script->ensureRanAnalysis(cx, fun, callee->getParent()))
if (!script->ensureRanAnalysis(cx, fun, fun->callScope()))
return;
if (cx->typeInferenceEnabled())
TypeMonitorCallSlow(cx, callee, args, constructing);

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

@ -1034,25 +1034,14 @@ EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, uintN st
if (src == str || EqualStrings(src, str)) {
/*
* Source matches, qualify by comparing scopeobj to the
* COMPILE_N_GO-memoized parent of the first literal
* function or regexp object if any. If none, then this
* script has no compiled-in dependencies on the prior
* eval's scopeobj.
* Source matches. Make sure there are no inner objects
* which might use the wrong parent and/or call scope by
* reusing the previous eval's script. Skip the script's
* first object, which entrains the eval's scope.
*/
JSObjectArray *objarray = script->objects();
int i = 1;
if (objarray->length == 1) {
if (JSScript::isValidOffset(script->regexpsOffset)) {
objarray = script->regexps();
i = 0;
} else {
i = -1;
}
}
if (i < 0 ||
objarray->vector[i]->getParent() == &scopeobj) {
JS_ASSERT(script->objects()->length >= 1);
if (script->objects()->length == 1 &&
!JSScript::isValidOffset(script->regexpsOffset)) {
JS_ASSERT(staticLevel == script->staticLevel);
*scriptp = script->u.evalHashLink;
script->u.evalHashLink = NULL;

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

@ -1663,17 +1663,6 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
return NewObject<withProto>(cx, clasp, proto, parent, kind);
}
static JS_ALWAYS_INLINE JSFunction *
NewFunction(JSContext *cx, js::GlobalObject &global)
{
JSObject *proto;
if (!js_GetClassPrototype(cx, &global, JSProto_Function, &proto))
return NULL;
JSObject *obj = NewObject<WithProto::Given>(cx, &FunctionClass, proto, &global,
gc::FINALIZE_FUNCTION);
return static_cast<JSFunction *>(obj);
}
static JS_ALWAYS_INLINE JSFunction *
NewFunction(JSContext *cx, JSObject *parent)
{

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

@ -785,7 +785,7 @@ mjit::Compiler::generatePrologue()
Jump hasScope = masm.branchTest32(Assembler::NonZero,
FrameFlagsAddress(), Imm32(StackFrame::HAS_SCOPECHAIN));
masm.loadPayload(Address(JSFrameReg, StackFrame::offsetOfCallee(script->function())), t0);
masm.loadPtr(Address(t0, offsetof(JSObject, parent)), t0);
masm.loadPtr(Address(t0, JSFunction::offsetOfCallScope()), t0);
masm.storePtr(t0, Address(JSFrameReg, StackFrame::offsetOfScopeChain()));
hasScope.linkTo(masm.label(), &masm);
}
@ -6124,7 +6124,7 @@ mjit::Compiler::jsop_callgname_epilogue()
* If the callee's parent is not equal to the global, jump to
* OOL slow path.
*/
masm.loadPtr(Address(objReg, offsetof(JSObject, parent)), objReg);
masm.loadPtr(Address(objReg, JSFunction::offsetOfCallScope()), objReg);
Jump globalMismatch = masm.branchPtr(Assembler::NotEqual, objReg, ImmPtr(globalObj));
stubcc.linkExit(globalMismatch, Uses(1));
frame.freeReg(objReg);

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

@ -706,7 +706,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
* windows, and user-defined JS functions precompiled and then shared among
* requests in server-side JS.
*/
if (obj->getParent() != obj2) {
if (obj->toFunction()->callScope() != obj2) {
obj = CloneFunctionObject(cx, fun, obj2, true);
if (!obj)
THROW();
@ -1351,7 +1351,7 @@ stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
if (!parent)
THROWV(NULL);
if (obj->getParent() != parent) {
if (obj->toFunction()->callScope() != parent) {
obj = CloneFunctionObject(f.cx, fun, parent, true);
if (!obj)
THROWV(NULL);

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

@ -73,7 +73,7 @@ StackFrame::scopeChain() const
{
JS_ASSERT_IF(!(flags_ & HAS_SCOPECHAIN), isFunctionFrame());
if (!(flags_ & HAS_SCOPECHAIN)) {
scopeChain_ = callee().getParent();
scopeChain_ = callee().toFunction()->callScope();
flags_ |= HAS_SCOPECHAIN;
}
return *scopeChain_;
@ -158,7 +158,7 @@ StackFrame::initCallFrame(JSContext *cx, JSObject &callee, JSFunction *fun,
flags_ = FUNCTION | HAS_PREVPC | HAS_SCOPECHAIN | flagsArg;
exec.fun = fun;
args.nactual = nactual;
scopeChain_ = callee.getParent();
scopeChain_ = callee.toFunction()->callScope();
ncode_ = NULL;
initPrev(cx);
JS_ASSERT(!hasImacropc());
@ -195,7 +195,7 @@ StackFrame::resetCallFrame(JSScript *script)
UNDERFLOW_ARGS;
JS_ASSERT(exec.fun->script() == callee().toFunction()->script());
scopeChain_ = callee().getParent();
scopeChain_ = callee().toFunction()->callScope();
SetValueRangeToUndefined(slots(), script->nfixed);
}
@ -478,7 +478,7 @@ StackFrame::markFunctionEpilogueDone()
* scope chain.
*/
scopeChain_ = isFunctionFrame()
? callee().getParent()
? callee().toFunction()->callScope()
: scopeChain_->scopeChain();
flags_ &= ~HAS_CALL_OBJ;
}