📄 jsfun.c
字号:
call_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, JS_PropertyStub, JS_PropertyStub, call_getProperty, call_setProperty, call_enumerate, (JSResolveOp)call_resolve, call_convert, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS};#endif /* JS_HAS_CALL_OBJECT *//* SHARED because fun_getProperty always computes a new value. */#define FUNCTION_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)static JSPropertySpec function_props[] = { {js_arguments_str, CALL_ARGUMENTS, FUNCTION_PROP_ATTRS,0,0}, {js_arity_str, FUN_ARITY, FUNCTION_PROP_ATTRS,0,0}, {js_length_str, ARGS_LENGTH, FUNCTION_PROP_ATTRS,0,0}, {js_name_str, FUN_NAME, FUNCTION_PROP_ATTRS,0,0}, {js_caller_str, FUN_CALLER, FUNCTION_PROP_ATTRS,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 defined _MSC_VER &&_MSC_VER <= 800 /* MSVC1.5 coredumps */ jsval bogus = *vp;#endif if (!JSVAL_IS_INT(id)) return JS_TRUE; slot = JSVAL_TO_INT(id); /* No valid function object should lack private data, but check anyway. */ fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL); if (!fun) 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:#if JS_HAS_ARGS_OBJECT /* 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;#else /* !JS_HAS_ARGS_OBJECT */ *vp = OBJECT_TO_JSVAL(fp ? obj : NULL); break;#endif /* !JS_HAS_ARGS_OBJECT */ case ARGS_LENGTH: if (!JSVERSION_IS_ECMA(cx->version)) *vp = INT_TO_JSVAL((jsint)(fp && fp->fun ? fp->argc : fun->nargs)); else 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)#if defined _MSC_VER &&_MSC_VER <= 800 /* MSVC1.5 coredumps */ if (bogus == *vp)#endif *vp = fp->argv[slot]; break; } return JS_TRUE;}static JSBoolfun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp){ JSFunction *fun; JSString *str; JSAtom *prototypeAtom; 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; /* No need to reflect fun.prototype in 'fun.prototype = ...'. */ if (flags & JSRESOLVE_ASSIGNING) 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, (jsid)prototypeAtom, &pval)) return JS_FALSE; if (JSVAL_IS_OBJECT(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 == cx->runtime->atomState.ObjectAtom) 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->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); }}struct _SwfdecScript { JSFunction * fun;};extern void swfdec_script_unref (void *script);static voidfun_finalize(JSContext *cx, JSObject *obj){ JSFunction *fun; /* 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; JS_ATOMIC_DECREMENT(&fun->nrefs); if (fun->nrefs) return; if (fun->script) js_DestroyScript(cx, fun->script); if (fun->swf) { ((struct _SwfdecScript *) fun->swf)->fun = NULL; swfdec_script_unref (fun->swf); } JS_free(cx, fun);}#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; JSString *atomstr; char *propname; JSScopeProperty *sprop; uint32 userid; /* NB: holds a signed int-tagged jsval */ JSAtom *atom; uintN i, n, dupflag; uint32 type;#ifdef DEBUG uintN nvars = 0, nargs = 0;#endif cx = xdr->cx; if (xdr->mode == JSXDR_ENCODE) { /* * No valid function object should lack private data, but fail soft * (return true, no error report) in case one does due to API pilot * or internal error. */ fun = (JSFunction *) JS_GetPrivate(cx, *objp); if (!fun) return JS_TRUE; atomstr = fun->atom ? ATOM_TO_STRING(fun->atom) : NULL; } else { fun = js_NewFunction(cx, NULL, NULL, 0, 0, NULL, NULL); if (!fun) return JS_FALSE; atomstr = NULL; } if (!JS_XDRStringOrNull(xdr, &atomstr) || !JS_XDRUint16(xdr, &fun->nargs) || !JS_XDRUint16(xdr, &fun->extra) || !JS_XDRUint16(xdr, &fun->nvars) || !JS_XDRUint8(xdr, &fun->flags)) { return JS_FALSE; } /* do arguments and local vars */ if (fun->object) { n = fun->nargs + fun->nvars; if (xdr->mode == JSXDR_ENCODE) { JSScope *scope; JSScopeProperty **spvec, *auto_spvec[8]; void *mark; if (n <= sizeof auto_spvec / sizeof auto_spvec[0]) { spvec = auto_spvec; mark = NULL; } else { mark = JS_ARENA_MARK(&cx->tempPool); JS_ARENA_ALLOCATE_CAST(spvec, JSScopeProperty **, &cx->tempPool, n * sizeof(JSScopeProperty *)); if (!spvec) { JS_ReportOutOfMemory(cx); return JS_FALSE; } } scope = OBJ_SCOPE(fun->object); for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { if (sprop->getter == js_GetArgument) { JS_ASSERT(nargs++ <= fun->nargs); spvec[sprop->shortid] = sprop; } else if (sprop->getter == js_GetLocalVariable) { JS_ASSERT(nvars++ <= fun->nvars); spvec[fun->nargs + sprop->shortid] = sprop; } } for (i = 0; i < n; i++) { sprop = spvec[i]; JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID); type = (i < fun->nargs) ? JSXDR_FUNARG : (sprop->attrs & JSPROP_READONLY) ? JSXDR_FUNCONST : JSXDR_FUNVAR; userid = INT_TO_JSVAL(sprop->shortid); /* XXX lossy conversion, need new XDR version for ECMAv3 */ propname = JS_GetStringBytes(ATOM_TO_STRING((JSAtom *)sprop->id)); if (!propname || !JS_XDRUint32(xdr, &type) || !JS_XDRUint32(xdr, &userid) || !JS_XDRCString(xdr, &propname)) { if (mark) JS_ARENA_RELEASE(&cx->tempPool, mark); return JS_FALSE; } } if (mark) JS_ARENA_RELEASE(&cx->tempPool, mark); } else { JSPropertyOp getter, setter; for (i = n; i != 0; i--) { uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT; if (!JS_XDRUint32(xdr, &type) || !JS_XDRUint32(xdr, &userid) || !JS_XDRCString(xdr, &propname)) { return JS_FALSE; } JS_ASSERT(type == JSXDR_FUNARG || type == JSXDR_FUNVAR || type == JSXDR_FUNCONST); if (type == JSXDR_FUNARG) { getter = js_GetArgument; setter = js_SetArgument; JS_ASSERT(nargs++ <= fun->nargs); } else if (type == JSXDR_FUNVAR || type == JSXDR_FUNCONST) { getter = js_GetLocalVariable; setter = js_SetLocalVariable; if (type == JSXDR_FUNCONST) attrs |= JSPROP_READONLY; JS_ASSERT(nvars++ <= fun->nvars); } else { getter = NULL; setter = NULL; } atom = js_Atomize(cx, propname, strlen(propname), 0); JS_free(cx, propname); if (!atom) return JS_FALSE; /* Flag duplicate argument if atom is bound in fun->object. */ dupflag = SCOPE_GET_PROPERTY(OBJ_SCOPE(fun->object), (jsid)atom) ? SPROP_IS_DUPLICATE : 0; if (!js_AddNativeProperty(cx, fun->object, (jsid)atom, getter, setter, SPROP_INVALID_SLOT, attrs | JSPROP_SHARED, SPROP_HAS_SHORTID | dupflag, JSVAL_TO_INT(userid))) { return JS_FALSE; } } } } if (!js_XDRScript(xdr, &fun->script, NULL)) return JS_FALSE; if (xdr->mode == JSXDR_DECODE) { *objp = fun->object; if (atomstr) { fun->atom = js_AtomizeString(cx, atomstr, 0); if (!fun->atom) return JS_FALSE; if (!OBJ_DEFINE_PROPERTY(cx, cx->globalObject, (jsid)fun->atom, OBJECT_TO_JSVAL(*objp), NULL, NULL, JSPROP_ENUMERATE, NULL)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -