}
} while (--nslots != 0); } JS_ASSERT(nslots == 0);
JS_FRIEND_API(JSBool)js_Invoke(JSContext *cx, uintN argc, uintN flags){    void *mark;    JSStackFrame *fp, frame;    jsval *sp, *newsp, *limit;    jsval *vp, v;    JSObject *funobj, *parent, *thisp;    JSBool ok;    JSClass *clasp;    JSObjectOps *ops;    JSNative native;    JSFunction *fun;    JSScript *script;    uintN minargs, nvars;    intN nslots, nalloc, surplus;    JSInterpreterHook hook;    void *hookData;    /* Mark the top of stack and load frequently-used registers. */    mark = JS_ARENA_MARK(&cx->stackPool);    fp = cx->fp;    sp = fp->sp;    /*     * Set vp to the callee value's stack slot (it's where rval goes).     * Once vp is set, control should flow through label out2: to return.     * Set frame.rval early so native class and object ops can throw and     * return false, causing a goto out2 with ok set to false.  Also set     * frame.flags to flags so that ComputeThis can test bits in it.     */    vp = sp - (2 + argc);    v = *vp;    frame.rval = JSVAL_VOID;    frame.flags = flags;    thisp = JSVAL_TO_OBJECT(vp[1]);    /*     * A callee must be an object reference, unless its |this| parameter     * implements the __noSuchMethod__ method, in which case that method will     * be called like so:     *     *   thisp.__noSuchMethod__(id, args)     *     * where id is the name of the method that this invocation attempted to     * call by name, and args is an Array containing this invocation's actual     * parameters.     */    if (JSVAL_IS_PRIMITIVE(v)) {#if JS_HAS_NO_SUCH_METHOD        jsbytecode *pc;        jsatomid atomIndex;        JSAtom *atom;        JSObject *argsobj;        JSArena *a;        if (!fp->script || (flags & JSINVOKE_INTERNAL))            goto bad;        /*         * We must ComputeThis here to censor Call objects; performance hit,         * but at least it's idempotent.         *         * Normally, we call ComputeThis after all frame members have been         * set, and in particular, after any revision of the callee value at         * *vp  due to clasp->convert (see below).  This matters because         * ComputeThis may access *vp via fp->argv[-2], to follow the parent         * chain to a global object to use as the |this| parameter.         *         * Obviously, here in the JSVAL_IS_PRIMITIVE(v) case, there can't be         * any such defaulting of |this| to callee (v, *vp) ancestor.         */        frame.argv = vp + 2;        ok = js_ComputeThis(cx, thisp, &frame);        if (!ok)            goto out2;        thisp = frame.thisp;        ok = OBJ_GET_PROPERTY(cx, thisp,                              ATOM_TO_JSID(cx->runtime->atomState                                           .noSuchMethodAtom),                              &v);        if (!ok)            goto out2;        if (JSVAL_IS_PRIMITIVE(v))            goto bad;        pc = (jsbytecode *) vp[-(intN)fp->script->depth];        switch ((JSOp) *pc) {          case JSOP_NAME:          case JSOP_GETPROP:#if JS_HAS_XML_SUPPORT          case JSOP_GETMETHOD:#endif            atomIndex = GET_ATOM_INDEX(pc);            atom = js_GetAtom(cx, &fp->script->atomMap, atomIndex);            argsobj = js_NewArrayObject(cx, argc, vp + 2);            if (!argsobj) {                ok = JS_FALSE;                goto out2;            }            sp = vp + 4;            if (argc < 2) {                a = cx->stackPool.current;                if ((jsuword)sp > a->limit) {                    /*                     * Arguments must be contiguous, and must include argv[-1]                     * and argv[-2], so allocate more stack, advance sp, and                     * set newsp[1] to thisp (vp[1]).  The other argv elements                     * will be set below, using negative indexing from sp.                     */                    newsp = js_AllocRawStack(cx, 4, NULL);                    if (!newsp) {                        ok = JS_FALSE;                        goto out2;                    }                    newsp[1] = OBJECT_TO_JSVAL(thisp);                    sp = newsp + 4;                } else if ((jsuword)sp > a->avail) {                    /*                     * Inline, optimized version of JS_ARENA_ALLOCATE to claim                     * the small number of words not already allocated as part                     * of the caller's operand stack.                     */                    JS_ArenaCountAllocation(&cx->stackPool,                                            (jsuword)sp - a->avail);                    a->avail = (jsuword)sp;                }            }            sp[-4] = v;            JS_ASSERT(sp[-3] == OBJECT_TO_JSVAL(thisp));            sp[-2] = ATOM_KEY(atom);            sp[-1] = OBJECT_TO_JSVAL(argsobj);            fp->sp = sp;            argc = 2;            break;          default:            goto bad;        }#else        goto bad;#endif    }    funobj = JSVAL_TO_OBJECT(v);    parent = OBJ_GET_PARENT(cx, funobj);    clasp = OBJ_GET_CLASS(cx, funobj);    if (clasp != &js_FunctionClass) {        /* Function is inlined, all other classes use object ops. */        ops = funobj->map->ops;        /*         * XXX this makes no sense -- why convert to function if clasp->call?         * XXX better to call that hook without converting         * XXX the only thing that needs fixing is liveconnect         *         * Try converting to function, for closure and API compatibility.         * We attempt the conversion under all circumstances for 1.2, but         * only if there is a call op defined otherwise.         */        if (JS_VERSION_IS_1_2(cx) ||            ((ops == &js_ObjectOps) ? clasp->call : ops->call)) {            ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v);            if (!ok)                goto out2;            if (JSVAL_IS_FUNCTION(cx, v)) {                /* Make vp refer to funobj to keep it available as argv[-2]. */                *vp = v;                funobj = JSVAL_TO_OBJECT(v);                parent = OBJ_GET_PARENT(cx, funobj);                goto have_fun;            }        }        fun = NULL;        script = NULL;        minargs = nvars = 0;        /* Try a call or construct native object op. */        native = (flags & JSINVOKE_CONSTRUCT) ? ops->construct : ops->call;        if (!native)            goto bad;    } else {have_fun:        /* Get private data and set derived locals from it. */        fun = (JSFunction *) JS_GetPrivate(cx, funobj);        if (fun->interpreted) {            native = NULL;            script = fun->u.script;        } else {            native = fun->u.native;            script = NULL;        }        minargs = fun->nargs + fun->extra;        nvars = fun->nvars;        /* Handle bound method special case. */        if (fun->flags & JSFUN_BOUND_METHOD)            thisp = parent;    }    /* Initialize the rest of frame, except for sp (set by SAVE_SP later). */    frame.varobj = NULL;    frame.callobj = frame.argsobj = NULL;    frame.script = script;    frame.fun = fun;    frame.argc = argc;    frame.argv = sp - argc;    frame.nvars = nvars;    frame.vars = sp;    frame.down = fp;    frame.annotation = NULL;    frame.scopeChain = NULL;    /* set below for real, after cx->fp is set */    frame.pc = NULL;    frame.spbase = NULL;    frame.sharpDepth = 0;    frame.sharpArray = NULL;    frame.dormantNext = NULL;    frame.xmlNamespace = NULL;    /* Compute the 'this' parameter and store it in frame as frame.thisp. */    ok = js_ComputeThis(cx, thisp, &frame);    if (!ok)        goto out2;    /* From here on, control must flow through label out: to return. */    cx->fp = &frame;    /* Init these now in case we goto out before first hook call. */    hook = cx->runtime->callHook;    hookData = NULL;    /* Check for missing arguments expected by the function. */    nslots = (intN)((argc < minargs) ? minargs - argc : 0);    if (nslots) {        /* All arguments must be contiguous, so we may have to copy actuals. */        nalloc = nslots;        limit = (jsval *) cx->stackPool.current->limit;        if (sp + nslots > limit) {            /* Hit end of arena: we have to copy argv[-2..(argc+nslots-1)]. */            nalloc += 2 + argc;        } else {            /* Take advantage of surplus slots in the caller's frame depth. */            surplus = (jsval *)mark - sp;            JS_ASSERT(surplus >= 0);            nalloc -= surplus;        }        /* Check whether we have enough space in the caller's frame. */        if (nalloc > 0) {            /* Need space for actuals plus missing formals minus surplus. */            newsp = js_AllocRawStack(cx, (uintN)nalloc, NULL);            if (!newsp) {                ok = JS_FALSE;                goto out;            }            /* If we couldn't allocate contiguous args, copy actuals now. */            if (newsp != mark) {                JS_ASSERT(sp + nslots > limit);                JS_ASSERT(2 + argc + nslots == (uintN)nalloc);                *newsp++ = vp[0];                *newsp++ = vp[1];                if (argc)                    memcpy(newsp, frame.argv, argc * sizeof(jsval));                frame.argv = newsp;                sp = frame.vars = newsp + argc;            }        }        /* Advance frame.vars to make room for the missing args. */        frame.vars += nslots;        /* Push void to initialize missing args. */        while (--nslots >= 0)            PUSH(JSVAL_VOID);    }    /* Now allocate stack space for local variables. */    nslots = (intN)frame.nvars;    if (nslots) {        surplus = (intN)((jsval *)cx->stackPool.current->avail - frame.vars);        if (surplus < nslots) {            newsp = js_AllocRawStack(cx, (uintN)nslots, NULL);            if (!newsp) {                ok = JS_FALSE;                goto out;            }            if (newsp != sp) {                /* NB: Discontinuity between argv and vars. */                sp = frame.vars = newsp;            }        }        /* Push void to initialize local variables. */        while (--nslots >= 0)            PUSH(JSVAL_VOID);    }    /* Store the current sp in frame before calling fun. */    SAVE_SP(&frame);    /* call the hook if present */    if (hook && (native || script))        hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->callHookData);    /* Call the function, either a native method or an interpreted script. */    if (native) {#if JS_HAS_LVALUE_RETURN        /* Set by JS_SetCallReturnValue2, used to return reference types. */        cx->rval2set = JS_FALSE;#endif        /* If native, use caller varobj and scopeChain for eval. */        frame.varobj = fp->varobj;        frame.scopeChain = fp->scopeChain;        ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval);        JS_RUNTIME_METER(cx->runtime, nativeCalls);    } else if (script) {#ifdef DUMP_CALL_TABLE        LogCall(cx, *vp, argc, frame.argv);#endif        /* Use parent scope so js_GetCallObject can find the right "Call". */        frame.scopeChain = parent;        if (fun->flags & JSFUN_HEAVYWEIGHT) {#if JS_HAS_CALL_OBJECT            /* Scope with a call object parented by the callee's parent. */            if (!js_GetCallObject(cx, &frame, parent)) {                ok = JS_FALSE;                goto out;            }#else            /* Bad old code used the function as a proxy for all calls to it. */            frame.scopeChain = funobj;#endif        }        ok = js_Interpret(cx, script->code, &v);    } else {        /* fun might be onerror trying to report a syntax error in itself. */        frame.scopeChain = NULL;        ok = JS_TRUE;    }out:    if (hookData) {        hook = cx->runtime->callHook;        if (hook)            hook(cx, &frame, JS_FALSE, &ok, hookData);    }#if JS_HAS_CALL_OBJECT    /* If frame has a call object, sync values and clear back-pointer. */    if (frame.callobj)        ok &= js_PutCallObject(cx, &frame);#endif#if JS_HAS_ARGS_OBJECT    /* If frame has an arguments object, sync values and clear back-pointer. */    if (frame.argsobj)        ok &= js_PutArgsObject(cx, &frame);#endif    /* Restore cx->fp now that we're done releasing frame objects. */    cx->fp = fp;out2:    /* Pop everything we may have allocated off the stack. */    JS_ARENA_RELEASE(&cx->stackPool, mark);    /* Store the return value and restore sp just above it. */    *vp = frame.rval;    fp->sp = vp + 1;    /*     * Store the location of the JSOP_CALL or JSOP_EVAL that generated the     * return value, but only if this is an external (compiled from script     * source) call that has stack budget for the generating pc.     */    if (fp->script && !(flags & JSINVOKE_INTERNAL))        vp[-(intN)fp->script->depth] = (jsval)fp->pc;    return ok;bad:    js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_CONSTRUCT);    ok = JS_FALSE;    goto out2;}