📄 jsfun.c
字号:
if (fun) return JS_TRUE;#if JS_HAS_CALL_OBJECT /* * NB: (new Function) is not lexically closed by its caller, it's just an * anonymous function in the top-level scope that its constructor inhabits. * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42, * and so would a call to f from another top-level's script or function. * * In older versions, before call objects, a new Function was adopted by * its running context's globalObject, which might be different from the * top-level reachable from scopeChain (in HTML frames, e.g.). */ parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]));#else /* Set up for dynamic parenting (see js_Invoke in jsinterp.c). */ parent = NULL;#endif fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA, parent, JSVERSION_IS_ECMA(cx->version) ? cx->runtime->atomState.anonymousAtom : NULL); if (!fun) return JS_FALSE; /* * Function is static and not called directly by other functions in this * file, therefore it is callable only as a native function by js_Invoke. * Find the scripted caller, possibly skipping other native frames such as * are built for Function.prototype.call or .apply activations that invoke * Function indirectly from a script. */ JS_ASSERT(!fp->script && fp->fun && fp->fun->native == Function); caller = JS_GetScriptedCaller(cx, fp); if (caller) { filename = caller->script->filename; lineno = js_PCToLineNumber(cx, caller->script, caller->pc); principals = JS_EvalFramePrincipals(cx, fp, caller); } else { filename = NULL; lineno = 0; principals = NULL; } n = argc ? argc - 1 : 0; if (n > 0) { /* * Collect the function-argument arguments into one string, separated * by commas, then make a tokenstream from that string, and scan it to * get the arguments. We need to throw the full scanner at the * problem, because the argument string can legitimately contain * comments and linefeeds. XXX It might be better to concatenate * everything up into a function definition and pass it to the * compiler, but doing it this way is less of a delta from the old * code. See ECMA 15.3.2.1. */ args_length = 0; for (i = 0; i < n; i++) { /* Collect the lengths for all the function-argument arguments. */ arg = js_ValueToString(cx, argv[i]); if (!arg) return JS_FALSE; argv[i] = STRING_TO_JSVAL(arg); args_length += JSSTRING_LENGTH(arg); } /* Add 1 for each joining comma. */ args_length += n - 1; /* * Allocate a string to hold the concatenated arguments, including room * for a terminating 0. Mark cx->tempPool for later release, to free * collected_args and its tokenstream in one swoop. */ mark = JS_ARENA_MARK(&cx->tempPool); JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool, (args_length+1) * sizeof(jschar)); if (!cp) return JS_FALSE; collected_args = cp; /* * Concatenate the arguments into the new string, separated by commas. */ for (i = 0; i < n; i++) { arg = JSVAL_TO_STRING(argv[i]); arg_length = JSSTRING_LENGTH(arg); (void) js_strncpy(cp, JSSTRING_CHARS(arg), arg_length); cp += arg_length; /* Add separating comma or terminating 0. */ *cp++ = (i + 1 < n) ? ',' : 0; } /* * Make a tokenstream (allocated from cx->tempPool) that reads from * the given string. */ ts = js_NewTokenStream(cx, collected_args, args_length, filename, lineno, principals); if (!ts) { JS_ARENA_RELEASE(&cx->tempPool, mark); return JS_FALSE; } /* The argument string may be empty or contain no tokens. */ tt = js_GetToken(cx, ts); if (tt != TOK_EOF) { for (;;) { /* * Check that it's a name. This also implicitly guards against * TOK_ERROR, which was already reported. */ if (tt != TOK_NAME) goto bad_formal; /* * Get the atom corresponding to the name from the tokenstream; * we're assured at this point that it's a valid identifier. */ atom = CURRENT_TOKEN(ts).t_atom; if (!js_LookupProperty(cx, obj, (jsid)atom, &obj2, (JSProperty **)&sprop)) { goto bad_formal; } dupflag = 0; if (sprop) { ok = JS_TRUE; if (obj2 == obj) { const char *name = js_AtomToPrintableString(cx, atom); /* * A duplicate parameter name. We force a duplicate * node on the SCOPE_LAST_PROP(scope) list with the * same id, distinguished by the SPROP_IS_DUPLICATE * flag, and not mapped by an entry in scope. */ JS_ASSERT(sprop->getter == js_GetArgument); ok = name && js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_DUPLICATE_FORMAL, name); dupflag = SPROP_IS_DUPLICATE; } OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop); if (!ok) goto bad_formal; sprop = NULL; } if (!js_AddNativeProperty(cx, fun->object, (jsid)atom, js_GetArgument, js_SetArgument, SPROP_INVALID_SLOT, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, SPROP_HAS_SHORTID | dupflag, fun->nargs)) { goto bad_formal; } fun->nargs++; /* * Get the next token. Stop on end of stream. Otherwise * insist on a comma, get another name, and iterate. */ tt = js_GetToken(cx, ts); if (tt == TOK_EOF) break; if (tt != TOK_COMMA) goto bad_formal; tt = js_GetToken(cx, ts); } } /* Clean up. */ ok = js_CloseTokenStream(cx, ts); JS_ARENA_RELEASE(&cx->tempPool, mark); if (!ok) return JS_FALSE; } if (argc) { str = js_ValueToString(cx, argv[argc-1]); } else { /* Can't use cx->runtime->emptyString because we're called too early. */ str = js_NewStringCopyZ(cx, js_empty_ucstr, 0); } if (!str) return JS_FALSE; if (argv) { /* Use the last arg (or this if argc == 0) as a local GC root. */ argv[(intN)(argc-1)] = STRING_TO_JSVAL(str); } mark = JS_ARENA_MARK(&cx->tempPool); ts = js_NewTokenStream(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str), filename, lineno, principals); if (!ts) { ok = JS_FALSE; } else { ok = js_CompileFunctionBody(cx, ts, fun) && js_CloseTokenStream(cx, ts); } JS_ARENA_RELEASE(&cx->tempPool, mark); return ok;bad_formal: /* * Report "malformed formal parameter" iff no illegal char or similar * scanner error was already reported. */ if (!(ts->flags & TSF_ERROR)) JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_FORMAL); /* * Clean up the arguments string and tokenstream if we failed to parse * the arguments. */ (void)js_CloseTokenStream(cx, ts); JS_ARENA_RELEASE(&cx->tempPool, mark); return JS_FALSE;}JSObject *js_InitFunctionClass(JSContext *cx, JSObject *obj){ JSObject *proto; JSAtom *atom; JSFunction *fun; proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1, function_props, function_methods, NULL, NULL); if (!proto) return NULL; atom = js_Atomize(cx, js_FunctionClass.name, strlen(js_FunctionClass.name), 0); if (!atom) goto bad; fun = js_NewFunction(cx, proto, NULL, 0, 0, obj, NULL); if (!fun) goto bad; fun->script = js_NewScript(cx, 0, 0, 0); if (!fun->script) goto bad; return proto;bad: cx->newborn[GCX_OBJECT] = NULL; return NULL;}#if JS_HAS_CALL_OBJECTJSObject *js_InitCallClass(JSContext *cx, JSObject *obj){ return JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0, call_props, NULL, NULL, NULL);}#endifJSFunction *js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, uintN flags, JSObject *parent, JSAtom *atom){ JSFunction *fun; /* Allocate a function struct. */ fun = (JSFunction *) JS_malloc(cx, sizeof *fun); if (!fun) return NULL; /* If funobj is null, allocate an object for it. */ if (funobj) { OBJ_SET_PARENT(cx, funobj, parent); } else { funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent); if (!funobj) { JS_free(cx, fun); return NULL; } } /* Initialize all function members. */ fun->nrefs = 0; fun->object = NULL; fun->native = native; fun->script = NULL; fun->swf = NULL; fun->nargs = nargs; fun->extra = 0; fun->nvars = 0; fun->flags = flags & JSFUN_FLAGS_MASK; fun->spare = 0; fun->atom = atom; fun->clasp = NULL; /* Link fun to funobj and vice versa. */ if (!js_LinkFunctionObject(cx, fun, funobj)) { cx->newborn[GCX_OBJECT] = NULL; JS_free(cx, fun); return NULL; } return fun;}JSObject *js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent){ JSObject *newfunobj; JSFunction *fun; JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass); newfunobj = js_NewObject(cx, &js_FunctionClass, funobj, parent); if (!newfunobj) return NULL; fun = (JSFunction *) JS_GetPrivate(cx, funobj); if (!js_LinkFunctionObject(cx, fun, newfunobj)) { cx->newborn[GCX_OBJECT] = NULL; return NULL; } return newfunobj;}JSBooljs_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *funobj){ if (!fun->object) fun->object = funobj; if (!JS_SetPrivate(cx, funobj, fun)) return JS_FALSE; JS_ATOMIC_INCREMENT(&fun->nrefs); return JS_TRUE;}JSFunction *js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native, uintN nargs, uintN attrs){ JSFunction *fun; fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom); if (!fun) return NULL; if (!OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, OBJECT_TO_JSVAL(fun->object), NULL, NULL, attrs & ~JSFUN_FLAGS_MASK, NULL)) { return NULL; } return fun;}#if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)# error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"#endifJSFunction *js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags){ jsval v; JSObject *obj; v = *vp; obj = NULL; if (JSVAL_IS_OBJECT(v)) { obj = JSVAL_TO_OBJECT(v); if (obj && OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) { if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &v)) return NULL; obj = JSVAL_IS_FUNCTION(cx, v) ? JSVAL_TO_OBJECT(v) : NULL; } } if (!obj) { js_ReportIsNotFunction(cx, vp, flags); return NULL; } return (JSFunction *) JS_GetPrivate(cx, obj);}voidjs_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags){ JSType type; JSString *fallback; JSString *str; /* * We provide the typename as the fallback to handle the case when * valueOf is not a function, which prevents ValueToString from being * called as the default case inside js_DecompileValueGenerator (and * so recursing back to here). */ type = JS_TypeOfValue(cx, *vp); fallback = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]); str = js_DecompileValueGenerator(cx, (flags & JSV2F_SEARCH_STACK) ? JSDVG_SEARCH_STACK : cx->fp ? vp - cx->fp->sp : JSDVG_IGNORE_STACK, *vp, fallback); if (str) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, (uintN)((flags & JSV2F_CONSTRUCT) ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION), JS_GetStringBytes(str)); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -