⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jsinterp.c

📁 Swfdec still is development software, but has also followed a rigid no-crashes-allowed policy. I b
💻 C
📖 第 1 页 / 共 5 页
字号:
        /* 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;    }    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);}/* * To economize on slots space in functions, the compiler records arguments and * local variables as shared (JSPROP_SHARED) properties with well-known getters * and setters: js_{Get,Set}Argument, js_{Get,Set}LocalVariable.  Now, we could * record args and vars in lists or hash tables in function-private data, but * that means more duplication in code, and more data at runtime in the hash * table case due to round-up to powers of two, just to recapitulate the scope * machinery in the function object. * * What's more, for a long time (to the dawn of "Mocha" in 1995), these getters * and setters knew how to search active stack frames in a context to find the * top activation of the function f, in order to satisfy a get or set of f.a, * for argument a, or f.x, for local variable x.  You could use f.a instead of * just a in function f(a) { return f.a }, for example, to return the actual * parameter. * * ECMA requires that we give up on this ancient extension, because it is not * compatible with the standard as used by real-world scripts.  While Chapter * 16 does allow for additional properties to be defined on native objects by * a conforming implementation, these magic getters and setters cause f.a's * meaning to vary unexpectedly.  Real-world scripts set f.A = 42 to define * "class static" (after Java) constants, for example, but if A also names an * arg or var in f, the constant is not available while f is active, and any * non-constant class-static can't be set while f is active. * * So, to label arg and var properties in functions without giving them magic * abilities to affect active frame stack slots, while keeping the properties * shared (slot-less) to save space in the common case (where no assignment * sets a function property with the same name as an arg or var), the setters * for args and vars must handle two special cases here. * * XXX functions tend to have few args and vars, so we risk O(n^2) growth here * XXX ECMA *really* wants args and vars to be stored in function-private data, *     not as function object properties. */static JSBoolSetFunctionSlot(JSContext *cx, JSObject *obj, JSPropertyOp setter, jsid id,                jsval v){    uintN slot;    JSObject *origobj;    JSScope *scope;    JSScopeProperty *sprop;    JSString *str;    JSBool ok;    slot = (uintN) JSVAL_TO_INT(id);    if (OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {        /*         * Given a non-function object obj that has a function object in its         * prototype chain, where an argument or local variable property named         * by (setter, slot) is being set, override the shared property in the         * prototype with an unshared property in obj.  This situation arises         * in real-world JS due to .prototype setting and collisions among a         * function's "static property" names and arg or var names, believe it         * or not.         */        origobj = obj;        do {            obj = OBJ_GET_PROTO(cx, obj);            if (!obj)                return JS_TRUE;        } while (OBJ_GET_CLASS(cx, obj) != &js_FunctionClass);        JS_LOCK_OBJ(cx, obj);        scope = OBJ_SCOPE(obj);        for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {            if (sprop->setter == setter) {                JS_ASSERT(!JSVAL_IS_INT(sprop->id) &&                          ATOM_IS_STRING((JSAtom *)sprop->id) &&                          (sprop->flags & SPROP_HAS_SHORTID));                if ((uintN) sprop->shortid == slot) {                    str = ATOM_TO_STRING((JSAtom *)sprop->id);                    JS_UNLOCK_SCOPE(cx, scope);                    return JS_DefineUCProperty(cx, origobj,                                               JSSTRING_CHARS(str),                                               JSSTRING_LENGTH(str),                                               v, NULL, NULL,                                               JSPROP_ENUMERATE);                }            }        }        JS_UNLOCK_SCOPE(cx, scope);        return JS_TRUE;    }    /*     * Argument and local variable properties of function objects are shared     * by default (JSPROP_SHARED), therefore slot-less.  But if for function     * f(a) {}, f.a = 42 is evaluated, f.a should be 42 after the assignment,     * whether or not f is active.  So js_SetArgument and js_SetLocalVariable     * must be prepared to change an arg or var from shared to unshared status,     * allocating a slot in obj to hold v.     */    ok = JS_TRUE;    JS_LOCK_OBJ(cx, obj);    scope = OBJ_SCOPE(obj);    for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {        if (sprop->setter == setter && (uintN) sprop->shortid == slot) {            if (sprop->attrs & JSPROP_SHARED) {                sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop,                                                    0, ~JSPROP_SHARED,                                                    sprop->getter, setter);                if (!sprop) {                    ok = JS_FALSE;                } else {                    /* See js_SetProperty, near the bottom. */                    GC_POKE(cx, pval);                    LOCKED_OBJ_SET_SLOT(obj, sprop->slot, v);                }            }            break;        }    }    JS_UNLOCK_SCOPE(cx, scope);    return ok;}JSBooljs_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp){    return JS_TRUE;}JSBooljs_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp){    return SetFunctionSlot(cx, obj, js_SetArgument, id, *vp);}JSBooljs_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp){    return JS_TRUE;}JSBooljs_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp){    return SetFunctionSlot(cx, obj, js_SetLocalVariable, id, *vp);}/* * Compute the 'this' parameter and store it in frame as frame.thisp. * Activation objects ("Call" objects not created with "new Call()", i.e., * "Call" objects that have private data) may not be referred to by 'this', * as dictated by ECMA. * * N.B.: fp->argv must be set, fp->argv[-1] the nominal 'this' paramter as * a jsval, and fp->argv[-2] must be the callee object reference, usually a * function object.  Also, fp->flags must contain JSFRAME_CONSTRUCTING if we * are preparing for a constructor call. */static JSBoolComputeThis(JSContext *cx, JSObject *thisp, JSStackFrame *fp){    JSObject *parent;    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 JS_FALSE;        /* Default return value for a constructor is the new object. */        if (fp->flags & JSFRAME_CONSTRUCTING)            fp->rval = OBJECT_TO_JSVAL(thisp);    } 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".         */        JS_ASSERT(!(fp->flags & JSFRAME_CONSTRUCTING));        if (JSVAL_IS_PRIMITIVE(fp->argv[-2]) ||            !(parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fp->argv[-2])))) {            thisp = cx->globalObject;        } else {            /* walk up to find the top-level object */            thisp = parent;            while ((parent = OBJ_GET_PARENT(cx, thisp)) != NULL)                thisp = parent;        }    }    fp->thisp = thisp;    fp->argv[-1] = OBJECT_TO_JSVAL(thisp);    return JS_TRUE;}extern JSBoolswfdec_script_interpret(void *script, JSContext *cx, jsval *rval);/* * Find a function reference and its 'this' object implicit first parameter * under argc arguments on cx's stack, and call the function.  Push missing * required arguments, allocate declared local variables, and pop everything * when done.  Then push the return value. */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;    void *swf;    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 = ComputeThis(cx, thisp, &frame);        if (!ok)            goto out2;        thisp = frame.thisp;        ok = OBJ_GET_PROPERTY(cx, thisp,                              (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:            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;            }

⌨️ 快捷键说明

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