jsinterp.c

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

C
1,863
字号
    /* Try to avoid another header if we can piggyback on the last segment. */    a = cx->stackPool.current;    sh = cx->stackHeaders;    if (sh && JS_STACK_SEGMENT(sh) + sh->nslots == sp) {        /* Extend the last stack segment, give back the 2 header slots. */        sh->nslots += nslots;        a->avail -= 2 * sizeof(jsval);    } else {        /*         * Need a new stack segment, so we must initialize unused slots in the         * current frame.  See js_GC, just before marking the "operand" jsvals,         * where we scan from fp->spbase to fp->sp or through fp->script->depth         * (whichever covers fewer slots).         */        fp = cx->fp;        if (fp && fp->script && fp->spbase) {#ifdef DEBUG            jsuword depthdiff = fp->script->depth * sizeof(jsval);            JS_ASSERT(JS_UPTRDIFF(fp->sp, fp->spbase) <= depthdiff);            JS_ASSERT(JS_UPTRDIFF(*markp, fp->spbase) >= depthdiff);#endif            end = fp->spbase + fp->script->depth;            for (vp = fp->sp; vp < end; vp++)                *vp = JSVAL_VOID;        }        /* Allocate and push a stack segment header from the 2 extra slots. */        sh = (JSStackHeader *)sp;        sh->nslots = nslots;        sh->down = cx->stackHeaders;        cx->stackHeaders = sh;        sp += 2;    }    /*     * Store JSVAL_NULL using memset, to let compilers optimize as they see     * fit, in case a caller allocates and pushes GC-things one by one, which     * could nest a last-ditch GC that will scan this segment.     */    memset(sp, 0, nslots * sizeof(jsval));    return sp;}JS_FRIEND_API(void)js_FreeStack(JSContext *cx, void *mark){    JSStackHeader *sh;    jsuword slotdiff;    /* Check for zero nslots allocation special case. */    if (!mark)        return;    /* We can assert because js_FreeStack always balances js_AllocStack. */    sh = cx->stackHeaders;    JS_ASSERT(sh);    /* If mark is in the current segment, reduce sh->nslots, else pop sh. */    slotdiff = JS_UPTRDIFF(mark, JS_STACK_SEGMENT(sh)) / sizeof(jsval);    if (slotdiff < (jsuword)sh->nslots)        sh->nslots = slotdiff;    else        cx->stackHeaders = sh->down;    /* Release the stackPool space allocated since mark was set. */    JS_ARENA_RELEASE(&cx->stackPool, mark);}JSBooljs_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp){    return JS_TRUE;}JSBooljs_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp){    return JS_TRUE;}JSBooljs_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp){    return JS_TRUE;}JSBooljs_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp){    return JS_TRUE;}JSObject *js_GetScopeChain(JSContext *cx, JSStackFrame *fp){    JSObject *obj, *cursor, *clonedChild, *parent;    JSTempValueRooter tvr;    obj = fp->blockChain;    if (!obj) {        /*         * Don't force a call object for a lightweight function call, but do         * insist that there is a call object for a heavyweight function call.         */        JS_ASSERT(!fp->fun ||                  !(fp->fun->flags & JSFUN_HEAVYWEIGHT) ||                  fp->callobj);        JS_ASSERT(fp->scopeChain);        return fp->scopeChain;    }    /*     * We have one or more lexical scopes to reflect into fp->scopeChain, so     * make sure there's a call object at the current head of the scope chain,     * if this frame is a call frame.     */    if (fp->fun && !fp->callobj) {        JS_ASSERT(OBJ_GET_CLASS(cx, fp->scopeChain) != &js_BlockClass ||                  JS_GetPrivate(cx, fp->scopeChain) != fp);        if (!js_GetCallObject(cx, fp, fp->scopeChain))            return NULL;    }    /*     * Clone the block chain. To avoid recursive cloning we set the parent of     * the cloned child after we clone the parent. In the following loop when     * clonedChild is null it indicates the first iteration when no special GC     * rooting is necessary. On the second and the following iterations we     * have to protect cloned so far chain against the GC during cloning of     * the cursor object.     */    cursor = obj;    clonedChild = NULL;    for (;;) {        parent = OBJ_GET_PARENT(cx, cursor);        /*         * We pass fp->scopeChain and not null even if we override the parent         * slot later as null triggers useless calculations of slot's value in         * js_NewObject that js_CloneBlockObject calls.         */        cursor = js_CloneBlockObject(cx, cursor, fp->scopeChain, fp);        if (!cursor) {            if (clonedChild)                JS_POP_TEMP_ROOT(cx, &tvr);            return NULL;        }        if (!clonedChild) {            /*             * The first iteration. Check if other follow and root obj if so             * to protect the whole cloned chain against GC.             */            obj = cursor;            if (!parent)                break;            JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);        } else {            /*             * Avoid OBJ_SET_PARENT overhead as clonedChild cannot escape to             * other threads.             */            clonedChild->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(cursor);            if (!parent) {                JS_ASSERT(tvr.u.value == OBJECT_TO_JSVAL(obj));                JS_POP_TEMP_ROOT(cx, &tvr);                break;            }        }        clonedChild = cursor;        cursor = parent;    }    fp->flags |= JSFRAME_POP_BLOCKS;    fp->scopeChain = obj;    fp->blockChain = NULL;    return obj;}/* * Walk the scope chain looking for block scopes whose locals need to be * copied from stack slots into object slots before fp goes away. */static JSBoolPutBlockObjects(JSContext *cx, JSStackFrame *fp){    JSBool ok;    JSObject *obj;    ok = JS_TRUE;    for (obj = fp->scopeChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {        if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {            if (JS_GetPrivate(cx, obj) != fp)                break;            ok &= js_PutBlockObject(cx, obj);        }    }    return ok;}JSObject *js_ComputeThis(JSContext *cx, JSObject *thisp, jsval *argv){    if (thisp && OBJ_GET_CLASS(cx, thisp) != &js_CallClass) {        /* Some objects (e.g., With) delegate 'this' to another object. */        thisp = OBJ_THIS_OBJECT(cx, thisp);        if (!thisp)            return NULL;    } else {        /*         * ECMA requires "the global object", but in the presence of multiple         * top-level objects (windows, frames, or certain layers in the client         * object model), we prefer fun's parent.  An example that causes this         * code to run:         *         *   // in window w1         *   function f() { return this }         *   function g() { return f }         *         *   // in window w2         *   var h = w1.g()         *   alert(h() == w1)         *         * The alert should display "true".         */        if (JSVAL_IS_PRIMITIVE(argv[-2]) ||            !OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]))) {            thisp = cx->globalObject;        } else {            jsid id;            jsval v;            uintN attrs;            /* Walk up the parent chain. */            thisp = JSVAL_TO_OBJECT(argv[-2]);            id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom);            for (;;) {                if (!OBJ_CHECK_ACCESS(cx, thisp, id, JSACC_PARENT, &v, &attrs))                    return NULL;                if (JSVAL_IS_VOID(v))                    v = OBJ_GET_SLOT(cx, thisp, JSSLOT_PARENT);                if (JSVAL_IS_NULL(v))                    break;                thisp = JSVAL_TO_OBJECT(v);            }        }    }    argv[-1] = OBJECT_TO_JSVAL(thisp);    return thisp;}#if JS_HAS_NO_SUCH_METHODstatic JSBoolNoSuchMethod(JSContext *cx, JSStackFrame *fp, jsval *vp, uint32 flags,             uintN argc){    JSObject *thisp, *argsobj;    jsval *sp, roots[3];    JSTempValueRooter tvr;    jsid id;    JSBool ok;    jsbytecode *pc;    jsatomid atomIndex;    /*     * We must call js_ComputeThis here to censor Call objects.  A performance     * hit, since we'll call it again in the normal sequence of invoke events,     * 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.     */    JS_ASSERT(JSVAL_IS_PRIMITIVE(vp[0]));    RESTORE_SP(fp);    if (JSVAL_IS_OBJECT(vp[1])) {        thisp = JSVAL_TO_OBJECT(vp[1]);    } else {        PRIMITIVE_TO_OBJECT(cx, vp[1], thisp);        if (!thisp)            return JS_FALSE;        vp[1] = OBJECT_TO_JSVAL(thisp);    }    thisp = js_ComputeThis(cx, thisp, vp + 2);    if (!thisp)        return JS_FALSE;    vp[1] = OBJECT_TO_JSVAL(thisp);    /* From here on, control must flow through label out: to return. */    memset(roots, 0, sizeof roots);    JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr);    id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);#if JS_HAS_XML_SUPPORT    if (OBJECT_IS_XML(cx, thisp)) {        JSXMLObjectOps *ops;        ops = (JSXMLObjectOps *) thisp->map->ops;        thisp = ops->getMethod(cx, thisp, id, &roots[2]);        if (!thisp) {            ok = JS_FALSE;            goto out;        }        vp[1] = OBJECT_TO_JSVAL(thisp);    } else#endif    {        ok = OBJ_GET_PROPERTY(cx, thisp, id, &roots[2]);        if (!ok)            goto out;    }    if (JSVAL_IS_PRIMITIVE(roots[2]))        goto not_function;    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);        roots[0] = ATOM_KEY(js_GetAtom(cx, &fp->script->atomMap, atomIndex));        argsobj = js_NewArrayObject(cx, argc, vp + 2);        if (!argsobj) {            ok = JS_FALSE;            goto out;        }        roots[1] = OBJECT_TO_JSVAL(argsobj);        ok = js_InternalInvoke(cx, thisp, roots[2], flags | JSINVOKE_INTERNAL,                               2, roots, &vp[0]);        break;      default:        goto not_function;    }  out:    JS_POP_TEMP_ROOT(cx, &tvr);    return ok;  not_function:    js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS);    ok = JS_FALSE;    goto out;}#endif /* JS_HAS_NO_SUCH_METHOD */#ifdef DUMP_CALL_TABLE#include "jsclist.h"#include "jshash.h"#include "jsdtoa.h"typedef struct CallKey {    jsval               callee;                 /* callee value */    const char          *filename;              /* function filename or null */    uintN               lineno;                 /* function lineno or 0 */} CallKey;/* Compensate for typeof null == "object" brain damage. */#define JSTYPE_NULL     JSTYPE_LIMIT#define TYPEOF(cx,v)    (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))#define TYPENAME(t)     (((t) == JSTYPE_NULL) ? js_null_str : js_type_str[t])#define NTYPEHIST       (JSTYPE_LIMIT + 1)typedef struct CallValue {    uint32              total;                  /* total call count */

⌨️ 快捷键说明

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