Bug 729382 - move the rest of the CallObject into ScopeObject (r=waldo)

This commit is contained in:
Luke Wagner 2012-02-23 13:58:39 -08:00
parent 644e9f3621
commit f6301bef27
10 changed files with 391 additions and 410 deletions

View File

@ -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 {

View File

@ -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)
{

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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");

View File

@ -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);
}

View File

@ -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 |

View File

@ -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

View File

@ -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. */