📄 jsfun.c
字号:
if (slot < JS_MAX(fp->argc, fp->fun->nargs) &&
!ArgWasDeleted(cx, fp, slot)) {
/* XXX ECMA specs DontEnum, contrary to other array-like objects */
if (!js_DefineProperty(cx, obj, (jsid) id, fp->argv[slot],
args_getProperty, args_setProperty,
JSVERSION_IS_ECMA(cx->version)
? 0
: JSPROP_ENUMERATE,
NULL)) {
return JS_FALSE;
}
*objp = obj;
}
} else {
str = JSVAL_TO_STRING(id);
atom = cx->runtime->atomState.lengthAtom;
if (str == ATOM_TO_STRING(atom)) {
tinyid = ARGS_LENGTH;
value = INT_TO_JSVAL(fp->argc);
} else {
atom = cx->runtime->atomState.calleeAtom;
if (str == ATOM_TO_STRING(atom)) {
tinyid = ARGS_CALLEE;
value = fp->argv ? fp->argv[-2]
: OBJECT_TO_JSVAL(fp->fun->object);
} else {
atom = NULL;
/* Quell GCC overwarnings. */
tinyid = 0;
value = JSVAL_NULL;
}
}
if (atom && !TEST_OVERRIDE_BIT(fp, tinyid)) {
if (!js_DefineNativeProperty(cx, obj, (jsid) atom, value,
args_getProperty, args_setProperty, 0,
SPROP_HAS_SHORTID, tinyid, NULL)) {
return JS_FALSE;
}
*objp = obj;
}
}
return JS_TRUE;
}
static JSBool
args_enumerate(JSContext *cx, JSObject *obj)
{
JSStackFrame *fp;
JSObject *pobj;
JSProperty *prop;
uintN slot, nargs;
fp = (JSStackFrame *)
JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
if (!fp)
return JS_TRUE;
JS_ASSERT(fp->argsobj);
JS_ASSERT(fp->fun);
/*
* Trigger reflection with value snapshot in args_resolve using a series
* of js_LookupProperty calls. We handle length, callee, and the indexed
* argument properties. We know that args_resolve covers all these cases
* and creates direct properties of obj, but that it may fail to resolve
* length or callee if overridden.
*/
if (!js_LookupProperty(cx, obj, (jsid) cx->runtime->atomState.lengthAtom,
&pobj, &prop)) {
return JS_FALSE;
}
if (prop)
OBJ_DROP_PROPERTY(cx, pobj, prop);
if (!js_LookupProperty(cx, obj, (jsid) cx->runtime->atomState.calleeAtom,
&pobj, &prop)) {
return JS_FALSE;
}
if (prop)
OBJ_DROP_PROPERTY(cx, pobj, prop);
nargs = JS_MAX(fp->argc, fp->fun->nargs);
for (slot = 0; slot < nargs; slot++) {
if (!js_LookupProperty(cx, obj, (jsid) INT_TO_JSVAL((jsint)slot),
&pobj, &prop)) {
return JS_FALSE;
}
if (prop)
OBJ_DROP_PROPERTY(cx, pobj, prop);
}
return JS_TRUE;
}
/*
* The Arguments class is not initialized via JS_InitClass, and must not be,
* because its name is "Object". Per ECMA, that causes instances of it to
* delegate to the object named by Object.prototype. It also ensures that
* arguments.toString() returns "[object Object]".
*
* The JSClass functions below collaborate to lazily reflect and synchronize
* actual argument values, argument count, and callee function object stored
* in a JSStackFrame with their corresponding property values in the frame's
* arguments object.
*/
JSClass js_ArgumentsClass = {
js_Object_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1),
JS_PropertyStub, args_delProperty,
args_getProperty, args_setProperty,
args_enumerate, (JSResolveOp) args_resolve,
JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
#endif /* JS_HAS_ARGS_OBJECT */
#if JS_HAS_CALL_OBJECT
JSObject *
js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)
{
JSObject *callobj, *funobj;
/* Create a call object for fp only if it lacks one. */
JS_ASSERT(fp->fun);
callobj = fp->callobj;
if (callobj)
return callobj;
JS_ASSERT(fp->fun);
/* The default call parent is its function's parent (static link). */
if (!parent) {
funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object;
if (funobj)
parent = OBJ_GET_PARENT(cx, funobj);
}
/* Create the call object and link it to its stack frame. */
callobj = js_NewObject(cx, &js_CallClass, NULL, parent);
if (!callobj || !JS_SetPrivate(cx, callobj, fp)) {
cx->newborn[GCX_OBJECT] = NULL;
return NULL;
}
fp->callobj = callobj;
/* Make callobj be the scope chain and the variables object. */
fp->scopeChain = callobj;
fp->varobj = callobj;
return callobj;
}
static JSBool
call_enumerate(JSContext *cx, JSObject *obj);
JSBool
js_PutCallObject(JSContext *cx, JSStackFrame *fp)
{
JSObject *callobj;
JSBool ok;
jsid argsid;
jsval aval;
/*
* Reuse call_enumerate here to reflect all actual args and vars into the
* call object from fp.
*/
callobj = fp->callobj;
if (!callobj)
return JS_TRUE;
ok = call_enumerate(cx, callobj);
/*
* Get the arguments object to snapshot fp's actual argument values.
*/
if (fp->argsobj) {
argsid = (jsid) cx->runtime->atomState.argumentsAtom;
ok &= js_GetProperty(cx, callobj, argsid, &aval);
ok &= js_SetProperty(cx, callobj, argsid, &aval);
ok &= js_PutArgsObject(cx, fp);
}
/*
* Clear the private pointer to fp, which is about to go away (js_Invoke).
* Do this last because the call_enumerate and js_GetProperty calls above
* need to follow the private slot to find fp.
*/
ok &= JS_SetPrivate(cx, callobj, NULL);
fp->callobj = NULL;
return ok;
}
static JSPropertySpec call_props[] = {
{js_arguments_str, CALL_ARGUMENTS, JSPROP_PERMANENT,0,0},
{"__callee__", CALL_CALLEE, 0,0,0},
{0,0,0,0,0}
};
static JSBool
call_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JSStackFrame *fp;
jsint slot;
if (!JSVAL_IS_INT(id))
return JS_TRUE;
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (!fp)
return JS_TRUE;
JS_ASSERT(fp->fun);
slot = JSVAL_TO_INT(id);
switch (slot) {
case CALL_ARGUMENTS:
if (!TEST_OVERRIDE_BIT(fp, slot)) {
JSObject *argsobj = js_GetArgsObject(cx, fp);
if (!argsobj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(argsobj);
}
break;
case CALL_CALLEE:
if (!TEST_OVERRIDE_BIT(fp, slot))
*vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
break;
default:
if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs))
*vp = fp->argv[slot];
break;
}
return JS_TRUE;
}
static JSBool
call_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JSStackFrame *fp;
jsint slot;
if (!JSVAL_IS_INT(id))
return JS_TRUE;
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (!fp)
return JS_TRUE;
JS_ASSERT(fp->fun);
slot = JSVAL_TO_INT(id);
switch (slot) {
case CALL_ARGUMENTS:
case CALL_CALLEE:
SET_OVERRIDE_BIT(fp, slot);
break;
default:
if ((uintN)slot < JS_MAX(fp->argc, fp->fun->nargs))
fp->argv[slot] = *vp;
break;
}
return JS_TRUE;
}
JSBool
js_GetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JSStackFrame *fp;
JS_ASSERT(JSVAL_IS_INT(id));
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (fp) {
/* XXX no jsint slot commoning here to avoid MSVC1.52 crashes */
if ((uintN)JSVAL_TO_INT(id) < fp->nvars)
*vp = fp->vars[JSVAL_TO_INT(id)];
}
return JS_TRUE;
}
JSBool
js_SetCallVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JSStackFrame *fp;
JS_ASSERT(JSVAL_IS_INT(id));
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (fp) {
/* XXX jsint slot is block-local here to avoid MSVC1.52 crashes */
jsint slot = JSVAL_TO_INT(id);
if ((uintN)slot < fp->nvars)
fp->vars[slot] = *vp;
}
return JS_TRUE;
}
static JSBool
call_enumerate(JSContext *cx, JSObject *obj)
{
JSStackFrame *fp;
JSObject *funobj;
JSScope *scope;
JSScopeProperty *sprop, *cprop;
JSPropertyOp getter;
jsval *vec;
JSProperty *prop;
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (!fp)
return JS_TRUE;
/*
* Do not enumerate a cloned function object at fp->argv[-2], it may have
* gained its own (mutable) scope (e.g., a brutally-shared XUL script sets
* the clone's prototype property). We must enumerate the function object
* that was decorated with parameter and local variable properties by the
* compiler when the compiler created fp->fun, namely fp->fun->object.
*
* Contrast with call_resolve, where we prefer fp->argv[-2], because we'll
* use js_LookupProperty to find any overridden properties in that object,
* if it was a mutated clone; and if not, we will search its prototype,
* fp->fun->object, to find compiler-created params and locals.
*/
funobj = fp->fun->object;
if (!funobj)
return JS_TRUE;
/*
* Reflect actual args from fp->argv for formal parameters, and local vars
* and functions in fp->vars for declared variables and nested-at-top-level
* local functions.
*/
scope = OBJ_SCOPE(funobj);
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
getter = sprop->getter;
if (getter == js_GetArgument)
vec = fp->argv;
else if (getter == js_GetLocalVariable)
vec = fp->vars;
else
continue;
/* Trigger reflection in call_resolve by doing a lookup. */
if (!js_LookupProperty(cx, obj, sprop->id, &obj, &prop))
return JS_FALSE;
JS_ASSERT(obj && prop);
cprop = (JSScopeProperty *)prop;
LOCKED_OBJ_SET_SLOT(obj, cprop->slot, vec[sprop->shortid]);
OBJ_DROP_PROPERTY(cx, obj, prop);
}
return JS_TRUE;
}
static JSBool
call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSObject **objp)
{
JSStackFrame *fp;
JSObject *funobj;
JSString *str;
JSAtom *atom;
JSObject *obj2;
JSScopeProperty *sprop;
jsid propid;
JSPropertyOp getter, setter;
uintN attrs, slot, nslots, spflags;
jsval *vp, value;
intN shortid;
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (!fp)
return JS_TRUE;
JS_ASSERT(fp->fun);
if (!JSVAL_IS_STRING(id))
return JS_TRUE;
funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object;
if (!funobj)
return JS_TRUE;
str = JSVAL_TO_STRING(id);
atom = js_AtomizeString(cx, str, 0);
if (!atom)
return JS_FALSE;
if (!js_LookupProperty(cx, funobj, (jsid)atom, &obj2,
(JSProperty **)&sprop)) {
return JS_FALSE;
}
if (sprop && OBJ_IS_NATIVE(obj2)) {
propid = sprop->id;
getter = sprop->getter;
attrs = sprop->attrs & ~JSPROP_SHARED;
slot = (uintN) sprop->shortid;
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
if (getter == js_GetArgument || getter == js_GetLocalVariable) {
if (getter == js_GetArgument) {
vp = fp->argv;
nslots = JS_MAX(fp->argc, fp->fun->nargs);
getter = setter = NULL;
} else {
vp = fp->vars;
nslots = fp->nvars;
getter = js_GetCallVariable;
setter = js_SetCallVariable;
}
if (slot < nslots) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -