fp = cx->fp; JS_ASSERT(!fp->script && fp->fun && fp->fun->native == Function); for (;;) { fp = fp->down; if (!fp) { filename = NULL; lineno = 0; principals = NULL; break; } if (fp->script) { filename = fp->script->filename; lineno = js_PCToLineNumber(fp->script, fp->pc); principals = fp->script->principals; break; } }
Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){    JSFunction *fun;    JSObject *parent;    uintN i, n, lineno;    JSAtom *atom;    const char *filename;    JSObject *obj2;    JSScopeProperty *sprop;    JSString *str, *arg;    JSStackFrame *fp;    void *mark;    JSTokenStream *ts;    JSPrincipals *principals;    jschar *collected_args, *cp;    size_t arg_length, args_length;    JSTokenType tt;    jsid oldArgId;    JSBool ok;    if (cx->fp && !(cx->fp->flags & JSFRAME_CONSTRUCTING)) {        obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL);        if (!obj)            return JS_FALSE;        *rval = OBJECT_TO_JSVAL(obj);    }    fun = (JSFunction *) JS_GetPrivate(cx, obj);    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;    if ((fp = cx->fp) != NULL && (fp = fp->down) != NULL && fp->script) {        filename = fp->script->filename;        lineno = js_PCToLineNumber(fp->script, fp->pc);        principals = fp->script->principals;    } 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 = JSVAL_TO_STRING(argv[i]);            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) {            while (1) {                /*                 * 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;                }                if (sprop && obj2 == obj) {                    if (JS_HAS_STRICT_OPTION(cx)) {                        JS_ASSERT(SPROP_GETTER(sprop, obj) == js_GetArgument);                        OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);                        if (!js_ReportCompileErrorNumber(cx, ts, NULL,                                                         JSREPORT_WARNING |                                                         JSREPORT_STRICT,                                                         JSMSG_DUPLICATE_FORMAL,                                                         ATOM_BYTES(atom))) {                            goto bad_formal;                        }                    }                    /*                     * A duplicate parameter name. We create a dummy symbol                     * entry with property id of the parameter number and set                     * the id to the name of the parameter.  See jsopcode.c:                     * the decompiler knows to treat this case specially.                     */                    oldArgId = (jsid) sprop->id;                    OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);                    sprop = NULL;                    if (!js_DefineProperty(cx, obj, oldArgId, JSVAL_VOID,                                           js_GetArgument, js_SetArgument,                                           JSPROP_ENUMERATE | JSPROP_PERMANENT,                                           (JSProperty **)&sprop)) {                        goto bad_formal;                    }                    sprop->id = (jsid) atom;                }                if (sprop)                    OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);                if (!js_DefineProperty(cx, obj, (jsid)atom, JSVAL_VOID,                                       js_GetArgument, js_SetArgument,                                       JSPROP_ENUMERATE | JSPROP_PERMANENT,                                       (JSProperty **)&sprop)) {                    goto bad_formal;                }                JS_ASSERT(sprop);                sprop->id = INT_TO_JSVAL(fun->nargs++);                OBJ_DROP_PROPERTY(cx, obj, (JSProperty *)sprop);                /*                 * 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);    }    /*     * 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.     */    fp = cx->fp;    JS_ASSERT(!fp->script && fp->fun && fp->fun->native == Function);    for (;;) {        fp = fp->down;        if (!fp) {            filename = NULL;            lineno = 0;            principals = NULL;            break;        }        if (fp->script) {            filename = fp->script->filename;            lineno = js_PCToLineNumber(fp->script, fp->pc);            principals = fp->script->principals;            break;        }    }    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;}