Bug 622053 - Streamline and greatly clarify Call object PropertyOp getters and setters, for easier reading and more bounds-checking assertions than the none (!) we had before. r=dmandelin

This commit is contained in:
Jeff Walden 2010-12-29 22:21:18 -06:00
parent 1fe4d7a5ad
commit 0db837d47a
4 changed files with 143 additions and 97 deletions

View File

@ -1146,138 +1146,102 @@ js_PutCallObjectOnTrace(JSContext *cx, JSObject *callobj, uint32 nargs, Value *a
JS_DEFINE_CALLINFO_6(extern, BOOL, js_PutCallObjectOnTrace, CONTEXT, OBJECT, UINT32, VALUEPTR,
UINT32, VALUEPTR, 0, nanojit::ACCSET_STORE_ANY)
enum JSCallPropertyKind {
JSCPK_ARGUMENTS,
JSCPK_ARG,
JSCPK_VAR,
JSCPK_UPVAR
};
namespace js {
static JSBool
CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
JSCallPropertyKind kind, JSBool setter = false)
GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
JS_ASSERT(obj->isCall());
uintN i = 0;
if (kind != JSCPK_ARGUMENTS) {
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
i = (uint16) JSID_TO_INT(id);
}
Value *array;
if (kind == JSCPK_UPVAR) {
JSObject &callee = obj->getCallObjCallee();
#ifdef DEBUG
JSFunction *calleeFun = callee.getFunctionPrivate();
JS_ASSERT(calleeFun->isFlatClosure());
JS_ASSERT(calleeFun->script()->bindings.countUpvars() == calleeFun->script()->upvars()->length);
JS_ASSERT(i < calleeFun->script()->bindings.countUpvars());
#endif
array = callee.getFlatClosureUpvars();
} else {
JSFunction *fun = obj->getCallObjCalleeFunction();
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
JS_ASSERT_IF(kind == JSCPK_ARG, i < fun->nargs);
JS_ASSERT_IF(kind == JSCPK_VAR, i < fun->script()->bindings.countVars());
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (kind == JSCPK_ARGUMENTS) {
if (setter) {
if (fp)
fp->setOverriddenArgs();
obj->setCallObjArguments(*vp);
} else {
JSStackFrame *fp = obj->maybeCallObjStackFrame();
if (fp && !fp->hasOverriddenArgs()) {
JSObject *argsobj;
argsobj = js_GetArgsObject(cx, fp);
JSObject *argsobj = js_GetArgsObject(cx, fp);
if (!argsobj)
return false;
vp->setObject(*argsobj);
} else {
*vp = obj->getCallObjArguments();
}
}
return true;
}
if (!fp) {
i += JSObject::CALL_RESERVED_SLOTS;
if (kind == JSCPK_VAR)
i += fun->nargs;
else
JS_ASSERT(kind == JSCPK_ARG);
array = obj->getSlots();
} else if (kind == JSCPK_ARG) {
array = fp->formalArgs();
} else {
JS_ASSERT(kind == JSCPK_VAR);
array = fp->slots();
}
}
if (setter) {
GC_POKE(cx, array[i]);
array[i] = *vp;
} else {
*vp = array[i];
}
return true;
}
namespace js {
static JSBool
GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return CallPropertyOp(cx, obj, id, vp, JSCPK_ARGUMENTS);
}
static JSBool
SetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return CallPropertyOp(cx, obj, id, vp, JSCPK_ARGUMENTS, true);
if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
fp->setOverriddenArgs();
obj->setCallObjArguments(*vp);
return true;
}
JSBool
GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG);
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
*vp = fp->formalArg(i);
else
*vp = obj->callObjArg(i);
return true;
}
JSBool
SetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, true);
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
Value *argp;
if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
argp = &fp->formalArg(i);
else
argp = &obj->callObjArg(i);
GC_POKE(cx, *argp);
*argp = *vp;
return true;
}
JSBool
GetFlatUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return CallPropertyOp(cx, obj, id, vp, JSCPK_UPVAR);
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
*vp = obj->getCallObjCallee().getFlatClosureUpvar(i);
return true;
}
JSBool
SetFlatUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return CallPropertyOp(cx, obj, id, vp, JSCPK_UPVAR, true);
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
Value *upvarp = &obj->getCallObjCallee().getFlatClosureUpvar(i);
GC_POKE(cx, *upvarp);
*upvarp = *vp;
return true;
}
JSBool
GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR);
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
*vp = fp->varSlot(i);
else
*vp = obj->callObjVar(i);
return true;
}
JSBool
GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
if (!CallPropertyOp(cx, obj, id, vp, JSCPK_VAR))
if (!GetCallVar(cx, obj, id, vp))
return false;
return CheckForEscapingClosure(cx, obj, vp);
@ -1286,7 +1250,20 @@ GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, Value *vp)
JSBool
SetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, true);
JS_ASSERT(obj->isCall());
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
uintN i = (uint16) JSID_TO_INT(id);
Value *varp;
if (JSStackFrame *fp = obj->maybeCallObjStackFrame())
varp = &fp->varSlot(i);
else
varp = &obj->callObjVar(i);
GC_POKE(cx, *varp);
*varp = *vp;
return true;
}
} // namespace js
@ -1296,7 +1273,7 @@ JSBool JS_FASTCALL
js_SetCallArg(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg)
{
Value argcopy = ValueArgToConstRef(arg);
return CallPropertyOp(cx, obj, slotid, &argcopy, JSCPK_ARG, true);
return SetCallArg(cx, obj, slotid, &argcopy);
}
JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallArg, CONTEXT, OBJECT, JSID, VALUE, 0,
nanojit::ACCSET_STORE_ANY)
@ -1305,7 +1282,7 @@ JSBool JS_FASTCALL
js_SetCallVar(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg)
{
Value argcopy = ValueArgToConstRef(arg);
return CallPropertyOp(cx, obj, slotid, &argcopy, JSCPK_VAR, true);
return SetCallVar(cx, obj, slotid, &argcopy);
}
JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallVar, CONTEXT, OBJECT, JSID, VALUE, 0,
nanojit::ACCSET_STORE_ANY)

View File

@ -250,6 +250,12 @@ struct JSStackFrame
return slots() + script()->nfixed;
}
js::Value &varSlot(uintN i) {
JS_ASSERT(i < script()->nfixed);
JS_ASSERT_IF(maybeFun(), i < script()->bindings.countVars());
return slots()[i];
}
/*
* Script
*

View File

@ -888,6 +888,9 @@ struct JSObject : js::gc::Cell {
/* Number of reserved slots. */
static const uint32 CALL_RESERVED_SLOTS = 2;
/* The stack frame for this Call object, if the frame is still active. */
inline JSStackFrame *maybeCallObjStackFrame() const;
inline JSObject &getCallObjCallee() const;
inline JSFunction *getCallObjCalleeFunction() const;
inline void setCallObjCallee(JSObject &callee);
@ -895,6 +898,14 @@ struct JSObject : js::gc::Cell {
inline const js::Value &getCallObjArguments() const;
inline void setCallObjArguments(const js::Value &v);
/* Returns the formal argument at the given index. */
inline const js::Value &callObjArg(uintN i) const;
inline js::Value &callObjArg(uintN i);
/* Returns the variable at the given index. */
inline const js::Value &callObjVar(uintN i) const;
inline js::Value &callObjVar(uintN i);
/*
* Date-specific getters and setters.
*/
@ -954,6 +965,7 @@ struct JSObject : js::gc::Cell {
inline js::Value *getFlatClosureUpvars() const;
inline js::Value getFlatClosureUpvar(uint32 i) const;
inline js::Value &getFlatClosureUpvar(uint32 i);
inline void setFlatClosureUpvars(js::Value *upvars);
inline bool hasMethodObj(const JSObject& obj) const;

View File

@ -432,6 +432,13 @@ JSObject::setArgsElement(uint32 i, const js::Value &v)
getArgsData()->slots[i] = v;
}
inline JSStackFrame *
JSObject::maybeCallObjStackFrame() const
{
JS_ASSERT(isCall());
return reinterpret_cast<JSStackFrame *>(getPrivate());
}
inline void
JSObject::setCallObjCallee(JSObject &callee)
{
@ -468,6 +475,40 @@ JSObject::setCallObjArguments(const js::Value &v)
setSlot(JSSLOT_CALL_ARGUMENTS, v);
}
inline const js::Value &
JSObject::callObjArg(uintN i) const
{
JS_ASSERT(isCall());
JS_ASSERT(i < getCallObjCalleeFunction()->nargs);
return getSlot(JSObject::CALL_RESERVED_SLOTS + i);
}
inline js::Value &
JSObject::callObjArg(uintN i)
{
JS_ASSERT(isCall());
JS_ASSERT(i < getCallObjCalleeFunction()->nargs);
return getSlotRef(JSObject::CALL_RESERVED_SLOTS + i);
}
inline const js::Value &
JSObject::callObjVar(uintN i) const
{
JSFunction *fun = getCallObjCalleeFunction();
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
JS_ASSERT(i < fun->script()->bindings.countVars());
return getSlot(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i);
}
inline js::Value &
JSObject::callObjVar(uintN i)
{
JSFunction *fun = getCallObjCalleeFunction();
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
JS_ASSERT(i < fun->script()->bindings.countVars());
return getSlotRef(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i);
}
inline const js::Value &
JSObject::getDateUTCTime() const
{
@ -485,8 +526,11 @@ JSObject::setDateUTCTime(const js::Value &time)
inline js::Value *
JSObject::getFlatClosureUpvars() const
{
JS_ASSERT(isFunction());
JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate()));
#ifdef DEBUG
JSFunction *fun = getFunctionPrivate();
JS_ASSERT(fun->isFlatClosure());
JS_ASSERT(fun->script()->bindings.countUpvars() == fun->script()->upvars()->length);
#endif
return (js::Value *) getSlot(JSSLOT_FLAT_CLOSURE_UPVARS).toPrivate();
}
@ -497,6 +541,13 @@ JSObject::getFlatClosureUpvar(uint32 i) const
return getFlatClosureUpvars()[i];
}
inline js::Value &
JSObject::getFlatClosureUpvar(uint32 i)
{
JS_ASSERT(i < getFunctionPrivate()->script()->bindings.countUpvars());
return getFlatClosureUpvars()[i];
}
inline void
JSObject::setFlatClosureUpvars(js::Value *upvars)
{