op = JSOP_FORNAME; if (!LookupArgOrVar(cx, &cg->treeContext, pn3, &op)) return JS_FALSE; pn3->pn_op = op;
pn3->pn_op = JSOP_FORNAME; if (!LookupArgOrVar(cx, &cg->treeContext, pn3)) return JS_FALSE; op = pn3->pn_op;
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn){    JSBool ok;    JSCodeGenerator cg2;    JSStmtInfo *stmt, stmtInfo;    ptrdiff_t top, off, tmp, beq, jmp;    JSParseNode *pn2, *pn3, *pn4;    JSAtom *atom;    JSAtomListElement *ale;    jsatomid atomIndex;    intN noteIndex;    JSOp op;    uint32 argc;    pn->pn_offset = top = CG_OFFSET(cg);    /* Emit notes to tell the current bytecode's source line number. */    UPDATE_LINENO_NOTES(cx, cg, pn);    switch (pn->pn_type) {      case TOK_FUNCTION:      {        JSFunction *fun;        /* Generate code for the function's body. */        pn2 = pn->pn_body;        if (!js_InitCodeGenerator(cx, &cg2, cg->filename,                                  pn->pn_pos.begin.lineno,                                  cg->principals)) {            return JS_FALSE;        }        cg2.treeContext.flags = pn->pn_flags;        cg2.treeContext.tryCount = pn->pn_tryCount;        fun = pn->pn_fun;        if (!js_EmitFunctionBody(cx, &cg2, pn2, fun))            return JS_FALSE;        js_FinishCodeGenerator(cx, &cg2);        /* Make the function object a literal in the outer script's pool. */        atom = js_AtomizeObject(cx, fun->object, 0);        if (!atom)            return JS_FALSE;        ale = js_IndexAtom(cx, atom, &cg->atomList);        if (!ale)            return JS_FALSE;        atomIndex = ALE_INDEX(ale);#if JS_HAS_LEXICAL_CLOSURE        /* Emit a bytecode pointing to the closure object in its immediate. */        if (pn->pn_op != JSOP_NOP) {            EMIT_ATOM_INDEX_OP(pn->pn_op, atomIndex);            break;        }#endif        /* Top-level named functions need a nop for decompilation. */        noteIndex = js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)atomIndex);        if (noteIndex < 0 ||            js_Emit1(cx, cg, JSOP_NOP) < 0) {            return JS_FALSE;        }        /* Top-levels also need a prolog op to predefine their names. */        CG_SWITCH_TO_PROLOG(cg);        EMIT_ATOM_INDEX_OP(JSOP_DEFFUN, atomIndex);        CG_SWITCH_TO_MAIN(cg);        break;      }#if JS_HAS_EXPORT_IMPORT      case TOK_EXPORT:        pn2 = pn->pn_head;        if (pn2->pn_type == TOK_STAR) {            /*             * 'export *' must have no other elements in the list (what would             * be the point?).             */            if (js_Emit1(cx, cg, JSOP_EXPORTALL) < 0)                return JS_FALSE;        } else {            /*             * If not 'export *', the list consists of NAME nodes identifying             * properties of the variable object to flag as exported.             */            do {                ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);                if (!ale)                    return JS_FALSE;                EMIT_ATOM_INDEX_OP(JSOP_EXPORTNAME, ALE_INDEX(ale));            } while ((pn2 = pn2->pn_next) != NULL);        }        break;      case TOK_IMPORT:        for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {            /*             * Each subtree on an import list is rooted by a DOT or LB node.             * A DOT may have a null pn_atom member, in which case pn_op must             * be JSOP_IMPORTALL -- see EmitPropOp above.             */            if (!js_EmitTree(cx, cg, pn2))                return JS_FALSE;        }        break;#endif /* JS_HAS_EXPORT_IMPORT */      case TOK_IF:        /* Emit code for the condition before pushing stmtInfo. */        if (!js_EmitTree(cx, cg, pn->pn_kid1))            return JS_FALSE;        js_PushStatement(&cg->treeContext, &stmtInfo, STMT_IF, CG_OFFSET(cg));        /* Emit an annotated branch-if-false around the then part. */        noteIndex = js_NewSrcNote(cx, cg, SRC_IF);        if (noteIndex < 0)            return JS_FALSE;        beq = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);        if (beq < 0)            return JS_FALSE;        /* Emit code for the then and optional else parts. */        if (!js_EmitTree(cx, cg, pn->pn_kid2))            return JS_FALSE;        pn3 = pn->pn_kid3;        if (pn3) {            /* Modify stmtInfo and the branch-if-false source note. */            stmtInfo.type = STMT_ELSE;            SN_SET_TYPE(&cg->notes[noteIndex], SRC_IF_ELSE);            /* Jump at end of then part around the else part. */            jmp = js_Emit3(cx, cg, JSOP_GOTO, 0, 0);            if (jmp < 0)                return JS_FALSE;            /* Ensure the branch-if-false comes here, then emit the else. */            CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);            if (!js_EmitTree(cx, cg, pn3))                return JS_FALSE;            /* Fixup the jump around the else part. */            CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);        } else {            /* No else part, fixup the branch-if-false to come here. */            CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);        }        return js_PopStatementCG(cx, cg);#if JS_HAS_SWITCH_STATEMENT      case TOK_SWITCH:      {        JSOp switchop;        uint32 ncases, tablen = 0;        JSScript *script;        jsint i, low, high;        jsdouble d;        size_t switchsize, tablesize;        void *mark;        JSParseNode **table;        jsbytecode *pc;        JSBool hasDefault = JS_FALSE;        JSBool isEcmaSwitch = cx->version == JSVERSION_DEFAULT ||                              cx->version >= JSVERSION_1_4;        ptrdiff_t defaultOffset = -1;        /* Try for most optimal, fall back if not dense ints, and per ECMAv2. */        switchop = JSOP_TABLESWITCH;        /* Emit code for the discriminant first. */        if (!js_EmitTree(cx, cg, pn->pn_kid1))            return JS_FALSE;        /* Switch bytecodes run from here till end of final case. */        top = CG_OFFSET(cg);        js_PushStatement(&cg->treeContext, &stmtInfo, STMT_SWITCH, top);        pn2 = pn->pn_kid2;        ncases = pn2->pn_count;        if (ncases == 0 ||            (ncases == 1 &&             (hasDefault = (pn2->pn_head->pn_type == TOK_DEFAULT)))) {            ncases = 0;            low = 0;            high = -1;            ok = JS_TRUE;        } else {            low  = JSVAL_INT_MAX;            high = JSVAL_INT_MIN;            cg2.current = NULL;            for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {                if (pn3->pn_type == TOK_DEFAULT) {                    hasDefault = JS_TRUE;                    ncases--;   /* one of the "cases" was the default */                    continue;                }                JS_ASSERT(pn3->pn_type == TOK_CASE);                pn4 = pn3->pn_left;                if (isEcmaSwitch) {                    if (switchop == JSOP_CONDSWITCH)                        continue;                    switch (pn4->pn_type) {                      case TOK_NUMBER:                        d = pn4->pn_dval;                        if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {                            pn3->pn_val = INT_TO_JSVAL(i);                        } else {                            atom = js_AtomizeDouble(cx, d, 0);                            if (!atom)                                return JS_FALSE;                            pn3->pn_val = ATOM_KEY(atom);                        }                        break;                      case TOK_STRING:                        pn3->pn_val = ATOM_KEY(pn4->pn_atom);                        break;                      case TOK_PRIMARY:                        if (pn4->pn_op == JSOP_TRUE) {                            pn3->pn_val = JSVAL_TRUE;                            break;                        }                        if (pn4->pn_op == JSOP_FALSE) {                            pn3->pn_val = JSVAL_FALSE;                            break;                        }                        /* FALL THROUGH */                      default:                        switchop = JSOP_CONDSWITCH;                        continue;                    }                } else {                    /* Pre-ECMAv2 switch evals case exprs at compile time. */                    if (!js_InitCodeGenerator(cx, &cg2, cg->filename,                                              pn3->pn_pos.begin.lineno,                                              cg->principals)) {                        return JS_FALSE;                    }                    cg2.currentLine = pn4->pn_pos.begin.lineno;                    if (!js_EmitTree(cx, &cg2, pn4))                        return JS_FALSE;                    if (js_Emit1(cx, &cg2, JSOP_POPV) < 0)                        return JS_FALSE;                    script = js_NewScriptFromCG(cx, &cg2, NULL);                    if (!script)                        return JS_FALSE;                    ok = js_Execute(cx, cx->fp->scopeChain, script, cx->fp, 0,                                    &pn3->pn_val);                    js_DestroyScript(cx, script);                    if (!ok)                        return JS_FALSE;                }                if (!JSVAL_IS_NUMBER(pn3->pn_val) &&                    !JSVAL_IS_STRING(pn3->pn_val) &&                    !JSVAL_IS_BOOLEAN(pn3->pn_val)) {                    char numBuf[12];                    JS_snprintf(numBuf, sizeof numBuf, "%u",                                pn4->pn_pos.begin.lineno);                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,                                         JSMSG_BAD_CASE,                                         cg2.filename ? cg2.filename : "stdin",                                         numBuf);                    return JS_FALSE;                }                if (switchop != JSOP_TABLESWITCH)                    continue;                if (!JSVAL_IS_INT(pn3->pn_val)) {                    switchop = JSOP_LOOKUPSWITCH;                    continue;                }                i = JSVAL_TO_INT(pn3->pn_val);                if ((jsuint)(i + (jsint)JS_BIT(15)) >= (jsuint)JS_BIT(16)) {                    switchop = JSOP_LOOKUPSWITCH;                    continue;                }                if (i < low)                    low = i;                if (high < i)                    high = i;            }            if (switchop == JSOP_CONDSWITCH) {                JS_ASSERT(!cg2.current);            } else {                if (cg2.current)                    js_FinishCodeGenerator(cx, &cg2);                if (switchop == JSOP_TABLESWITCH) {                    tablen = (uint32)(high - low + 1);                    if (tablen >= JS_BIT(16) || tablen > 2 * ncases)                        switchop = JSOP_LOOKUPSWITCH;                }            }        }        /*         * Emit a note with two offsets: first tells total switch code length,         * second tells offset to first JSOP_CASE if condswitch.         */        noteIndex = js_NewSrcNote3(cx, cg, SRC_SWITCH, 0, 0);        if (noteIndex < 0)            return JS_FALSE;        if (switchop == JSOP_CONDSWITCH) {            /*             * 0 bytes of immediate for unoptimized ECMAv2 switch.             */            switchsize = 0;        } else if (switchop == JSOP_TABLESWITCH) {            /*             * 3 offsets (len, low, high) before the table, 1 per entry.             */            switchsize = (size_t)(JUMP_OFFSET_LEN * (3 + tablen));        } else {            /*             * JSOP_LOOKUPSWITCH:             * 1 offset (len) and 1 atom index (npairs) before the table,             * 1 atom index and 1 jump offset per entry.             */            switchsize = (size_t)(JUMP_OFFSET_LEN + ATOM_INDEX_LEN +                                  (ATOM_INDEX_LEN + JUMP_OFFSET_LEN) * ncases);        }        /* Emit switchop and switchsize bytes of jump or lookup table. */        if (js_EmitN(cx, cg, switchop, switchsize) < 0)            return JS_FALSE;        off = -1;        if (switchop == JSOP_CONDSWITCH) {            intN caseNoteIndex = -1;            /* Emit code for evaluating cases and jumping to case statements. */            for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {                pn4 = pn3->pn_left;                if (pn4 && !js_EmitTree(cx, cg, pn4))                    return JS_FALSE;                if (caseNoteIndex >= 0) {                    /* off is the previous JSOP_CASE's bytecode offset. */                    if (!js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0,                                             CG_OFFSET(cg) - off)) {                        return JS_FALSE;                    }                }                if (pn3->pn_type == TOK_DEFAULT)                    continue;                caseNoteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);                if (caseNoteIndex < 0)                    return JS_FALSE;                off = js_Emit3(cx, cg, JSOP_CASE, 0, 0);                if (off < 0)                    return JS_FALSE;                pn3->pn_offset = off;                if (pn3 == pn2->pn_head) {                    /* Switch note's second offset is to first JSOP_CASE. */                    if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,                                             off - top)) {                        return JS_FALSE;                    }                }            }            /* Emit default even if no explicit default statement. */            defaultOffset = js_Emit3(cx, cg, JSOP_DEFAULT, 0, 0);            if (defaultOffset < 0)                return JS_FALSE;        }        /* Emit code for each case's statements, copying pn_offset up to pn3. */        for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {            if (switchop == JSOP_CONDSWITCH && pn3->pn_type != TOK_DEFAULT) {                pn3->pn_val = INT_TO_JSVAL(pn3->pn_offset - top);                CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, pn3->pn_offset);            }            pn4 = pn3->pn_right;            if (!js_EmitTree(cx, cg, pn4))                return JS_FALSE;            pn3->pn_offset = pn4->pn_offset;            if (pn3->pn_type == TOK_DEFAULT)                off = pn3->pn_offset - top;        }        if (!hasDefault) {            /* If no default case, offset for default is to end of switch. */            off = CG_OFFSET(cg) - top;        }        /* We better have set "off" by now. */        JS_ASSERT(off != -1);        /* Set the default offset (to end of switch if no default). */        pc = NULL;        if (switchop == JSOP_CONDSWITCH) {            JS_ASSERT(defaultOffset != -1);            if (!js_SetJumpOffset(cx, cg, CG_CODE(cg, defaultOffset),                                  off - (defaultOffset - top))) {                return JS_FALSE;            }        } else {            pc = CG_CODE(cg, top);            if (!js_SetJumpOffset(cx, cg, pc, off))                return JS_FALSE;            pc += JUMP_OFFSET_LEN;        }        /* Set the SRC_SWITCH note's offset operand to tell end of switch. */        off = CG_OFFSET(cg) - top;        if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, off))            return JS_FALSE;        if (switchop == JSOP_TABLESWITCH) {            /* Fill in jump table. */            if (!js_SetJumpOffset(cx, cg, pc, low))                return JS_FALSE;            pc += JUMP_OFFSET_LEN;            if (!js_SetJumpOffset(cx, cg, pc, high))                return JS_FALSE;            pc += JUMP_OFFSET_LEN;            if (tablen) {                /* Avoid bloat for a compilation unit with many switches. */                mark = JS_ARENA_MARK(&cx->tempPool);                tablesize = (size_t)tablen * sizeof *table;                JS_ARENA_ALLOCATE_CAST(table, JSParseNode **, &cx->tempPool,                                       tablesize);                if (!table) {                    JS_ReportOutOfMemory(cx);                    return JS_FALSE;                }                memset(table, 0, tablesize);                for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {                    if (pn3->pn_type == TOK_DEFAULT)                        continue;                    i = JSVAL_TO_INT(pn3->pn_val);                    i -= low;                    JS_ASSERT((uint32)i < tablen);                    table[i] = pn3;                }                for (i = 0; i < (jsint)tablen; i++) {                    pn3 = table[i];                    off = pn3 ? pn3->pn_offset - top : 0;                    if (!js_SetJumpOffset(cx, cg, pc, off))                        return JS_FALSE;                    pc += JUMP_OFFSET_LEN;                }                JS_ARENA_RELEASE(&cx->tempPool, mark);            }        } else if (switchop == JSOP_LOOKUPSWITCH) {            /* Fill in lookup table. */            SET_ATOM_INDEX(pc, ncases);            pc += ATOM_INDEX_LEN;            for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {                if (pn3->pn_type == TOK_DEFAULT)                    continue;                atom = js_AtomizeValue(cx, pn3->pn_val, 0);                if (!atom)                    return JS_FALSE;                ale = js_IndexAtom(cx, atom, &cg->atomList);                if (!ale)                    return JS_FALSE;                SET_ATOM_INDEX(pc, ALE_INDEX(ale));                pc += ATOM_INDEX_LEN;                off = pn3->pn_offset - top;                if (!js_SetJumpOffset(cx, cg, pc, off))                    return JS_FALSE;                pc += JUMP_OFFSET_LEN;            }        }        return js_PopStatementCG(cx, cg);      }#endif /* JS_HAS_SWITCH_STATEMENT */      case TOK_WHILE:        js_PushStatement(&cg->treeContext, &stmtInfo, STMT_WHILE_LOOP, top);        if (!js_EmitTree(cx, cg, pn->pn_left))            return JS_FALSE;        noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);        if (noteIndex < 0)            return JS_FALSE;        beq = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);        if (beq < 0)            return JS_FALSE;        if (!js_EmitTree(cx, cg, pn->pn_right))            return JS_FALSE;        jmp = js_Emit3(cx, cg, JSOP_GOTO, 0, 0);        if (jmp < 0)            return JS_FALSE;        CHECK_AND_SET_JUMP_OFFSET(cx, cg, CG_CODE(cg,jmp), top - jmp);        CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);        return js_PopStatementCG(cx, cg);#if JS_HAS_DO_WHILE_LOOP      case TOK_DO:        /* Emit an annotated nop so we know to decompile a 'do' keyword. */        if (js_NewSrcNote(cx, cg, SRC_WHILE) < 0 ||            js_Emit1(cx, cg, JSOP_NOP) < 0) {            return JS_FALSE;        }        /* Compile the loop body. */        top = CG_OFFSET(cg);        js_PushStatement(&cg->treeContext, &stmtInfo, STMT_DO_LOOP, top);        if (!js_EmitTree(cx, cg, pn->pn_left))            return JS_FALSE;        /* Set loop and enclosing label update offsets, for continue. */        stmt = &stmtInfo;        do {            stmt->update = CG_OFFSET(cg);        } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);        /* Compile the loop condition, now that continues know where to go. */        if (!js_EmitTree(cx, cg, pn->pn_right))            return JS_FALSE;        /* Re-use the SRC_WHILE note, this time for the JSOP_IFNE opcode. */        if (js_NewSrcNote(cx, cg, SRC_WHILE) < 0)            return JS_FALSE;        jmp = top - CG_OFFSET(cg);        if (js_Emit3(cx, cg, JSOP_IFNE,                     JUMP_OFFSET_HI(jmp), JUMP_OFFSET_LO(jmp)) < 0) {            return JS_FALSE;        }        return js_PopStatementCG(cx, cg);#endif /* JS_HAS_DO_WHILE_LOOP */      case TOK_FOR:        pn2 = pn->pn_left;        js_PushStatement(&cg->treeContext, &stmtInfo, STMT_FOR_LOOP, top);        if (pn2->pn_type == TOK_IN) {            /* If the left part is var x = i, bind x, evaluate i, and pop. */            pn3 = pn2->pn_left;            if (pn3->pn_type == TOK_VAR && pn3->pn_head->pn_expr) {                if (!js_EmitTree(cx, cg, pn3))                    return JS_FALSE;                /* Set pn3 to the variable name, to avoid another var note. */                pn3 = pn3->pn_head;                JS_ASSERT(pn3->pn_type == TOK_NAME);            }            /* Fix stmtInfo and emit a push to allocate the iterator. */            stmtInfo.type = STMT_FOR_IN_LOOP;            noteIndex = -1;            if (js_Emit1(cx, cg, JSOP_PUSH) < 0)                return JS_FALSE;            /* Compile the object expression to the right of 'in'. */            if (!js_EmitTree(cx, cg, pn2->pn_right))                return JS_FALSE;            if (js_Emit1(cx, cg, JSOP_TOOBJECT) < 0)                return JS_FALSE;            top = CG_OFFSET(cg);            SET_STATEMENT_TOP(&stmtInfo, top);            /* Compile a JSOP_FOR* bytecode based on the left hand side. */            switch (pn3->pn_type) {              case TOK_VAR:                pn3 = pn3->pn_head;                if (js_NewSrcNote(cx, cg, SRC_VAR) < 0)                    return JS_FALSE;                /* FALL THROUGH */              case TOK_NAME:                op = JSOP_FORNAME;                if (!LookupArgOrVar(cx, &cg->treeContext, pn3, &op))                    return JS_FALSE;                pn3->pn_op = op;                if (pn3->pn_slot >= 0) {                    if (pn3->pn_attrs & JSPROP_READONLY)                        op = JSOP_GETVAR;                    atomIndex = (jsatomid) pn3->pn_slot;                    EMIT_ATOM_INDEX_OP(op, atomIndex);                } else {                    if (!EmitAtomOp(cx, pn3, op, cg))                        return JS_FALSE;                }                break;              case TOK_DOT:                if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg))                    return JS_FALSE;                break;              case TOK_LB:                /*                 * We separate the first/next bytecode from the enumerator                 * variable binding to avoid any side-effects in the index                 * expression (e.g., for (x[i++] in {}) should not bind x[i]                 * or increment i at all).                 */                if (!js_Emit1(cx, cg, JSOP_FORELEM))                    return JS_FALSE;                beq = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);                if (beq < 0)                    return JS_FALSE;                if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))                    return JS_FALSE;                break;              default:                JS_ASSERT(0);            }            if (pn3->pn_type != TOK_LB) {                /* Pop and test the loop condition generated by JSOP_FOR*. */                beq = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);                if (beq < 0)                    return JS_FALSE;            }        } else {