📄 jsfun.c
字号:
uint32 nullAtom; /* flag to indicate if fun->atom is NULL */ JSTempValueRooter tvr; uint32 flagsword; /* originally only flags was JS_XDRUint8'd */ uint16 extraUnused; /* variable for no longer used field */ JSAtom *propAtom; JSScopeProperty *sprop; uint32 userid; /* NB: holds a signed int-tagged jsval */ uintN i, n, dupflag; uint32 type; JSBool ok;#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; if (!FUN_INTERPRETED(fun)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION, JS_GetFunctionName(fun)); return JS_FALSE; } nullAtom = !fun->atom; flagsword = ((uint32)fun->u.i.nregexps << 16) | fun->flags; extraUnused = 0; } else { fun = js_NewFunction(cx, NULL, NULL, 0, 0, NULL, NULL); if (!fun) return JS_FALSE; } /* From here on, control flow must flow through label out. */ JS_PUSH_TEMP_ROOT_OBJECT(cx, fun->object, &tvr); ok = JS_TRUE; if (!JS_XDRUint32(xdr, &nullAtom)) goto bad; if (!nullAtom && !js_XDRStringAtom(xdr, &fun->atom)) goto bad; if (!JS_XDRUint16(xdr, &fun->nargs) || !JS_XDRUint16(xdr, &extraUnused) || !JS_XDRUint16(xdr, &fun->u.i.nvars) || !JS_XDRUint32(xdr, &flagsword)) { goto bad; } /* Assert that all previous writes of extraUnused were writes of 0. */ JS_ASSERT(extraUnused == 0); /* do arguments and local vars */ if (fun->object) { n = fun->nargs + fun->u.i.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); goto bad; } } 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->u.i.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); propAtom = JSID_TO_ATOM(sprop->id); if (!JS_XDRUint32(xdr, &type) || !JS_XDRUint32(xdr, &userid) || !js_XDRCStringAtom(xdr, &propAtom)) { if (mark) JS_ARENA_RELEASE(&cx->tempPool, mark); goto bad; } } if (mark) JS_ARENA_RELEASE(&cx->tempPool, mark); } else { JSPropertyOp getter, setter; for (i = n; i != 0; i--) { uintN attrs = JSPROP_PERMANENT; if (!JS_XDRUint32(xdr, &type) || !JS_XDRUint32(xdr, &userid) || !js_XDRCStringAtom(xdr, &propAtom)) { goto bad; } 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->u.i.nvars); } else { getter = NULL; setter = NULL; } /* Flag duplicate argument if atom is bound in fun->object. */ dupflag = SCOPE_GET_PROPERTY(OBJ_SCOPE(fun->object), ATOM_TO_JSID(propAtom)) ? SPROP_IS_DUPLICATE : 0; if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(propAtom), getter, setter, SPROP_INVALID_SLOT, attrs | JSPROP_SHARED, dupflag | SPROP_HAS_SHORTID, JSVAL_TO_INT(userid))) { goto bad; } } } } if (!js_XDRScript(xdr, &fun->u.i.script, NULL)) goto bad; if (xdr->mode == JSXDR_DECODE) { fun->flags = (uint16) flagsword | JSFUN_INTERPRETED; fun->u.i.nregexps = (uint16) (flagsword >> 16); *objp = fun->object; js_CallNewScriptHook(cx, fun->u.i.script, fun); }out: JS_POP_TEMP_ROOT(cx, &tvr); return ok;bad: ok = JS_FALSE; goto out;}#else /* !JS_HAS_XDR */#define fun_xdrObject NULL#endif /* !JS_HAS_XDR *//* * [[HasInstance]] internal method for Function objects: fetch the .prototype * property of its 'this' parameter, and walks the prototype chain of v (only * if v is an object) returning true if .prototype is found. */static JSBoolfun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp){ jsval pval; JSString *str; if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(cx->runtime->atomState .classPrototypeAtom), &pval)) { return JS_FALSE; } if (JSVAL_IS_PRIMITIVE(pval)) { /* * Throw a runtime error if instanceof is called on a function that * has a non-object as its .prototype value. */ str = js_DecompileValueGenerator(cx, -1, OBJECT_TO_JSVAL(obj), NULL); if (str) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, JS_GetStringBytes(str)); } return JS_FALSE; } return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp);}static uint32fun_mark(JSContext *cx, JSObject *obj, void *arg){ JSFunction *fun; fun = (JSFunction *) JS_GetPrivate(cx, obj); if (fun) { GC_MARK(cx, fun, "private"); if (fun->atom) GC_MARK_ATOM(cx, fun->atom); if (FUN_INTERPRETED(fun) && fun->u.i.script) js_MarkScript(cx, fun->u.i.script); } return 0;}static uint32fun_reserveSlots(JSContext *cx, JSObject *obj){ JSFunction *fun; fun = (JSFunction *) JS_GetPrivate(cx, obj); return (fun && FUN_INTERPRETED(fun)) ? fun->u.i.nregexps : 0;}/* * Reserve two slots in all function objects for XPConnect. Note that this * does not bloat every instance, only those on which reserved slots are set, * and those on which ad-hoc properties are defined. */JS_FRIEND_DATA(JSClass) js_FunctionClass = { js_Function_str, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_HAS_CACHED_PROTO(JSProto_Function), JS_PropertyStub, JS_PropertyStub, fun_getProperty, JS_PropertyStub, fun_enumerate, (JSResolveOp)fun_resolve, fun_convert, fun_finalize, NULL, NULL, NULL, NULL, fun_xdrObject, fun_hasInstance, fun_mark, fun_reserveSlots};JSBooljs_fun_toString(JSContext *cx, JSObject *obj, uint32 indent, uintN argc, jsval *argv, jsval *rval){ jsval fval; JSFunction *fun; JSString *str; if (!argv) { JS_ASSERT(JS_ObjectIsFunction(cx, obj)); } else { fval = argv[-1]; if (!VALUE_IS_FUNCTION(cx, fval)) { /* * If we don't have a function to start off with, try converting * the object to a function. If that doesn't work, complain. */ if (JSVAL_IS_OBJECT(fval)) { obj = JSVAL_TO_OBJECT(fval); if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, JSTYPE_FUNCTION, &fval)) { return JS_FALSE; } argv[-1] = fval; } if (!VALUE_IS_FUNCTION(cx, fval)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, js_Function_str, js_toString_str, JS_GetTypeName(cx, JS_TypeOfValue(cx, fval))); return JS_FALSE; } } obj = JSVAL_TO_OBJECT(fval); } fun = (JSFunction *) JS_GetPrivate(cx, obj); if (!fun) return JS_TRUE; if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent)) return JS_FALSE; str = JS_DecompileFunction(cx, fun, (uintN)indent); if (!str) return JS_FALSE; *rval = STRING_TO_JSVAL(str); return JS_TRUE;}static JSBoolfun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ return js_fun_toString(cx, obj, 0, argc, argv, rval);}#if JS_HAS_TOSOURCEstatic JSBoolfun_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ return js_fun_toString(cx, obj, JS_DONT_PRETTY_PRINT, argc, argv, rval);}#endifstatic const char call_str[] = "call";static JSBoolfun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsval fval, *sp, *oldsp; JSString *str; void *mark; uintN i; JSStackFrame *fp; JSBool ok; if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1])) return JS_FALSE; fval = argv[-1]; if (!VALUE_IS_FUNCTION(cx, fval)) { str = JS_ValueToString(cx, fval); if (str) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, js_Function_str, call_str, JS_GetStringBytes(str)); } return JS_FALSE; } if (argc == 0) { /* Call fun with its global object as the 'this' param if no args. */ obj = NULL; } else { /* Otherwise convert the first arg to 'this' and skip over it. */ if (!js_ValueToObject(cx, argv[0], &obj)) return JS_FALSE; argc--; argv++; } /* Allocate stack space for fval, obj, and the args. */ sp = js_AllocStack(cx, 2 + argc, &mark); if (!sp) return JS_FALSE; /* Push fval, obj, and the args. */ *sp++ = fval; *sp++ = OBJECT_TO_JSVAL(obj); for (i = 0; i < argc; i++) *sp++ = argv[i]; /* Lift current frame to include the args and do the call. */ fp = cx->fp; oldsp = fp->sp; fp->sp = sp; ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER); /* Store rval and pop stack back to our frame's sp. */ *rval = fp->sp[-1]; fp->sp = oldsp; js_FreeStack(cx, mark); return ok;}static JSBoolfun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsval fval, *sp, *oldsp; JSString *str; JSObject *aobj; jsuint length; JSBool arraylike, ok; void *mark; uintN i; JSStackFrame *fp; if (argc == 0) { /* Will get globalObject as 'this' and no other arguments. */ return fun_call(cx, obj, argc, argv, rval); } if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1])) return JS_FALSE; fval = argv[-1]; if (!VALUE_IS_FUNCTION(cx, fval)) { str = JS_ValueToString(cx, fval); if (str) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -