зеркало из https://github.com/mozilla/gecko-dev.git
Add call scope to JSFunction, bug 693754.
This commit is contained in:
Родитель
c90a77a4aa
Коммит
def71d2001
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче