зеркало из https://github.com/mozilla/gecko-dev.git
Bug 729382 - move the rest of the CallObject into ScopeObject (r=waldo)
This commit is contained in:
Родитель
89ae88e849
Коммит
bc5c79813f
|
@ -589,7 +589,7 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fpArg)
|
||||||
* null returned above or in the #else
|
* null returned above or in the #else
|
||||||
*/
|
*/
|
||||||
if (!fp->hasCallObj() && fp->isNonEvalFunctionFrame())
|
if (!fp->hasCallObj() && fp->isNonEvalFunctionFrame())
|
||||||
return CreateFunCallObject(cx, fp);
|
return CallObject::createForFunction(cx, fp);
|
||||||
return &fp->callObj();
|
return &fp->callObj();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,10 +844,10 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
|
||||||
| (!shape->writable() ? JSPD_READONLY : 0)
|
| (!shape->writable() ? JSPD_READONLY : 0)
|
||||||
| (!shape->configurable() ? JSPD_PERMANENT : 0);
|
| (!shape->configurable() ? JSPD_PERMANENT : 0);
|
||||||
pd->spare = 0;
|
pd->spare = 0;
|
||||||
if (shape->getter() == GetCallArg) {
|
if (shape->getter() == CallObject::getArgOp) {
|
||||||
pd->slot = shape->shortid();
|
pd->slot = shape->shortid();
|
||||||
pd->flags |= JSPD_ARGUMENT;
|
pd->flags |= JSPD_ARGUMENT;
|
||||||
} else if (shape->getter() == GetCallVar) {
|
} else if (shape->getter() == CallObject::getVarOp) {
|
||||||
pd->slot = shape->shortid();
|
pd->slot = shape->shortid();
|
||||||
pd->flags |= JSPD_VARIABLE;
|
pd->flags |= JSPD_VARIABLE;
|
||||||
} else {
|
} 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
|
bool
|
||||||
StackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
StackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -362,30 +362,6 @@ js_PutCallObject(js::StackFrame *fp);
|
||||||
|
|
||||||
namespace js {
|
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.
|
* Function extended with reserved slots for use by various kinds of functions.
|
||||||
* Most functions do not have these extensions, but enough are that efficient
|
* 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;
|
JSObject *limitBlock, *limitClone;
|
||||||
if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj()) {
|
if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj()) {
|
||||||
JS_ASSERT_IF(fp->scopeChain().isClonedBlock(), fp->scopeChain().getPrivate() != fp);
|
JS_ASSERT_IF(fp->scopeChain().isClonedBlock(), fp->scopeChain().getPrivate() != fp);
|
||||||
if (!CreateFunCallObject(cx, fp))
|
if (!CallObject::createForFunction(cx, fp))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* We know we must clone everything on blockChain. */
|
/* 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. */
|
/* Give strict mode eval its own fresh lexical environment. */
|
||||||
StackFrame *fp = efg.fp();
|
StackFrame *fp = efg.fp();
|
||||||
if (fp->isStrictEvalFrame() && !CreateEvalCallObject(cx, fp))
|
if (fp->isStrictEvalFrame() && !CallObject::createForStrictEval(cx, fp))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Probes::startExecution(cx, script);
|
Probes::startExecution(cx, script);
|
||||||
|
|
|
@ -98,9 +98,9 @@ Bindings::lookup(JSContext *cx, JSAtom *name, uintN *indexp) const
|
||||||
if (indexp)
|
if (indexp)
|
||||||
*indexp = shape->shortid();
|
*indexp = shape->shortid();
|
||||||
|
|
||||||
if (shape->getter() == GetCallArg)
|
if (shape->getter() == CallObject::getArgOp)
|
||||||
return ARGUMENT;
|
return ARGUMENT;
|
||||||
if (shape->getter() == GetCallUpvar)
|
if (shape->getter() == CallObject::getUpvarOp)
|
||||||
return UPVAR;
|
return UPVAR;
|
||||||
|
|
||||||
return shape->writable() ? VARIABLE : CONSTANT;
|
return shape->writable() ? VARIABLE : CONSTANT;
|
||||||
|
@ -128,13 +128,13 @@ Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
|
||||||
JS_ASSERT(nvars == 0);
|
JS_ASSERT(nvars == 0);
|
||||||
JS_ASSERT(nupvars == 0);
|
JS_ASSERT(nupvars == 0);
|
||||||
indexp = &nargs;
|
indexp = &nargs;
|
||||||
getter = GetCallArg;
|
getter = CallObject::getArgOp;
|
||||||
setter = SetCallArg;
|
setter = CallObject::setArgOp;
|
||||||
slot += nargs;
|
slot += nargs;
|
||||||
} else if (kind == UPVAR) {
|
} else if (kind == UPVAR) {
|
||||||
indexp = &nupvars;
|
indexp = &nupvars;
|
||||||
getter = GetCallUpvar;
|
getter = CallObject::getUpvarOp;
|
||||||
setter = SetCallUpvar;
|
setter = CallObject::setUpvarOp;
|
||||||
slot = lastBinding->maybeSlot();
|
slot = lastBinding->maybeSlot();
|
||||||
attrs |= JSPROP_SHARED;
|
attrs |= JSPROP_SHARED;
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,8 +142,8 @@ Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
|
||||||
JS_ASSERT(nupvars == 0);
|
JS_ASSERT(nupvars == 0);
|
||||||
|
|
||||||
indexp = &nvars;
|
indexp = &nvars;
|
||||||
getter = GetCallVar;
|
getter = CallObject::getVarOp;
|
||||||
setter = SetCallVar;
|
setter = CallObject::setVarOp;
|
||||||
if (kind == CONSTANT)
|
if (kind == CONSTANT)
|
||||||
attrs |= JSPROP_READONLY;
|
attrs |= JSPROP_READONLY;
|
||||||
slot += nargs + nvars;
|
slot += nargs + nvars;
|
||||||
|
@ -248,9 +248,9 @@ Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
|
||||||
const Shape &shape = r.front();
|
const Shape &shape = r.front();
|
||||||
uintN index = uint16_t(shape.shortid());
|
uintN index = uint16_t(shape.shortid());
|
||||||
|
|
||||||
if (shape.getter() == GetCallArg) {
|
if (shape.getter() == CallObject::getArgOp) {
|
||||||
JS_ASSERT(index < nargs);
|
JS_ASSERT(index < nargs);
|
||||||
} else if (shape.getter() == GetCallUpvar) {
|
} else if (shape.getter() == CallObject::getUpvarOp) {
|
||||||
JS_ASSERT(index < nupvars);
|
JS_ASSERT(index < nupvars);
|
||||||
index += nargs + nvars;
|
index += nargs + nvars;
|
||||||
} else {
|
} else {
|
||||||
|
@ -262,7 +262,7 @@ Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
|
||||||
names[index] = JSID_TO_ATOM(shape.propid());
|
names[index] = JSID_TO_ATOM(shape.propid());
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(JSID_IS_INT(shape.propid()));
|
JS_ASSERT(JSID_IS_INT(shape.propid()));
|
||||||
JS_ASSERT(shape.getter() == GetCallArg);
|
JS_ASSERT(shape.getter() == CallObject::getArgOp);
|
||||||
names[index] = NULL;
|
names[index] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ Bindings::lastArgument() const
|
||||||
|
|
||||||
const js::Shape *shape = lastVariable();
|
const js::Shape *shape = lastVariable();
|
||||||
if (nvars > 0) {
|
if (nvars > 0) {
|
||||||
while (shape->previous() && shape->getter() != GetCallArg)
|
while (shape->previous() && shape->getter() != CallObject::getArgOp)
|
||||||
shape = shape->previous();
|
shape = shape->previous();
|
||||||
}
|
}
|
||||||
return shape;
|
return shape;
|
||||||
|
@ -295,7 +295,7 @@ Bindings::lastVariable() const
|
||||||
|
|
||||||
const js::Shape *shape = lastUpvar();
|
const js::Shape *shape = lastUpvar();
|
||||||
if (nupvars > 0) {
|
if (nupvars > 0) {
|
||||||
while (shape->getter() == GetCallUpvar)
|
while (shape->getter() == CallObject::getUpvarOp)
|
||||||
shape = shape->previous();
|
shape = shape->previous();
|
||||||
}
|
}
|
||||||
return shape;
|
return shape;
|
||||||
|
|
|
@ -408,7 +408,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||||
Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg);
|
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::offsetOfFormalArg(fun, slot)
|
||||||
: StackFrame::offsetOfFixed(slot));
|
: StackFrame::offsetOfFixed(slot));
|
||||||
masm.storeValue(pic.u.vr, addr);
|
masm.storeValue(pic.u.vr, addr);
|
||||||
|
@ -417,7 +417,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||||
|
|
||||||
escapedFrame.linkTo(masm.label(), &masm);
|
escapedFrame.linkTo(masm.label(), &masm);
|
||||||
{
|
{
|
||||||
if (shape->setterOp() == SetCallVar)
|
if (shape->setterOp() == CallObject::setVarOp)
|
||||||
slot += fun->nargs;
|
slot += fun->nargs;
|
||||||
|
|
||||||
slot += CallObject::RESERVED_SLOTS;
|
slot += CallObject::RESERVED_SLOTS;
|
||||||
|
@ -655,8 +655,8 @@ class SetPropCompiler : public PICStubCompiler
|
||||||
} else {
|
} else {
|
||||||
if (shape->hasSetterValue())
|
if (shape->hasSetterValue())
|
||||||
return disable("scripted setter");
|
return disable("scripted setter");
|
||||||
if (shape->setterOp() != SetCallArg &&
|
if (shape->setterOp() != CallObject::setArgOp &&
|
||||||
shape->setterOp() != SetCallVar) {
|
shape->setterOp() != CallObject::setVarOp) {
|
||||||
return disable("setter");
|
return disable("setter");
|
||||||
}
|
}
|
||||||
JS_ASSERT(obj->isCall());
|
JS_ASSERT(obj->isCall());
|
||||||
|
@ -679,7 +679,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||||
return error();
|
return error();
|
||||||
{
|
{
|
||||||
types::AutoEnterTypeInference enter(cx);
|
types::AutoEnterTypeInference enter(cx);
|
||||||
if (shape->setterOp() == SetCallArg)
|
if (shape->setterOp() == CallObject::setArgOp)
|
||||||
pic.rhsTypes->addSubset(cx, types::TypeScript::ArgTypes(script, slot));
|
pic.rhsTypes->addSubset(cx, types::TypeScript::ArgTypes(script, slot));
|
||||||
else
|
else
|
||||||
pic.rhsTypes->addSubset(cx, types::TypeScript::LocalTypes(script, slot));
|
pic.rhsTypes->addSubset(cx, types::TypeScript::LocalTypes(script, slot));
|
||||||
|
@ -1548,9 +1548,9 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||||
|
|
||||||
CallObjPropKind kind;
|
CallObjPropKind kind;
|
||||||
const Shape *shape = getprop.shape;
|
const Shape *shape = getprop.shape;
|
||||||
if (shape->getterOp() == GetCallArg) {
|
if (shape->getterOp() == CallObject::getArgOp) {
|
||||||
kind = ARG;
|
kind = ARG;
|
||||||
} else if (shape->getterOp() == GetCallVar) {
|
} else if (shape->getterOp() == CallObject::getVarOp) {
|
||||||
kind = VAR;
|
kind = VAR;
|
||||||
} else {
|
} else {
|
||||||
return disable("unhandled callobj sprop getter");
|
return disable("unhandled callobj sprop getter");
|
||||||
|
|
|
@ -2494,7 +2494,7 @@ static Env *
|
||||||
Frame_GetEnv(JSContext *cx, StackFrame *fp)
|
Frame_GetEnv(JSContext *cx, StackFrame *fp)
|
||||||
{
|
{
|
||||||
assertSameCompartment(cx, fp);
|
assertSameCompartment(cx, fp);
|
||||||
if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj() && !CreateFunCallObject(cx, fp))
|
if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj() && !CallObject::createForFunction(cx, fp))
|
||||||
return NULL;
|
return NULL;
|
||||||
return GetScopeChain(cx, fp);
|
return GetScopeChain(cx, fp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Paul Biggar <pbiggar@mozilla.com> (original author)
|
* 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
|
* 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"),
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
@ -56,6 +57,100 @@
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::types;
|
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
|
* 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.
|
* 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();
|
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 = {
|
Class js::DeclEnvClass = {
|
||||||
js_Object_str,
|
js_Object_str,
|
||||||
JSCLASS_HAS_PRIVATE |
|
JSCLASS_HAS_PRIVATE |
|
||||||
|
|
|
@ -103,7 +103,7 @@ class ScopeObject : public JSObject
|
||||||
* The stack frame for this scope object, if the frame is still active.
|
* The stack frame for this scope object, if the frame is still active.
|
||||||
* Note: these members may not be called for a StaticBlockObject.
|
* Note: these members may not be called for a StaticBlockObject.
|
||||||
*/
|
*/
|
||||||
inline js::StackFrame *maybeStackFrame() const;
|
inline StackFrame *maybeStackFrame() const;
|
||||||
inline void setStackFrame(StackFrame *frame);
|
inline void setStackFrame(StackFrame *frame);
|
||||||
|
|
||||||
/* For jit access. */
|
/* For jit access. */
|
||||||
|
@ -115,11 +115,14 @@ class CallObject : public ScopeObject
|
||||||
static const uint32_t CALLEE_SLOT = 1;
|
static const uint32_t CALLEE_SLOT = 1;
|
||||||
static const uint32_t ARGUMENTS_SLOT = 2;
|
static const uint32_t ARGUMENTS_SLOT = 2;
|
||||||
|
|
||||||
|
static CallObject *
|
||||||
|
create(JSContext *cx, JSScript *script, JSObject &enclosing, JSObject *callee);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const uint32_t RESERVED_SLOTS = 3;
|
static const uint32_t RESERVED_SLOTS = 3;
|
||||||
|
|
||||||
static CallObject *
|
static CallObject *createForFunction(JSContext *cx, StackFrame *fp);
|
||||||
create(JSContext *cx, JSScript *script, JSObject &enclosing, JSObject *callee);
|
static CallObject *createForStrictEval(JSContext *cx, StackFrame *fp);
|
||||||
|
|
||||||
/* True if this is for a strict mode eval frame or for a function call. */
|
/* True if this is for a strict mode eval frame or for a function call. */
|
||||||
inline bool isForEval() const;
|
inline bool isForEval() const;
|
||||||
|
@ -138,28 +141,37 @@ class CallObject : public ScopeObject
|
||||||
* 1. js_PutCallObject is called in a frame which hasArgsObj
|
* 1. js_PutCallObject is called in a frame which hasArgsObj
|
||||||
* 2. the script assigns to 'arguments'
|
* 2. the script assigns to 'arguments'
|
||||||
*/
|
*/
|
||||||
inline const js::Value &arguments() const;
|
inline const Value &arguments() const;
|
||||||
inline void setArguments(const js::Value &v);
|
inline void setArguments(const Value &v);
|
||||||
|
|
||||||
/* Returns the formal argument at the given index. */
|
/* Returns the formal argument at the given index. */
|
||||||
inline const js::Value &arg(uintN i) const;
|
inline const Value &arg(uintN i) const;
|
||||||
inline void setArg(uintN i, const js::Value &v);
|
inline void setArg(uintN i, const Value &v);
|
||||||
inline void initArgUnchecked(uintN i, const js::Value &v);
|
inline void initArgUnchecked(uintN i, const Value &v);
|
||||||
|
|
||||||
/* Returns the variable at the given index. */
|
/* Returns the variable at the given index. */
|
||||||
inline const js::Value &var(uintN i) const;
|
inline const Value &var(uintN i) const;
|
||||||
inline void setVar(uintN i, const js::Value &v);
|
inline void setVar(uintN i, const Value &v);
|
||||||
inline void initVarUnchecked(uintN i, const js::Value &v);
|
inline void initVarUnchecked(uintN i, const Value &v);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the actual arrays of arguments and variables. Only call if type
|
* Get the actual arrays of arguments and variables. Only call if type
|
||||||
* inference is enabled, where we ensure that call object variables are in
|
* inference is enabled, where we ensure that call object variables are in
|
||||||
* contiguous slots (see NewCallObject).
|
* contiguous slots (see NewCallObject).
|
||||||
*/
|
*/
|
||||||
inline js::HeapSlotArray argArray();
|
inline HeapSlotArray argArray();
|
||||||
inline js::HeapSlotArray varArray();
|
inline HeapSlotArray varArray();
|
||||||
|
|
||||||
inline void copyValues(uintN nargs, Value *argv, uintN nvars, Value *slots);
|
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
|
class DeclEnvObject : public ScopeObject
|
||||||
|
@ -220,7 +232,7 @@ class BlockObject : public NestedScopeObject
|
||||||
class StaticBlockObject : public BlockObject
|
class StaticBlockObject : public BlockObject
|
||||||
{
|
{
|
||||||
/* These ScopeObject operations are not valid on a static block object. */
|
/* These ScopeObject operations are not valid on a static block object. */
|
||||||
js::StackFrame *maybeStackFrame() const;
|
StackFrame *maybeStackFrame() const;
|
||||||
void setStackFrame(StackFrame *frame);
|
void setStackFrame(StackFrame *frame);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -239,7 +251,7 @@ class StaticBlockObject : public BlockObject
|
||||||
Definition *maybeDefinitionParseNode(unsigned i);
|
Definition *maybeDefinitionParseNode(unsigned i);
|
||||||
void poisonDefinitionParseNode(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
|
class ClonedBlockObject : public BlockObject
|
||||||
|
|
|
@ -370,7 +370,7 @@ StackFrame::functionPrologue(JSContext *cx)
|
||||||
JSFunction *fun = this->fun();
|
JSFunction *fun = this->fun();
|
||||||
|
|
||||||
if (fun->isHeavyweight()) {
|
if (fun->isHeavyweight()) {
|
||||||
if (!CreateFunCallObject(cx, this))
|
if (!CallObject::createForFunction(cx, this))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
/* Force instantiation of the scope chain, for JIT frames. */
|
/* Force instantiation of the scope chain, for JIT frames. */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче