📄 jsfun.c
字号:
JS_ASSERT(fp->argsobj); slot = JSVAL_TO_INT(id); switch (slot) { case ARGS_CALLEE: case ARGS_LENGTH: SET_OVERRIDE_BIT(fp, slot); break; default: if (FUN_INTERPRETED(fp->fun) && (uintN)slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) { fp->argv[slot] = *vp; } break; } return JS_TRUE;}static JSBoolargs_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp){ JSStackFrame *fp; uintN slot; JSString *str; JSAtom *atom; intN tinyid; jsval value; *objp = NULL; fp = (JSStackFrame *) JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); if (!fp) return JS_TRUE; JS_ASSERT(fp->argsobj); if (JSVAL_IS_INT(id)) { slot = JSVAL_TO_INT(id); if (slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) { /* XXX ECMA specs DontEnum, contrary to other array-like objects */ if (!js_DefineProperty(cx, obj, INT_JSVAL_TO_JSID(id), fp->argv[slot], args_getProperty, args_setProperty, JS_VERSION_IS_ECMA(cx) ? 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, ATOM_TO_JSID(atom), value, args_getProperty, args_setProperty, 0, SPROP_HAS_SHORTID, tinyid, NULL)) { return JS_FALSE; } *objp = obj; } } return JS_TRUE;}static JSBoolargs_enumerate(JSContext *cx, JSObject *obj){ JSStackFrame *fp; JSObject *pobj; JSProperty *prop; uintN slot, argc; fp = (JSStackFrame *) JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); if (!fp) return JS_TRUE; JS_ASSERT(fp->argsobj); /* * 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, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop)) { return JS_FALSE; } if (prop) OBJ_DROP_PROPERTY(cx, pobj, prop); if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop)) { return JS_FALSE; } if (prop) OBJ_DROP_PROPERTY(cx, pobj, prop); argc = fp->argc; for (slot = 0; slot < argc; slot++) { if (!js_LookupProperty(cx, obj, INT_TO_JSID((jsint)slot), &pobj, &prop)) return JS_FALSE; if (prop) OBJ_DROP_PROPERTY(cx, pobj, prop); } return JS_TRUE;}#if JS_HAS_GENERATORS/* * If a generator-iterator's arguments or call object escapes, it needs to * mark its generator object. */static uint32args_or_call_mark(JSContext *cx, JSObject *obj, void *arg){ JSStackFrame *fp; fp = JS_GetPrivate(cx, obj); if (fp && (fp->flags & JSFRAME_GENERATOR)) GC_MARK(cx, FRAME_TO_GENERATOR(fp)->obj, "FRAME_TO_GENERATOR(fp)->obj"); return 0;}#else# define args_or_call_mark NULL#endif/* * 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) | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), JS_PropertyStub, args_delProperty, args_getProperty, args_setProperty, args_enumerate, (JSResolveOp) args_resolve, JS_ConvertStub, JS_FinalizeStub, NULL, NULL, NULL, NULL, NULL, NULL, args_or_call_mark, NULL};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->weakRoots.newborn[GCX_OBJECT] = NULL; return NULL; } fp->callobj = callobj; /* Make callobj be the scope chain and the variables object. */ JS_ASSERT(fp->scopeChain == parent); fp->scopeChain = callobj; fp->varobj = callobj; return callobj;}static JSBoolcall_enumerate(JSContext *cx, JSObject *obj);JSBooljs_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 = ATOM_TO_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 JSBoolcall_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 JSBoolcall_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;}JSBooljs_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;}JSBooljs_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 JSBoolcall_enumerate(JSContext *cx, JSObject *obj){ JSStackFrame *fp; JSObject *funobj, *pobj; JSScope *scope; JSScopeProperty *sprop, *cprop; JSPropertyOp getter; jsval *vec; JSAtom *atom; 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 by looking up the unhidden atom for sprop->id. */ JS_ASSERT(JSID_IS_ATOM(sprop->id)); atom = JSID_TO_ATOM(sprop->id); JS_ASSERT(atom->flags & ATOM_HIDDEN); atom = atom->entry.value; if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop)) return JS_FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -