mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 729382 - move the rest of the CallObject into ScopeObject (r=waldo)
This commit is contained in:
parent
644e9f3621
commit
f6301bef27
@ -589,7 +589,7 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fpArg)
|
||||
* null returned above or in the #else
|
||||
*/
|
||||
if (!fp->hasCallObj() && fp->isNonEvalFunctionFrame())
|
||||
return CreateFunCallObject(cx, fp);
|
||||
return CallObject::createForFunction(cx, fp);
|
||||
return &fp->callObj();
|
||||
}
|
||||
|
||||
@ -844,10 +844,10 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
|
||||
| (!shape->writable() ? JSPD_READONLY : 0)
|
||||
| (!shape->configurable() ? JSPD_PERMANENT : 0);
|
||||
pd->spare = 0;
|
||||
if (shape->getter() == GetCallArg) {
|
||||
if (shape->getter() == CallObject::getArgOp) {
|
||||
pd->slot = shape->shortid();
|
||||
pd->flags |= JSPD_ARGUMENT;
|
||||
} else if (shape->getter() == GetCallVar) {
|
||||
} else if (shape->getter() == CallObject::getVarOp) {
|
||||
pd->slot = shape->shortid();
|
||||
pd->flags |= JSPD_VARIABLE;
|
||||
} else {
|
||||
|
344
js/src/jsfun.cpp
344
js/src/jsfun.cpp
@ -599,350 +599,6 @@ Class js::StrictArgumentsObjectClass = {
|
||||
}
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
||||
CallObject *
|
||||
CreateFunCallObject(JSContext *cx, StackFrame *fp)
|
||||
{
|
||||
JS_ASSERT(fp->isNonEvalFunctionFrame());
|
||||
JS_ASSERT(!fp->hasCallObj());
|
||||
|
||||
JSObject *scopeChain = &fp->scopeChain();
|
||||
JS_ASSERT_IF(scopeChain->isWith() || scopeChain->isBlock() || scopeChain->isCall(),
|
||||
scopeChain->getPrivate() != fp);
|
||||
|
||||
/*
|
||||
* For a named function expression Call's parent points to an environment
|
||||
* object holding function's name.
|
||||
*/
|
||||
if (JSAtom *lambdaName = CallObjectLambdaName(fp->fun())) {
|
||||
scopeChain = DeclEnvObject::create(cx, fp);
|
||||
if (!scopeChain)
|
||||
return NULL;
|
||||
|
||||
if (!DefineNativeProperty(cx, scopeChain, ATOM_TO_JSID(lambdaName),
|
||||
ObjectValue(fp->callee()), NULL, NULL,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CallObject *callobj = CallObject::create(cx, fp->script(), *scopeChain, &fp->callee());
|
||||
if (!callobj)
|
||||
return NULL;
|
||||
|
||||
callobj->setStackFrame(fp);
|
||||
fp->setScopeChainWithOwnCallObj(*callobj);
|
||||
return callobj;
|
||||
}
|
||||
|
||||
CallObject *
|
||||
CreateEvalCallObject(JSContext *cx, StackFrame *fp)
|
||||
{
|
||||
CallObject *callobj = CallObject::create(cx, fp->script(), fp->scopeChain(), NULL);
|
||||
if (!callobj)
|
||||
return NULL;
|
||||
|
||||
callobj->setStackFrame(fp);
|
||||
fp->setScopeChainWithOwnCallObj(*callobj);
|
||||
return callobj;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
void
|
||||
js_PutCallObject(StackFrame *fp)
|
||||
{
|
||||
CallObject &callobj = fp->callObj().asCall();
|
||||
JS_ASSERT(callobj.maybeStackFrame() == fp);
|
||||
JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame());
|
||||
JS_ASSERT(fp->isEvalFrame() == callobj.isForEval());
|
||||
|
||||
/* Get the arguments object to snapshot fp's actual argument values. */
|
||||
if (fp->hasArgsObj()) {
|
||||
if (callobj.arguments().isMagic(JS_UNASSIGNED_ARGUMENTS))
|
||||
callobj.setArguments(ObjectValue(fp->argsObj()));
|
||||
js_PutArgsObject(fp);
|
||||
}
|
||||
|
||||
JSScript *script = fp->script();
|
||||
Bindings &bindings = script->bindings;
|
||||
|
||||
if (callobj.isForEval()) {
|
||||
JS_ASSERT(script->strictModeCode);
|
||||
JS_ASSERT(bindings.countArgs() == 0);
|
||||
|
||||
/* This could be optimized as below, but keep it simple for now. */
|
||||
callobj.copyValues(0, NULL, bindings.countVars(), fp->slots());
|
||||
} else {
|
||||
JSFunction *fun = fp->fun();
|
||||
JS_ASSERT(script == callobj.getCalleeFunction()->script());
|
||||
JS_ASSERT(script == fun->script());
|
||||
|
||||
uintN n = bindings.countArgsAndVars();
|
||||
if (n > 0) {
|
||||
uint32_t nvars = bindings.countVars();
|
||||
uint32_t nargs = bindings.countArgs();
|
||||
JS_ASSERT(fun->nargs == nargs);
|
||||
JS_ASSERT(nvars + nargs == n);
|
||||
|
||||
JSScript *script = fun->script();
|
||||
if (script->usesEval
|
||||
#ifdef JS_METHODJIT
|
||||
|| script->debugMode
|
||||
#endif
|
||||
) {
|
||||
callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots());
|
||||
} else {
|
||||
/*
|
||||
* For each arg & var that is closed over, copy it from the stack
|
||||
* into the call object. We use initArg/VarUnchecked because,
|
||||
* when you call a getter on a call object, js_NativeGetInline
|
||||
* caches the return value in the slot, so we can't assert that
|
||||
* it's undefined.
|
||||
*/
|
||||
uint32_t nclosed = script->nClosedArgs;
|
||||
for (uint32_t i = 0; i < nclosed; i++) {
|
||||
uint32_t e = script->getClosedArg(i);
|
||||
#ifdef JS_GC_ZEAL
|
||||
callobj.setArg(e, fp->formalArg(e));
|
||||
#else
|
||||
callobj.initArgUnchecked(e, fp->formalArg(e));
|
||||
#endif
|
||||
}
|
||||
|
||||
nclosed = script->nClosedVars;
|
||||
for (uint32_t i = 0; i < nclosed; i++) {
|
||||
uint32_t e = script->getClosedVar(i);
|
||||
#ifdef JS_GC_ZEAL
|
||||
callobj.setVar(e, fp->slots()[e]);
|
||||
#else
|
||||
callobj.initVarUnchecked(e, fp->slots()[e]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the args and vars for the active call if this is an outer
|
||||
* function in a script nesting.
|
||||
*/
|
||||
types::TypeScriptNesting *nesting = script->nesting();
|
||||
if (nesting && script->isOuterFunction) {
|
||||
nesting->argArray = callobj.argArray();
|
||||
nesting->varArray = callobj.varArray();
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear private pointers to fp, which is about to go away. */
|
||||
if (js_IsNamedLambda(fun)) {
|
||||
JSObject &env = callobj.enclosingScope();
|
||||
JS_ASSERT(env.asDeclEnv().maybeStackFrame() == fp);
|
||||
env.setPrivate(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
callobj.setStackFrame(NULL);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
static JSBool
|
||||
GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
|
||||
StackFrame *fp = callobj.maybeStackFrame();
|
||||
if (fp && callobj.arguments().isMagic(JS_UNASSIGNED_ARGUMENTS)) {
|
||||
JSObject *argsobj = js_GetArgsObject(cx, fp);
|
||||
if (!argsobj)
|
||||
return false;
|
||||
vp->setObject(*argsobj);
|
||||
} else {
|
||||
/* Nested functions cannot get the 'arguments' of enclosing scopes. */
|
||||
JS_ASSERT(!callobj.arguments().isMagic(JS_UNASSIGNED_ARGUMENTS));
|
||||
*vp = callobj.arguments();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
/* Nested functions cannot set the 'arguments' of enclosing scopes. */
|
||||
JS_ASSERT(obj->asCall().maybeStackFrame());
|
||||
obj->asCall().setArguments(*vp);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
*vp = fp->formalArg(i);
|
||||
else
|
||||
*vp = callobj.arg(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
fp->formalArg(i) = *vp;
|
||||
else
|
||||
callobj.setArg(i, *vp);
|
||||
|
||||
JSFunction *fun = callobj.getCalleeFunction();
|
||||
JSScript *script = fun->script();
|
||||
if (!script->ensureHasTypes(cx))
|
||||
return false;
|
||||
|
||||
TypeScript::SetArgument(cx, script, i, *vp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
*vp = callobj.getCallee()->toFunction()->getFlatClosureUpvar(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
callobj.getCallee()->toFunction()->setFlatClosureUpvar(i, *vp);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
*vp = fp->varSlot(i);
|
||||
else
|
||||
*vp = callobj.var(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
fp->varSlot(i) = *vp;
|
||||
else
|
||||
callobj.setVar(i, *vp);
|
||||
|
||||
JSFunction *fun = callobj.getCalleeFunction();
|
||||
JSScript *script = fun->script();
|
||||
if (!script->ensureHasTypes(cx))
|
||||
return false;
|
||||
|
||||
TypeScript::SetLocal(cx, script, i, *vp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
static JSBool
|
||||
call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
|
||||
{
|
||||
JS_ASSERT(!obj->getProto());
|
||||
|
||||
if (!JSID_IS_ATOM(id))
|
||||
return true;
|
||||
|
||||
JSObject *callee = obj->asCall().getCallee();
|
||||
#ifdef DEBUG
|
||||
if (callee) {
|
||||
JSScript *script = callee->toFunction()->script();
|
||||
JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id)));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Resolve arguments so that we never store a particular Call object's
|
||||
* arguments object reference in a Call prototype's |arguments| slot.
|
||||
*
|
||||
* Include JSPROP_ENUMERATE for consistency with all other Call object
|
||||
* properties; see js::Bindings::add and js::Interpret's JSOP_DEFFUN
|
||||
* rebinding-Call-property logic.
|
||||
*/
|
||||
if (callee && id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
|
||||
if (!DefineNativeProperty(cx, obj, id, UndefinedValue(),
|
||||
GetCallArguments, SetCallArguments,
|
||||
JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE,
|
||||
0, 0, DNP_DONT_PURGE)) {
|
||||
return false;
|
||||
}
|
||||
*objp = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Control flow reaches here only if id was not resolved. */
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
call_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isCall());
|
||||
|
||||
/* Mark any generator frame, as for arguments objects. */
|
||||
#if JS_HAS_GENERATORS
|
||||
StackFrame *fp = (StackFrame *) obj->getPrivate();
|
||||
if (fp && fp->isFloatingGenerator())
|
||||
MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object");
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_PUBLIC_DATA(Class) js::CallClass = {
|
||||
"Call",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS) |
|
||||
JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS,
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_PropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
(JSResolveOp)call_resolve,
|
||||
NULL, /* convert: Leave it NULL so we notice if calls ever escape */
|
||||
NULL, /* finalize */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* hasInstance */
|
||||
call_trace
|
||||
};
|
||||
|
||||
bool
|
||||
StackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
||||
{
|
||||
|
@ -362,30 +362,6 @@ js_PutCallObject(js::StackFrame *fp);
|
||||
|
||||
namespace js {
|
||||
|
||||
CallObject *
|
||||
CreateFunCallObject(JSContext *cx, StackFrame *fp);
|
||||
|
||||
CallObject *
|
||||
CreateEvalCallObject(JSContext *cx, StackFrame *fp);
|
||||
|
||||
extern JSBool
|
||||
GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
|
||||
|
||||
extern JSBool
|
||||
GetCallVar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
|
||||
|
||||
extern JSBool
|
||||
GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
|
||||
|
||||
extern JSBool
|
||||
SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp);
|
||||
|
||||
extern JSBool
|
||||
SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp);
|
||||
|
||||
extern JSBool
|
||||
SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp);
|
||||
|
||||
/*
|
||||
* Function extended with reserved slots for use by various kinds of functions.
|
||||
* Most functions do not have these extensions, but enough are that efficient
|
||||
|
@ -160,7 +160,7 @@ js::GetScopeChain(JSContext *cx, StackFrame *fp)
|
||||
JSObject *limitBlock, *limitClone;
|
||||
if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj()) {
|
||||
JS_ASSERT_IF(fp->scopeChain().isClonedBlock(), fp->scopeChain().getPrivate() != fp);
|
||||
if (!CreateFunCallObject(cx, fp))
|
||||
if (!CallObject::createForFunction(cx, fp))
|
||||
return NULL;
|
||||
|
||||
/* We know we must clone everything on blockChain. */
|
||||
@ -646,7 +646,7 @@ js::ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const V
|
||||
|
||||
/* Give strict mode eval its own fresh lexical environment. */
|
||||
StackFrame *fp = efg.fp();
|
||||
if (fp->isStrictEvalFrame() && !CreateEvalCallObject(cx, fp))
|
||||
if (fp->isStrictEvalFrame() && !CallObject::createForStrictEval(cx, fp))
|
||||
return false;
|
||||
|
||||
Probes::startExecution(cx, script);
|
||||
|
@ -98,9 +98,9 @@ Bindings::lookup(JSContext *cx, JSAtom *name, uintN *indexp) const
|
||||
if (indexp)
|
||||
*indexp = shape->shortid();
|
||||
|
||||
if (shape->getter() == GetCallArg)
|
||||
if (shape->getter() == CallObject::getArgOp)
|
||||
return ARGUMENT;
|
||||
if (shape->getter() == GetCallUpvar)
|
||||
if (shape->getter() == CallObject::getUpvarOp)
|
||||
return UPVAR;
|
||||
|
||||
return shape->writable() ? VARIABLE : CONSTANT;
|
||||
@ -128,13 +128,13 @@ Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
|
||||
JS_ASSERT(nvars == 0);
|
||||
JS_ASSERT(nupvars == 0);
|
||||
indexp = &nargs;
|
||||
getter = GetCallArg;
|
||||
setter = SetCallArg;
|
||||
getter = CallObject::getArgOp;
|
||||
setter = CallObject::setArgOp;
|
||||
slot += nargs;
|
||||
} else if (kind == UPVAR) {
|
||||
indexp = &nupvars;
|
||||
getter = GetCallUpvar;
|
||||
setter = SetCallUpvar;
|
||||
getter = CallObject::getUpvarOp;
|
||||
setter = CallObject::setUpvarOp;
|
||||
slot = lastBinding->maybeSlot();
|
||||
attrs |= JSPROP_SHARED;
|
||||
} else {
|
||||
@ -142,8 +142,8 @@ Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
|
||||
JS_ASSERT(nupvars == 0);
|
||||
|
||||
indexp = &nvars;
|
||||
getter = GetCallVar;
|
||||
setter = SetCallVar;
|
||||
getter = CallObject::getVarOp;
|
||||
setter = CallObject::setVarOp;
|
||||
if (kind == CONSTANT)
|
||||
attrs |= JSPROP_READONLY;
|
||||
slot += nargs + nvars;
|
||||
@ -248,9 +248,9 @@ Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
|
||||
const Shape &shape = r.front();
|
||||
uintN index = uint16_t(shape.shortid());
|
||||
|
||||
if (shape.getter() == GetCallArg) {
|
||||
if (shape.getter() == CallObject::getArgOp) {
|
||||
JS_ASSERT(index < nargs);
|
||||
} else if (shape.getter() == GetCallUpvar) {
|
||||
} else if (shape.getter() == CallObject::getUpvarOp) {
|
||||
JS_ASSERT(index < nupvars);
|
||||
index += nargs + nvars;
|
||||
} else {
|
||||
@ -262,7 +262,7 @@ Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
|
||||
names[index] = JSID_TO_ATOM(shape.propid());
|
||||
} else {
|
||||
JS_ASSERT(JSID_IS_INT(shape.propid()));
|
||||
JS_ASSERT(shape.getter() == GetCallArg);
|
||||
JS_ASSERT(shape.getter() == CallObject::getArgOp);
|
||||
names[index] = NULL;
|
||||
}
|
||||
}
|
||||
@ -282,7 +282,7 @@ Bindings::lastArgument() const
|
||||
|
||||
const js::Shape *shape = lastVariable();
|
||||
if (nvars > 0) {
|
||||
while (shape->previous() && shape->getter() != GetCallArg)
|
||||
while (shape->previous() && shape->getter() != CallObject::getArgOp)
|
||||
shape = shape->previous();
|
||||
}
|
||||
return shape;
|
||||
@ -295,7 +295,7 @@ Bindings::lastVariable() const
|
||||
|
||||
const js::Shape *shape = lastUpvar();
|
||||
if (nupvars > 0) {
|
||||
while (shape->getter() == GetCallUpvar)
|
||||
while (shape->getter() == CallObject::getUpvarOp)
|
||||
shape = shape->previous();
|
||||
}
|
||||
return shape;
|
||||
|
@ -408,7 +408,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||
Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg);
|
||||
|
||||
{
|
||||
Address addr(pic.shapeReg, shape->setterOp() == SetCallArg
|
||||
Address addr(pic.shapeReg, shape->setterOp() == CallObject::setArgOp
|
||||
? StackFrame::offsetOfFormalArg(fun, slot)
|
||||
: StackFrame::offsetOfFixed(slot));
|
||||
masm.storeValue(pic.u.vr, addr);
|
||||
@ -417,7 +417,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||
|
||||
escapedFrame.linkTo(masm.label(), &masm);
|
||||
{
|
||||
if (shape->setterOp() == SetCallVar)
|
||||
if (shape->setterOp() == CallObject::setVarOp)
|
||||
slot += fun->nargs;
|
||||
|
||||
slot += CallObject::RESERVED_SLOTS;
|
||||
@ -655,8 +655,8 @@ class SetPropCompiler : public PICStubCompiler
|
||||
} else {
|
||||
if (shape->hasSetterValue())
|
||||
return disable("scripted setter");
|
||||
if (shape->setterOp() != SetCallArg &&
|
||||
shape->setterOp() != SetCallVar) {
|
||||
if (shape->setterOp() != CallObject::setArgOp &&
|
||||
shape->setterOp() != CallObject::setVarOp) {
|
||||
return disable("setter");
|
||||
}
|
||||
JS_ASSERT(obj->isCall());
|
||||
@ -679,7 +679,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||
return error();
|
||||
{
|
||||
types::AutoEnterTypeInference enter(cx);
|
||||
if (shape->setterOp() == SetCallArg)
|
||||
if (shape->setterOp() == CallObject::setArgOp)
|
||||
pic.rhsTypes->addSubset(cx, types::TypeScript::ArgTypes(script, slot));
|
||||
else
|
||||
pic.rhsTypes->addSubset(cx, types::TypeScript::LocalTypes(script, slot));
|
||||
@ -1548,9 +1548,9 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||
|
||||
CallObjPropKind kind;
|
||||
const Shape *shape = getprop.shape;
|
||||
if (shape->getterOp() == GetCallArg) {
|
||||
if (shape->getterOp() == CallObject::getArgOp) {
|
||||
kind = ARG;
|
||||
} else if (shape->getterOp() == GetCallVar) {
|
||||
} else if (shape->getterOp() == CallObject::getVarOp) {
|
||||
kind = VAR;
|
||||
} else {
|
||||
return disable("unhandled callobj sprop getter");
|
||||
|
@ -2494,7 +2494,7 @@ static Env *
|
||||
Frame_GetEnv(JSContext *cx, StackFrame *fp)
|
||||
{
|
||||
assertSameCompartment(cx, fp);
|
||||
if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj() && !CreateFunCallObject(cx, fp))
|
||||
if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj() && !CallObject::createForFunction(cx, fp))
|
||||
return NULL;
|
||||
return GetScopeChain(cx, fp);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Paul Biggar <pbiggar@mozilla.com> (original author)
|
||||
* Luke Wagner <luke@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
@ -56,6 +57,100 @@
|
||||
using namespace js;
|
||||
using namespace js::types;
|
||||
|
||||
void
|
||||
js_PutCallObject(StackFrame *fp)
|
||||
{
|
||||
CallObject &callobj = fp->callObj().asCall();
|
||||
JS_ASSERT(callobj.maybeStackFrame() == fp);
|
||||
JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame());
|
||||
JS_ASSERT(fp->isEvalFrame() == callobj.isForEval());
|
||||
|
||||
/* Get the arguments object to snapshot fp's actual argument values. */
|
||||
if (fp->hasArgsObj()) {
|
||||
if (callobj.arguments().isMagic(JS_UNASSIGNED_ARGUMENTS))
|
||||
callobj.setArguments(ObjectValue(fp->argsObj()));
|
||||
js_PutArgsObject(fp);
|
||||
}
|
||||
|
||||
JSScript *script = fp->script();
|
||||
Bindings &bindings = script->bindings;
|
||||
|
||||
if (callobj.isForEval()) {
|
||||
JS_ASSERT(script->strictModeCode);
|
||||
JS_ASSERT(bindings.countArgs() == 0);
|
||||
|
||||
/* This could be optimized as below, but keep it simple for now. */
|
||||
callobj.copyValues(0, NULL, bindings.countVars(), fp->slots());
|
||||
} else {
|
||||
JSFunction *fun = fp->fun();
|
||||
JS_ASSERT(script == callobj.getCalleeFunction()->script());
|
||||
JS_ASSERT(script == fun->script());
|
||||
|
||||
uintN n = bindings.countArgsAndVars();
|
||||
if (n > 0) {
|
||||
uint32_t nvars = bindings.countVars();
|
||||
uint32_t nargs = bindings.countArgs();
|
||||
JS_ASSERT(fun->nargs == nargs);
|
||||
JS_ASSERT(nvars + nargs == n);
|
||||
|
||||
JSScript *script = fun->script();
|
||||
if (script->usesEval
|
||||
#ifdef JS_METHODJIT
|
||||
|| script->debugMode
|
||||
#endif
|
||||
) {
|
||||
callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots());
|
||||
} else {
|
||||
/*
|
||||
* For each arg & var that is closed over, copy it from the stack
|
||||
* into the call object. We use initArg/VarUnchecked because,
|
||||
* when you call a getter on a call object, js_NativeGetInline
|
||||
* caches the return value in the slot, so we can't assert that
|
||||
* it's undefined.
|
||||
*/
|
||||
uint32_t nclosed = script->nClosedArgs;
|
||||
for (uint32_t i = 0; i < nclosed; i++) {
|
||||
uint32_t e = script->getClosedArg(i);
|
||||
#ifdef JS_GC_ZEAL
|
||||
callobj.setArg(e, fp->formalArg(e));
|
||||
#else
|
||||
callobj.initArgUnchecked(e, fp->formalArg(e));
|
||||
#endif
|
||||
}
|
||||
|
||||
nclosed = script->nClosedVars;
|
||||
for (uint32_t i = 0; i < nclosed; i++) {
|
||||
uint32_t e = script->getClosedVar(i);
|
||||
#ifdef JS_GC_ZEAL
|
||||
callobj.setVar(e, fp->slots()[e]);
|
||||
#else
|
||||
callobj.initVarUnchecked(e, fp->slots()[e]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the args and vars for the active call if this is an outer
|
||||
* function in a script nesting.
|
||||
*/
|
||||
types::TypeScriptNesting *nesting = script->nesting();
|
||||
if (nesting && script->isOuterFunction) {
|
||||
nesting->argArray = callobj.argArray();
|
||||
nesting->varArray = callobj.varArray();
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear private pointers to fp, which is about to go away. */
|
||||
if (js_IsNamedLambda(fun)) {
|
||||
JSObject &env = callobj.enclosingScope();
|
||||
JS_ASSERT(env.asDeclEnv().maybeStackFrame() == fp);
|
||||
env.setPrivate(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
callobj.setStackFrame(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a call object for the given bindings. If this is a call object
|
||||
* for a function invocation, callee should be the function being called.
|
||||
@ -126,6 +221,248 @@ CallObject::create(JSContext *cx, JSScript *script, JSObject &enclosing, JSObjec
|
||||
return &obj->asCall();
|
||||
}
|
||||
|
||||
CallObject *
|
||||
CallObject::createForFunction(JSContext *cx, StackFrame *fp)
|
||||
{
|
||||
JS_ASSERT(fp->isNonEvalFunctionFrame());
|
||||
JS_ASSERT(!fp->hasCallObj());
|
||||
|
||||
JSObject *scopeChain = &fp->scopeChain();
|
||||
JS_ASSERT_IF(scopeChain->isWith() || scopeChain->isBlock() || scopeChain->isCall(),
|
||||
scopeChain->getPrivate() != fp);
|
||||
|
||||
/*
|
||||
* For a named function expression Call's parent points to an environment
|
||||
* object holding function's name.
|
||||
*/
|
||||
if (JSAtom *lambdaName = CallObjectLambdaName(fp->fun())) {
|
||||
scopeChain = DeclEnvObject::create(cx, fp);
|
||||
if (!scopeChain)
|
||||
return NULL;
|
||||
|
||||
if (!DefineNativeProperty(cx, scopeChain, ATOM_TO_JSID(lambdaName),
|
||||
ObjectValue(fp->callee()), NULL, NULL,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CallObject *callobj = create(cx, fp->script(), *scopeChain, &fp->callee());
|
||||
if (!callobj)
|
||||
return NULL;
|
||||
|
||||
callobj->setStackFrame(fp);
|
||||
fp->setScopeChainWithOwnCallObj(*callobj);
|
||||
return callobj;
|
||||
}
|
||||
|
||||
CallObject *
|
||||
CallObject::createForStrictEval(JSContext *cx, StackFrame *fp)
|
||||
{
|
||||
CallObject *callobj = create(cx, fp->script(), fp->scopeChain(), NULL);
|
||||
if (!callobj)
|
||||
return NULL;
|
||||
|
||||
callobj->setStackFrame(fp);
|
||||
fp->setScopeChainWithOwnCallObj(*callobj);
|
||||
return callobj;
|
||||
}
|
||||
|
||||
JSBool
|
||||
CallObject::getArgumentsOp(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
|
||||
StackFrame *fp = callobj.maybeStackFrame();
|
||||
if (fp && callobj.arguments().isMagic(JS_UNASSIGNED_ARGUMENTS)) {
|
||||
JSObject *argsobj = js_GetArgsObject(cx, fp);
|
||||
if (!argsobj)
|
||||
return false;
|
||||
vp->setObject(*argsobj);
|
||||
} else {
|
||||
/* Nested functions cannot get the 'arguments' of enclosing scopes. */
|
||||
JS_ASSERT(!callobj.arguments().isMagic(JS_UNASSIGNED_ARGUMENTS));
|
||||
*vp = callobj.arguments();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
CallObject::setArgumentsOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
/* Nested functions cannot set the 'arguments' of enclosing scopes. */
|
||||
JS_ASSERT(obj->asCall().maybeStackFrame());
|
||||
obj->asCall().setArguments(*vp);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
CallObject::getArgOp(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
*vp = fp->formalArg(i);
|
||||
else
|
||||
*vp = callobj.arg(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
CallObject::setArgOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
fp->formalArg(i) = *vp;
|
||||
else
|
||||
callobj.setArg(i, *vp);
|
||||
|
||||
JSFunction *fun = callobj.getCalleeFunction();
|
||||
JSScript *script = fun->script();
|
||||
if (!script->ensureHasTypes(cx))
|
||||
return false;
|
||||
|
||||
TypeScript::SetArgument(cx, script, i, *vp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
CallObject::getUpvarOp(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
*vp = callobj.getCallee()->toFunction()->getFlatClosureUpvar(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
CallObject::setUpvarOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
callobj.getCallee()->toFunction()->setFlatClosureUpvar(i, *vp);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
CallObject::getVarOp(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
*vp = fp->varSlot(i);
|
||||
else
|
||||
*vp = callobj.var(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
CallObject::setVarOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
|
||||
JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16_t) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
fp->varSlot(i) = *vp;
|
||||
else
|
||||
callobj.setVar(i, *vp);
|
||||
|
||||
JSFunction *fun = callobj.getCalleeFunction();
|
||||
JSScript *script = fun->script();
|
||||
if (!script->ensureHasTypes(cx))
|
||||
return false;
|
||||
|
||||
TypeScript::SetLocal(cx, script, i, *vp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
|
||||
{
|
||||
JS_ASSERT(!obj->getProto());
|
||||
|
||||
if (!JSID_IS_ATOM(id))
|
||||
return true;
|
||||
|
||||
JSObject *callee = obj->asCall().getCallee();
|
||||
#ifdef DEBUG
|
||||
if (callee) {
|
||||
JSScript *script = callee->toFunction()->script();
|
||||
JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id)));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Resolve arguments so that we never store a particular Call object's
|
||||
* arguments object reference in a Call prototype's |arguments| slot.
|
||||
*
|
||||
* Include JSPROP_ENUMERATE for consistency with all other Call object
|
||||
* properties; see js::Bindings::add and js::Interpret's JSOP_DEFFUN
|
||||
* rebinding-Call-property logic.
|
||||
*/
|
||||
if (callee && id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
|
||||
if (!DefineNativeProperty(cx, obj, id, UndefinedValue(),
|
||||
CallObject::getArgumentsOp, CallObject::setArgumentsOp,
|
||||
JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE,
|
||||
0, 0, DNP_DONT_PURGE)) {
|
||||
return false;
|
||||
}
|
||||
*objp = obj;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Control flow reaches here only if id was not resolved. */
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
call_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isCall());
|
||||
|
||||
/* Mark any generator frame, as for arguments objects. */
|
||||
#if JS_HAS_GENERATORS
|
||||
StackFrame *fp = (StackFrame *) obj->getPrivate();
|
||||
if (fp && fp->isFloatingGenerator())
|
||||
MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object");
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_PUBLIC_DATA(Class) js::CallClass = {
|
||||
"Call",
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS) |
|
||||
JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS,
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_PropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
(JSResolveOp)call_resolve,
|
||||
NULL, /* convert: Leave it NULL so we notice if calls ever escape */
|
||||
NULL, /* finalize */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* hasInstance */
|
||||
call_trace
|
||||
};
|
||||
|
||||
Class js::DeclEnvClass = {
|
||||
js_Object_str,
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
|
@ -103,7 +103,7 @@ class ScopeObject : public JSObject
|
||||
* The stack frame for this scope object, if the frame is still active.
|
||||
* Note: these members may not be called for a StaticBlockObject.
|
||||
*/
|
||||
inline js::StackFrame *maybeStackFrame() const;
|
||||
inline StackFrame *maybeStackFrame() const;
|
||||
inline void setStackFrame(StackFrame *frame);
|
||||
|
||||
/* For jit access. */
|
||||
@ -115,11 +115,14 @@ class CallObject : public ScopeObject
|
||||
static const uint32_t CALLEE_SLOT = 1;
|
||||
static const uint32_t ARGUMENTS_SLOT = 2;
|
||||
|
||||
static CallObject *
|
||||
create(JSContext *cx, JSScript *script, JSObject &enclosing, JSObject *callee);
|
||||
|
||||
public:
|
||||
static const uint32_t RESERVED_SLOTS = 3;
|
||||
|
||||
static CallObject *
|
||||
create(JSContext *cx, JSScript *script, JSObject &enclosing, JSObject *callee);
|
||||
static CallObject *createForFunction(JSContext *cx, StackFrame *fp);
|
||||
static CallObject *createForStrictEval(JSContext *cx, StackFrame *fp);
|
||||
|
||||
/* True if this is for a strict mode eval frame or for a function call. */
|
||||
inline bool isForEval() const;
|
||||
@ -138,28 +141,37 @@ class CallObject : public ScopeObject
|
||||
* 1. js_PutCallObject is called in a frame which hasArgsObj
|
||||
* 2. the script assigns to 'arguments'
|
||||
*/
|
||||
inline const js::Value &arguments() const;
|
||||
inline void setArguments(const js::Value &v);
|
||||
inline const Value &arguments() const;
|
||||
inline void setArguments(const Value &v);
|
||||
|
||||
/* Returns the formal argument at the given index. */
|
||||
inline const js::Value &arg(uintN i) const;
|
||||
inline void setArg(uintN i, const js::Value &v);
|
||||
inline void initArgUnchecked(uintN i, const js::Value &v);
|
||||
inline const Value &arg(uintN i) const;
|
||||
inline void setArg(uintN i, const Value &v);
|
||||
inline void initArgUnchecked(uintN i, const Value &v);
|
||||
|
||||
/* Returns the variable at the given index. */
|
||||
inline const js::Value &var(uintN i) const;
|
||||
inline void setVar(uintN i, const js::Value &v);
|
||||
inline void initVarUnchecked(uintN i, const js::Value &v);
|
||||
inline const Value &var(uintN i) const;
|
||||
inline void setVar(uintN i, const Value &v);
|
||||
inline void initVarUnchecked(uintN i, const Value &v);
|
||||
|
||||
/*
|
||||
* Get the actual arrays of arguments and variables. Only call if type
|
||||
* inference is enabled, where we ensure that call object variables are in
|
||||
* contiguous slots (see NewCallObject).
|
||||
*/
|
||||
inline js::HeapSlotArray argArray();
|
||||
inline js::HeapSlotArray varArray();
|
||||
inline HeapSlotArray argArray();
|
||||
inline HeapSlotArray varArray();
|
||||
|
||||
inline void copyValues(uintN nargs, Value *argv, uintN nvars, Value *slots);
|
||||
|
||||
static JSBool getArgumentsOp(JSContext *cx, JSObject *obj, jsid id, Value *vp);
|
||||
static JSBool setArgumentsOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp);
|
||||
static JSBool getArgOp(JSContext *cx, JSObject *obj, jsid id, Value *vp);
|
||||
static JSBool getVarOp(JSContext *cx, JSObject *obj, jsid id, Value *vp);
|
||||
static JSBool getUpvarOp(JSContext *cx, JSObject *obj, jsid id, Value *vp);
|
||||
static JSBool setArgOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp);
|
||||
static JSBool setVarOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp);
|
||||
static JSBool setUpvarOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp);
|
||||
};
|
||||
|
||||
class DeclEnvObject : public ScopeObject
|
||||
@ -220,7 +232,7 @@ class BlockObject : public NestedScopeObject
|
||||
class StaticBlockObject : public BlockObject
|
||||
{
|
||||
/* These ScopeObject operations are not valid on a static block object. */
|
||||
js::StackFrame *maybeStackFrame() const;
|
||||
StackFrame *maybeStackFrame() const;
|
||||
void setStackFrame(StackFrame *frame);
|
||||
|
||||
public:
|
||||
@ -239,7 +251,7 @@ class StaticBlockObject : public BlockObject
|
||||
Definition *maybeDefinitionParseNode(unsigned i);
|
||||
void poisonDefinitionParseNode(unsigned i);
|
||||
|
||||
const js::Shape *addVar(JSContext *cx, jsid id, intN index, bool *redeclared);
|
||||
const Shape *addVar(JSContext *cx, jsid id, intN index, bool *redeclared);
|
||||
};
|
||||
|
||||
class ClonedBlockObject : public BlockObject
|
||||
|
@ -370,7 +370,7 @@ StackFrame::functionPrologue(JSContext *cx)
|
||||
JSFunction *fun = this->fun();
|
||||
|
||||
if (fun->isHeavyweight()) {
|
||||
if (!CreateFunCallObject(cx, this))
|
||||
if (!CallObject::createForFunction(cx, this))
|
||||
return false;
|
||||
} else {
|
||||
/* Force instantiation of the scope chain, for JIT frames. */
|
||||
|
Loading…
Reference in New Issue
Block a user