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

📄 jsemit.c

📁 Swfdec still is development software, but has also followed a rigid no-crashes-allowed policy. I b
💻 C
📖 第 1 页 / 共 5 页
字号:
 * This routine tries to optimize name gets and sets to stack slot loads and * stores, given the variables object and scope chain in cx's top frame, the * compile-time context in tc, and a TOK_NAME node pn.  It returns false on * error, true on success. * * The caller can inspect pn->pn_slot for a non-negative slot number to tell * whether optimization occurred, in which case LookupArgOrVar also updated * pn->pn_op.  If pn->pn_slot is still -1 on return, pn->pn_op nevertheless * may have been optimized, e.g., from JSOP_NAME to JSOP_ARGUMENTS.  Whether * or not pn->pn_op was modified, if this function finds an argument or local * variable name, pn->pn_attrs will contain the property's attributes after a * successful return. */static JSBoolLookupArgOrVar(JSContext *cx, JSTreeContext *tc, JSParseNode *pn){    JSObject *obj, *pobj;    JSClass *clasp;    JSAtom *atom;    JSScopeProperty *sprop;    JSOp op;    JS_ASSERT(pn->pn_type == TOK_NAME);    if (pn->pn_slot >= 0 || pn->pn_op == JSOP_ARGUMENTS)        return JS_TRUE;    /*     * We can't optimize if var and closure (a local function not in a larger     * expression and not at top-level within another's body) collide.     * XXX suboptimal: keep track of colliding names and deoptimize only those     */    if (tc->flags & TCF_FUN_CLOSURE_VS_VAR)        return JS_TRUE;    /*     * We can't optimize if we're not compiling a function body, whether via     * eval, or directly when compiling a function statement or expression.     */    obj = cx->fp->varobj;    clasp = OBJ_GET_CLASS(cx, obj);    if (clasp != &js_FunctionClass && clasp != &js_CallClass)        return JS_TRUE;    /*     * We can't optimize if we're in an eval called inside a with statement,     * or we're compiling a with statement and its body, or we're in a catch     * block whose exception variable has the same name as pn.     */    atom = pn->pn_atom;    if (cx->fp->scopeChain != obj ||        js_InWithStatement(tc) ||        js_InCatchBlock(tc, atom)) {        return JS_TRUE;    }    /*     * Ok, we may be able to optimize name to stack slot. Look for an argument     * or variable property in the function, or its call object, not found in     * any prototype object.  Rewrite pn_op and update pn accordingly.  NB: We     * know that JSOP_DELNAME on an argument or variable must evaluate to     * false, due to JSPROP_PERMANENT.     */    if (!js_LookupProperty(cx, obj, (jsid)atom, &pobj, (JSProperty **)&sprop))        return JS_FALSE;    op = pn->pn_op;    if (sprop) {        if (pobj == obj) {            JSPropertyOp getter = sprop->getter;            if (getter == js_GetArgument) {                switch (op) {                  case JSOP_NAME:     op = JSOP_GETARG; break;                  case JSOP_SETNAME:  op = JSOP_SETARG; break;                  case JSOP_INCNAME:  op = JSOP_INCARG; break;                  case JSOP_NAMEINC:  op = JSOP_ARGINC; break;                  case JSOP_DECNAME:  op = JSOP_DECARG; break;                  case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;                  case JSOP_FORNAME:  op = JSOP_FORARG; break;                  case JSOP_DELNAME:  op = JSOP_FALSE; break;                  default: JS_ASSERT(0);                }            } else if (getter == js_GetLocalVariable ||                       getter == js_GetCallVariable)            {                switch (op) {                  case JSOP_NAME:     op = JSOP_GETVAR; break;                  case JSOP_SETNAME:  op = JSOP_SETVAR; break;                  case JSOP_SETCONST: op = JSOP_SETVAR; break;                  case JSOP_INCNAME:  op = JSOP_INCVAR; break;                  case JSOP_NAMEINC:  op = JSOP_VARINC; break;                  case JSOP_DECNAME:  op = JSOP_DECVAR; break;                  case JSOP_NAMEDEC:  op = JSOP_VARDEC; break;                  case JSOP_FORNAME:  op = JSOP_FORVAR; break;                  case JSOP_DELNAME:  op = JSOP_FALSE; break;                  default: JS_ASSERT(0);                }            }            if (op != pn->pn_op) {                pn->pn_op = op;                pn->pn_slot = sprop->shortid;            }            pn->pn_attrs = sprop->attrs;        }        OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);    }    if (pn->pn_slot < 0) {        /*         * We couldn't optimize it, so it's not an arg or local var name.  Now         * we must check for the predefined arguments variable.  It may be         * overridden by assignment, in which case the function is heavyweight         * and the interpreter will look up 'arguments' in the function's call         * object.         */        if (pn->pn_op == JSOP_NAME &&            atom == cx->runtime->atomState.argumentsAtom) {            pn->pn_op = JSOP_ARGUMENTS;            return JS_TRUE;        }        tc->flags |= TCF_FUN_USES_NONLOCALS;    }    return JS_TRUE;}/* * If pn contains a useful expression, return true with *answer set to true. * If pn contains a useless expression, return true with *answer set to false. * Return false on error. * * The caller should initialize *answer to false and invoke this function on * an expression statement or similar subtree to decide whether the tree could * produce code that has any side effects.  For an expression statement, we * define useless code as code with no side effects, because the main effect, * the value left on the stack after the code executes, will be discarded by a * pop bytecode. */static JSBoolCheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,                 JSBool *answer){    JSBool ok;    JSFunction *fun;    JSParseNode *pn2;    ok = JS_TRUE;    if (!pn || *answer)        return ok;    switch (pn->pn_arity) {      case PN_FUNC:        /*         * A named function is presumed useful: we can't yet know that it is         * not called.  The side effects are the creation of a scope object         * to parent this function object, and the binding of the function's         * name in that scope object.  See comments at case JSOP_NAMEDFUNOBJ:         * in jsinterp.c.         */        fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(pn->pn_funAtom));        if (fun->atom)            *answer = JS_TRUE;        break;      case PN_LIST:        if (pn->pn_type == TOK_NEW ||            pn->pn_type == TOK_LP ||            pn->pn_type == TOK_LB) {            /*             * All invocation operations (construct: TOK_NEW, call: TOK_LP)             * are presumed to be useful, because they may have side effects             * even if their main effect (their return value) is discarded.             *             * TOK_LB binary trees of 3 or more nodes are flattened into lists             * to avoid too much recursion.  All such lists must be presumed             * to be useful because each index operation could invoke a getter             * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,             * does not apply here: arguments[i][j] might invoke a getter).             */            *answer = JS_TRUE;        } else {            for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)                ok &= CheckSideEffects(cx, tc, pn2, answer);        }        break;      case PN_TERNARY:        ok = CheckSideEffects(cx, tc, pn->pn_kid1, answer) &&             CheckSideEffects(cx, tc, pn->pn_kid2, answer) &&             CheckSideEffects(cx, tc, pn->pn_kid3, answer);        break;      case PN_BINARY:        if (pn->pn_type == TOK_ASSIGN) {            /*             * Assignment is presumed to be useful, even if the next operation             * is another assignment overwriting this one's ostensible effect,             * because the left operand may be a property with a setter that             * has side effects.             */            *answer = JS_TRUE;        } else {            if (pn->pn_type == TOK_LB) {                pn2 = pn->pn_left;                if (pn2->pn_type == TOK_NAME && !LookupArgOrVar(cx, tc, pn2))                    return JS_FALSE;                if (pn2->pn_op != JSOP_ARGUMENTS) {                    /*                     * Any indexed property reference could call a getter with                     * side effects, except for arguments[i] where arguments is                     * unambiguous.                     */                    *answer = JS_TRUE;                }            }            ok = CheckSideEffects(cx, tc, pn->pn_left, answer) &&                 CheckSideEffects(cx, tc, pn->pn_right, answer);        }        break;      case PN_UNARY:        if (pn->pn_type == TOK_INC || pn->pn_type == TOK_DEC ||            pn->pn_type == TOK_DELETE ||            pn->pn_type == TOK_THROW ||            pn->pn_type == TOK_DEFSHARP) {            /* All these operations have effects that we must commit. */            *answer = JS_TRUE;        } else {            ok = CheckSideEffects(cx, tc, pn->pn_kid, answer);        }        break;      case PN_NAME:        if (pn->pn_type == TOK_NAME) {            if (!LookupArgOrVar(cx, tc, pn))                return JS_FALSE;            if (pn->pn_slot < 0 && pn->pn_op != JSOP_ARGUMENTS) {                /*                 * Not an argument or local variable use, so this expression                 * could invoke a getter that has side effects.                 */                *answer = JS_TRUE;            }        }        pn2 = pn->pn_expr;        if (pn->pn_type == TOK_DOT && pn2->pn_type == TOK_NAME) {            if (!LookupArgOrVar(cx, tc, pn2))                return JS_FALSE;            if (!(pn2->pn_op == JSOP_ARGUMENTS &&                  pn->pn_atom == cx->runtime->atomState.lengthAtom)) {                /*                 * Any dotted property reference could call a getter, except                 * for arguments.length where arguments is unambiguous.                 */                *answer = JS_TRUE;            }        }        ok = CheckSideEffects(cx, tc, pn2, answer);        break;      case PN_NULLARY:        if (pn->pn_type == TOK_DEBUGGER)            *answer = JS_TRUE;        break;    }    return ok;}static JSBoolEmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg){    JSParseNode *pn2, *pndot, *pnup, *pndown;    ptrdiff_t top;    JSAtomListElement *ale;    pn2 = pn->pn_expr;    if (op == JSOP_GETPROP &&        pn->pn_type == TOK_DOT &&        pn2->pn_type == TOK_NAME) {        /* Try to optimize arguments.length into JSOP_ARGCNT. */        if (!LookupArgOrVar(cx, &cg->treeContext, pn2))            return JS_FALSE;        if (pn2->pn_op == JSOP_ARGUMENTS &&            pn->pn_atom == cx->runtime->atomState.lengthAtom) {            return js_Emit1(cx, cg, JSOP_ARGCNT) >= 0;        }    }    /*     * If the object operand is also a dotted property reference, reverse the     * list linked via pn_expr temporarily so we can iterate over it from the     * bottom up (reversing again as we go), to avoid excessive recursion.     */    if (pn2->pn_type == TOK_DOT) {        pndot = pn2;        pnup = NULL;        top = CG_OFFSET(cg);        for (;;) {            /* Reverse pndot->pn_expr to point up, not down. */            pndot->pn_offset = top;            pndown = pndot->pn_expr;            pndot->pn_expr = pnup;            if (pndown->pn_type != TOK_DOT)                break;            pnup = pndot;            pndot = pndown;        }        /* pndown is a primary expression, not a dotted property reference. */        if (!js_EmitTree(cx, cg, pndown))            return JS_FALSE;        do {            /* Walk back up the list, emitting annotated name ops. */            if (js_NewSrcNote2(cx, cg, SRC_PCBASE,                               CG_OFFSET(cg) - pndown->pn_offset) < 0) {                return JS_FALSE;            }            ale = js_IndexAtom(cx, pndot->pn_atom, &cg->atomList);            if (!ale)                return JS_FALSE;            EMIT_ATOM_INDEX_OP(pndot->pn_op, ALE_INDEX(ale));            /* Reverse the pn_expr link again. */            pnup = pndot->pn_expr;            pndot->pn_expr = pndown;            pndown = pndot;        } while ((pndot = pnup) != NULL);    } else {        if (!js_EmitTree(cx, cg, pn2))            return JS_FALSE;    }    if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - pn2->pn_offset) < 0)        return JS_FALSE;    if (!pn->pn_atom) {        JS_ASSERT(op == JSOP_IMPORTALL);        if (js_Emit1(cx, cg, op) < 0)            return JS_FALSE;    } else {        ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);        if (!ale)            return JS_FALSE;        EMIT_ATOM_INDEX_OP(op, ALE_INDEX(ale));    }    return JS_TRUE;}static JSBoolEmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg){    ptrdiff_t top;    JSParseNode *left, *right, *next;    jsint slot;    top = CG_OFFSET(cg);    if (pn->pn_arity == PN_LIST) {        /* Left-associative operator chain to avoid too much recursion. */        JS_ASSERT(pn->pn_op == JSOP_GETELEM);        JS_ASSERT(pn->pn_count >= 3);        left = pn->pn_head;        right = PN_LAST(pn);        next = left->pn_next;        JS_ASSERT(next != right);        /*         * Try to optimize arguments[0][j]... into JSOP_ARGSUB<0> followed by         * one or more index expression and JSOP_GETELEM op pairs.         */        if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) {            if (!LookupArgOrVar(cx, &cg->treeContext, left))                return JS_FALSE;            if (left->pn_op == JSOP_ARGUMENTS &&                JSDOUBLE_IS_INT(next->pn_dval, slot) &&                (jsuint)slot < ATOM_INDEX_LIMIT) {                left->pn_offset = next->pn_offset = top;                EMIT_ATOM_INDEX_OP(JSOP_ARGSUB, (jsatomid)slot);               

⌨️ 快捷键说明

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