📄 jsfun.c
字号:
/* * If we found the property in a different object, don't try sticking * it into wrong slots vector. This can occur because we have a mutable * __proto__ slot, and cloned function objects rely on their __proto__ * to delegate to the object that contains the var and arg properties. */ if (!prop || pobj != obj) { if (prop) OBJ_DROP_PROPERTY(cx, pobj, prop); continue; } cprop = (JSScopeProperty *)prop; LOCKED_OBJ_SET_SLOT(obj, cprop->slot, vec[(uint16) sprop->shortid]); OBJ_DROP_PROPERTY(cx, obj, prop); } return JS_TRUE;}static JSBoolcall_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp){ JSStackFrame *fp; JSObject *funobj; JSString *str; JSAtom *atom; JSObject *obj2; JSProperty *prop; JSScopeProperty *sprop; 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; JS_ASSERT((JSFunction *) JS_GetPrivate(cx, funobj) == fp->fun); str = JSVAL_TO_STRING(id); atom = js_AtomizeString(cx, str, 0); if (!atom) return JS_FALSE; if (!js_LookupHiddenProperty(cx, funobj, ATOM_TO_JSID(atom), &obj2, &prop)) return JS_FALSE; if (prop) { if (!OBJ_IS_NATIVE(obj2)) { OBJ_DROP_PROPERTY(cx, obj2, prop); return JS_TRUE; } sprop = (JSScopeProperty *) prop; getter = sprop->getter; attrs = sprop->attrs & ~JSPROP_SHARED; slot = (uintN) sprop->shortid; OBJ_DROP_PROPERTY(cx, obj2, prop); /* Ensure we found an arg or var property for the same function. */ if ((sprop->flags & SPROP_IS_HIDDEN) && (obj2 == funobj || (JSFunction *) JS_GetPrivate(cx, obj2) == fp->fun)) { if (getter == js_GetArgument) { vp = fp->argv; nslots = JS_MAX(fp->argc, fp->fun->nargs); getter = setter = NULL; } else { JS_ASSERT(getter == js_GetLocalVariable); vp = fp->vars; nslots = fp->nvars; getter = js_GetCallVariable; setter = js_SetCallVariable; } if (slot < nslots) { value = vp[slot]; spflags = SPROP_HAS_SHORTID; shortid = (intN) slot; } else { value = JSVAL_VOID; spflags = 0; shortid = 0; } if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs, spflags, shortid, NULL)) { return JS_FALSE; } *objp = obj; } } return JS_TRUE;}static JSBoolcall_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp){ JSStackFrame *fp; if (type == JSTYPE_FUNCTION) { fp = (JSStackFrame *) JS_GetPrivate(cx, obj); if (fp) { JS_ASSERT(fp->fun); *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object); } } return JS_TRUE;}JSClass js_CallClass = { js_Call_str, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_CACHED_PROTO(JSProto_Call), JS_PropertyStub, JS_PropertyStub, call_getProperty, call_setProperty, call_enumerate, (JSResolveOp)call_resolve, call_convert, JS_FinalizeStub, NULL, NULL, NULL, NULL, NULL, NULL, args_or_call_mark, NULL,};/* * ECMA-262 specifies that length is a property of function object instances, * but we can avoid that space cost by delegating to a prototype property that * is JSPROP_PERMANENT and JSPROP_SHARED. Each fun_getProperty call computes * a fresh length value based on the arity of the individual function object's * private data. * * The extensions below other than length, i.e., the ones not in ECMA-262, * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility * with ECMA we must allow a delegating object to override them. */#define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)static JSPropertySpec function_props[] = { {js_arguments_str, CALL_ARGUMENTS, JSPROP_PERMANENT, 0,0}, {js_arity_str, FUN_ARITY, JSPROP_PERMANENT, 0,0}, {js_caller_str, FUN_CALLER, JSPROP_PERMANENT, 0,0}, {js_length_str, ARGS_LENGTH, LENGTH_PROP_ATTRS, 0,0}, {js_name_str, FUN_NAME, JSPROP_PERMANENT, 0,0}, {0,0,0,0,0}};static JSBoolfun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ jsint slot; JSFunction *fun; JSStackFrame *fp; if (!JSVAL_IS_INT(id)) return JS_TRUE; slot = JSVAL_TO_INT(id); /* * Loop because getter and setter can be delegated from another class, * but loop only for ARGS_LENGTH because we must pretend that f.length * is in each function instance f, per ECMA-262, instead of only in the * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED * to make it appear so). * * This code couples tightly to the attributes for the function_props[] * initializers above, and to js_SetProperty and js_HasOwnPropertyHelper. * * It's important to allow delegating objects, even though they inherit * this getter (fun_getProperty), to override arguments, arity, caller, * and name. If we didn't return early for slot != ARGS_LENGTH, we would * clobber *vp with the native property value, instead of letting script * override that value in delegating objects. * * Note how that clobbering is what simulates JSPROP_READONLY for all of * the non-standard properties when the directly addressed object (obj) * is a function object (i.e., when this loop does not iterate). */ while (!(fun = (JSFunction *) JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) { if (slot != ARGS_LENGTH) return JS_TRUE; obj = OBJ_GET_PROTO(cx, obj); if (!obj) return JS_TRUE; } /* Find fun's top-most activation record. */ for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL)); fp = fp->down) { continue; } switch (slot) { case CALL_ARGUMENTS: /* Warn if strict about f.arguments or equivalent unqualified uses. */ if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT, js_GetErrorMessage, NULL, JSMSG_DEPRECATED_USAGE, js_arguments_str)) { return JS_FALSE; } if (fp) { if (!js_GetArgsValue(cx, fp, vp)) return JS_FALSE; } else { *vp = JSVAL_NULL; } break; case ARGS_LENGTH: case FUN_ARITY: *vp = INT_TO_JSVAL((jsint)fun->nargs); break; case FUN_NAME: *vp = fun->atom ? ATOM_KEY(fun->atom) : STRING_TO_JSVAL(cx->runtime->emptyString); break; case FUN_CALLER: while (fp && (fp->flags & JSFRAME_SKIP_CALLER) && fp->down) fp = fp->down; if (fp && fp->down && fp->down->fun && fp->down->argv) *vp = fp->down->argv[-2]; else *vp = JSVAL_NULL; if (!JSVAL_IS_PRIMITIVE(*vp) && cx->runtime->checkObjectAccess) { id = ATOM_KEY(cx->runtime->atomState.callerAtom); if (!cx->runtime->checkObjectAccess(cx, obj, id, JSACC_READ, vp)) return JS_FALSE; } break; default: /* XXX fun[0] and fun.arguments[0] are equivalent. */ if (fp && fp->fun && (uintN)slot < fp->fun->nargs) *vp = fp->argv[slot]; break; } return JS_TRUE;}static JSBoolfun_enumerate(JSContext *cx, JSObject *obj){ jsid prototypeId; JSObject *pobj; JSProperty *prop; prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); if (!OBJ_LOOKUP_PROPERTY(cx, obj, prototypeId, &pobj, &prop)) return JS_FALSE; if (prop) OBJ_DROP_PROPERTY(cx, pobj, prop); return JS_TRUE;}static JSBoolfun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp){ JSFunction *fun; JSString *str; JSAtom *prototypeAtom; /* * No need to reflect fun.prototype in 'fun.prototype = ...' or in an * unqualified reference to prototype, which the emitter looks up as a * hidden atom when attempting to bind to a formal parameter or local * variable slot. */ if (flags & (JSRESOLVE_ASSIGNING | JSRESOLVE_HIDDEN)) return JS_TRUE; if (!JSVAL_IS_STRING(id)) return JS_TRUE; /* No valid function object should lack private data, but check anyway. */ fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL); if (!fun || !fun->object) return JS_TRUE; /* * Ok, check whether id is 'prototype' and bootstrap the function object's * prototype property. */ str = JSVAL_TO_STRING(id); prototypeAtom = cx->runtime->atomState.classPrototypeAtom; if (str == ATOM_TO_STRING(prototypeAtom)) { JSObject *proto, *parentProto; jsval pval; proto = parentProto = NULL; if (fun->object != obj && fun->object) { /* * Clone of a function: make its prototype property value have the * same class as the clone-parent's prototype. */ if (!OBJ_GET_PROPERTY(cx, fun->object, ATOM_TO_JSID(prototypeAtom), &pval)) { return JS_FALSE; } if (!JSVAL_IS_PRIMITIVE(pval)) { /* * We are about to allocate a new object, so hack the newborn * root until then to protect pval in case it is figuratively * up in the air, with no strong refs protecting it. */ cx->weakRoots.newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(pval); parentProto = JSVAL_TO_OBJECT(pval); } } /* * Beware of the wacky case of a user function named Object -- trying * to find a prototype for that will recur back here _ad perniciem_. */ if (!parentProto && fun->atom == CLASS_ATOM(cx, Object)) return JS_TRUE; /* * If resolving "prototype" in a clone, clone the parent's prototype. * Pass the constructor's (obj's) parent as the prototype parent, to * avoid defaulting to parentProto.constructor.__parent__. */ proto = js_NewObject(cx, &js_ObjectClass, parentProto, OBJ_GET_PARENT(cx, obj)); if (!proto) return JS_FALSE; /* * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for * user-defined functions, but DontEnum | ReadOnly | DontDelete for * native "system" constructors such as Object or Function. So lazily * set the former here in fun_resolve, but eagerly define the latter * in JS_InitClass, with the right attributes. */ if (!js_SetClassPrototype(cx, obj, proto, JSPROP_ENUMERATE | JSPROP_PERMANENT)) { cx->weakRoots.newborn[GCX_OBJECT] = NULL; return JS_FALSE; } *objp = obj; } return JS_TRUE;}static JSBoolfun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp){ switch (type) { case JSTYPE_FUNCTION: *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; default: return js_TryValueOf(cx, obj, type, vp); }}static voidfun_finalize(JSContext *cx, JSObject *obj){ JSFunction *fun; JSScript *script; /* No valid function object should lack private data, but check anyway. */ fun = (JSFunction *) JS_GetPrivate(cx, obj); if (!fun) return; if (fun->object == obj) fun->object = NULL; /* Null-check required since the parser sets interpreted very early. */ if (FUN_INTERPRETED(fun) && fun->u.i.script && js_IsAboutToBeFinalized(cx, fun)) { script = fun->u.i.script; fun->u.i.script = NULL; js_DestroyScript(cx, script); }}#if JS_HAS_XDR#include "jsxdrapi.h"enum { JSXDR_FUNARG = 1, JSXDR_FUNVAR = 2, JSXDR_FUNCONST = 3};/* XXX store parent and proto, if defined */static JSBoolfun_xdrObject(JSXDRState *xdr, JSObject **objp){ JSContext *cx; JSFunction *fun;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -