jsinterp.c

来自「java script test programing source code」· C语言 代码 · 共 1,863 行 · 第 1/5 页

C
1,863
字号
     * parameters.     */    if (JSVAL_IS_PRIMITIVE(v)) {#if JS_HAS_NO_SUCH_METHOD        if (fp->script && !(flags & JSINVOKE_INTERNAL)) {            ok = NoSuchMethod(cx, fp, vp, flags, argc);            if (ok)                frame.rval = *vp;            goto out2;        }#endif        goto bad;    }    /* Load thisv after potentially calling NoSuchMethod, which may set it. */    thisv = vp[1];    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 ((ops == &js_ObjectOps) ? clasp->call : ops->call) {            ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v);            if (!ok)                goto out2;            if (VALUE_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;        nslots = nvars = 0;        /* Try a call or construct native object op. */        native = (flags & JSINVOKE_CONSTRUCT) ? ops->construct : ops->call;        if (!native)            goto bad;        if (JSVAL_IS_OBJECT(thisv)) {            thisp = JSVAL_TO_OBJECT(thisv);        } else {            PRIMITIVE_TO_OBJECT(cx, thisv, thisp);            if (!thisp)                goto out2;            vp[1] = thisv = OBJECT_TO_JSVAL(thisp);        }    } else {have_fun:        /* Get private data and set derived locals from it. */        fun = (JSFunction *) JS_GetPrivate(cx, funobj);        nslots = (fun->nargs > argc) ? fun->nargs - argc : 0;        if (FUN_INTERPRETED(fun)) {            native = NULL;            script = fun->u.i.script;            nvars = fun->u.i.nvars;        } else {            native = fun->u.n.native;            script = NULL;            nvars = 0;            nslots += fun->u.n.extra;        }        if (JSFUN_BOUND_METHOD_TEST(fun->flags)) {            /* Handle bound method special case. */            thisp = parent;        } else if (JSVAL_IS_OBJECT(thisv)) {            thisp = JSVAL_TO_OBJECT(thisv);        } else {            uintN thispflags = JSFUN_THISP_FLAGS(fun->flags);            JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT));            if (JSVAL_IS_STRING(thisv)) {                if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_STRING)) {                    thisp = (JSObject *) thisv;                    goto init_frame;                }                thisp = js_StringToObject(cx, JSVAL_TO_STRING(thisv));            } else if (JSVAL_IS_INT(thisv)) {                if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_NUMBER)) {                    thisp = (JSObject *) thisv;                    goto init_frame;                }                thisp = js_NumberToObject(cx, (jsdouble)JSVAL_TO_INT(thisv));            } else if (JSVAL_IS_DOUBLE(thisv)) {                if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_NUMBER)) {                    thisp = (JSObject *) thisv;                    goto init_frame;                }                thisp = js_NumberToObject(cx, *JSVAL_TO_DOUBLE(thisv));            } else {                JS_ASSERT(JSVAL_IS_BOOLEAN(thisv));                if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_BOOLEAN)) {                    thisp = (JSObject *) thisv;                    goto init_frame;                }                thisp = js_BooleanToObject(cx, JSVAL_TO_BOOLEAN(thisv));            }            if (!thisp) {                ok = JS_FALSE;                goto out2;            }            goto init_frame;        }    }    if (flags & JSINVOKE_CONSTRUCT) {        /* Default return value for a constructor is the new object. */        frame.rval = OBJECT_TO_JSVAL(thisp);    } else {        thisp = js_ComputeThis(cx, thisp, vp + 2);        if (!thisp) {            ok = JS_FALSE;            goto out2;        }    }  init_frame:    /* Initialize the rest of frame, except for sp (set by SAVE_SP later). */    frame.thisp = thisp;    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.flags = flags;    frame.dormantNext = NULL;    frame.xmlNamespace = NULL;    frame.blockChain = NULL;    /* 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 argument slots required by the function. */    if (nslots) {        /* All arguments must be contiguous, so we may have to copy actuals. */        nalloc = nslots;        limit = (jsval *) cx->stackPool.current->limit;        JS_ASSERT((jsval *) cx->stackPool.current->base <= sp && sp <= 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. */            JS_ASSERT((jsval *)mark >= sp);            surplus = (jsval *)mark - sp;            nalloc -= surplus;        }        /* Check whether we have enough space in the caller's frame. */        if ((intN)nalloc > 0) {            /* Need space for actuals plus missing formals minus surplus. */            newsp = js_AllocRawStack(cx, 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 == 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. */        do {            PUSH(JSVAL_VOID);        } while (--nslots != 0);    }    JS_ASSERT(nslots == 0);    /* Now allocate stack space for local variables. */    if (nvars) {        JS_ASSERT((jsval *)cx->stackPool.current->avail >= frame.vars);        surplus = (jsval *)cx->stackPool.current->avail - frame.vars;        if (surplus < nvars) {            newsp = js_AllocRawStack(cx, nvars, 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. */        do {            PUSH(JSVAL_VOID);        } while (--nvars != 0);    }    JS_ASSERT(nvars == 0);    /* 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) {#ifdef DEBUG_NOT_THROWING        JSBool alreadyThrowing = cx->throwing;#endif#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);#ifdef DEBUG_NOT_THROWING        if (ok && !alreadyThrowing)            ASSERT_NOT_THROWING(cx);#endif    } 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 (JSFUN_HEAVYWEIGHT_TEST(fun->flags)) {            /* Scope with a call object parented by the callee's parent. */            if (!js_GetCallObject(cx, &frame, parent)) {                ok = JS_FALSE;                goto out;            }        }        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 frame has a call object, sync values and clear back-pointer. */    if (frame.callobj)        ok &= js_PutCallObject(cx, &frame);    /* If frame has an arguments object, sync values and clear back-pointer. */    if (frame.argsobj)        ok &= js_PutArgsObject(cx, &frame);    /* 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_FUNFLAGS);    ok = JS_FALSE;    goto out2;}JSBooljs_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,                  uintN argc, jsval *argv, jsval *rval){    JSStackFrame *fp, *oldfp, frame;    jsval *oldsp, *sp;    void *mark;    uintN i;    JSBool ok;    fp = oldfp = cx->fp;    if (!fp) {        memset(&frame, 0, sizeof frame);        cx->fp = fp = &frame;    }    oldsp = fp->sp;    sp = js_AllocStack(cx, 2 + argc, &mark);    if (!sp) {        ok = JS_FALSE;        goto out;    }    PUSH(fval);    PUSH(OBJECT_TO_JSVAL(obj));    for (i = 0; i < argc; i++)        PUSH(argv[i]);    SAVE_SP(fp);    ok = js_Invoke(cx, argc, flags | JSINVOKE_INTERNAL);    if (ok) {        RESTORE_SP(fp);        /*         * Store *rval in the a scoped local root if a scope is open, else in         * the lastInternalResult pigeon-hole GC root, solely so users of         * js_InternalInvoke and its direct and indirect (js_ValueToString for         * example) callers do not need to manage roots for local, temporary         * references to such results.         */        *rval = POP_OPND();        if (JSVAL_IS_GCTHING(*rval)) {            if (cx->localRootStack) {                if (js_PushLocalRoot(cx, cx->localRootStack, *rval) < 0)                    ok = JS_FALSE;            } else {                cx->weakRoots.lastInternalResult = *rval;            }        }    }    js_FreeStack(cx, mark);out:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?