if (pn2->pn_type == TOK_LC) { if (!js_Emit1(cx, cg, JSOP_JSEXPR) < 0) return JS_FALSE; }
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn){    JSBool ok, useful, wantval;    JSStmtInfo *stmt, stmtInfo;    ptrdiff_t top, off, tmp, beq, jmp;    JSParseNode *pn2, *pn3;    JSAtom *atom;    JSAtomListElement *ale;    jsatomid atomIndex;    intN noteIndex;    JSSrcNoteType noteType;    jsbytecode *pc;    JSOp op;    uint32 argc;    int stackDummy;    if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);        return JS_FALSE;    }    ok = JS_TRUE;    cg->emitLevel++;    pn->pn_offset = top = CG_OFFSET(cg);    /* Emit notes to tell the current bytecode's source line number. */    UPDATE_LINE_NUMBER_NOTES(cx, cg, pn);    switch (pn->pn_type) {      case TOK_FUNCTION:      {        void *cg2mark;        JSCodeGenerator *cg2;        JSFunction *fun;#if JS_HAS_XML_SUPPORT        if (pn->pn_arity == PN_NULLARY) {            if (js_Emit1(cx, cg, JSOP_GETFUNNS) < 0)                return JS_FALSE;            break;        }#endif        /* Generate code for the function's body. */        cg2mark = JS_ARENA_MARK(&cx->tempPool);        JS_ARENA_ALLOCATE_TYPE(cg2, JSCodeGenerator, &cx->tempPool);        if (!cg2) {            JS_ReportOutOfMemory(cx);            return JS_FALSE;        }        if (!js_InitCodeGenerator(cx, cg2, cg->codePool, cg->notePool,                                  cg->filename, pn->pn_pos.begin.lineno,                                  cg->principals)) {            return JS_FALSE;        }        cg2->treeContext.flags = (uint16) (pn->pn_flags | TCF_IN_FUNCTION);        cg2->treeContext.tryCount = pn->pn_tryCount;        cg2->parent = cg;        fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(pn->pn_funAtom));        if (!js_EmitFunctionBody(cx, cg2, pn->pn_body, fun))            return JS_FALSE;        /*         * We need an activation object if an inner peeks out, or if such         * inner-peeking caused one of our inners to become heavyweight.         */        if (cg2->treeContext.flags &            (TCF_FUN_USES_NONLOCALS | TCF_FUN_HEAVYWEIGHT)) {            cg->treeContext.flags |= TCF_FUN_HEAVYWEIGHT;        }        js_FinishCodeGenerator(cx, cg2);        JS_ARENA_RELEASE(&cx->tempPool, cg2mark);        /* Make the function object a literal in the outer script's pool. */        ale = js_IndexAtom(cx, pn->pn_funAtom, &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 in the         * variable object, or if local, to fill their stack slots.         */        CG_SWITCH_TO_PROLOG(cg);#if JS_HAS_LEXICAL_CLOSURE        if (cg->treeContext.flags & TCF_IN_FUNCTION) {            JSObject *obj, *pobj;            JSProperty *prop;            JSScopeProperty *sprop;            uintN slot;            obj = OBJ_GET_PARENT(cx, fun->object);            if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(fun->atom),                                         &pobj, &prop)) {                return JS_FALSE;            }            JS_ASSERT(prop && pobj == obj);            sprop = (JSScopeProperty *) prop;            JS_ASSERT(sprop->getter == js_GetLocalVariable);            slot = sprop->shortid;            OBJ_DROP_PROPERTY(cx, pobj, prop);            if (atomIndex >= JS_BIT(16)) {                /*                 * Lots of literals in the outer function, so we have to emit                 * [JSOP_LITOPX, atomIndex, JSOP_DEFLOCALFUN, var slot].                 */                off = js_EmitN(cx, cg, JSOP_LITOPX, 3);                if (off < 0)                    return JS_FALSE;                pc = CG_CODE(cg, off);                SET_LITERAL_INDEX(pc, atomIndex);                EMIT_UINT16_IMM_OP(JSOP_DEFLOCALFUN, slot);            } else {                /* Emit [JSOP_DEFLOCALFUN, var slot, atomIndex]. */                off = js_EmitN(cx, cg, JSOP_DEFLOCALFUN,                               VARNO_LEN + ATOM_INDEX_LEN);                if (off < 0)                    return JS_FALSE;                pc = CG_CODE(cg, off);                SET_VARNO(pc, slot);                pc += VARNO_LEN;                SET_ATOM_INDEX(pc, atomIndex);            }        } else#endif            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 variables 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:        /* Initialize so we can detect else-if chains and avoid recursion. */        stmtInfo.type = STMT_IF;        beq = jmp = -1;        noteIndex = -1;      if_again:        /* Emit code for the condition before pushing stmtInfo. */        if (!js_EmitTree(cx, cg, pn->pn_kid1))            return JS_FALSE;        if (stmtInfo.type == STMT_IF) {            js_PushStatement(&cg->treeContext, &stmtInfo, STMT_IF,                             CG_OFFSET(cg));        } else {            /*             * We came here from the goto further below that detects else-if             * chains, so we must mutate stmtInfo back into a STMT_IF record.             * Also (see below for why) we need a note offset for SRC_IF_ELSE             * to help the decompiler.             */            JS_ASSERT(stmtInfo.type == STMT_ELSE);            stmtInfo.type = STMT_IF;            if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))                return JS_FALSE;        }        /* Emit an annotated branch-if-false around the then part. */        pn3 = pn->pn_kid3;        noteIndex = js_NewSrcNote(cx, cg, pn3 ? SRC_IF_ELSE : SRC_IF);        if (noteIndex < 0)            return JS_FALSE;        beq = EmitJump(cx, cg, JSOP_IFEQ, 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;        if (pn3) {            /* Modify stmtInfo so we know we're in the else part. */            stmtInfo.type = STMT_ELSE;            /*             * Emit a JSOP_BACKPATCH op to jump from the end of our then part             * around the else part.  The js_PopStatementCG call at the bottom             * of this switch case will fix up the backpatch chain linked from             * stmtInfo.breaks.             */            jmp = EmitGoto(cx, cg, &stmtInfo, &stmtInfo.breaks, NULL, SRC_NULL);            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 (pn3->pn_type == TOK_IF) {                pn = pn3;                goto if_again;            }            if (!js_EmitTree(cx, cg, pn3))                return JS_FALSE;            /*             * Annotate SRC_IF_ELSE with the offset from branch to jump, for             * the decompiler's benefit.  We can't just "back up" from the pc             * of the else clause, because we don't know whether an extended             * jump was required to leap from the end of the then clause over             * the else clause.             */            if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))                return JS_FALSE;        } else {            /* No else part, fixup the branch-if-false to come here. */            CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);        }        ok = js_PopStatementCG(cx, cg);        break;#if JS_HAS_SWITCH_STATEMENT      case TOK_SWITCH:        /* Out of line to avoid bloating js_EmitTree's stack frame size. */        ok = EmitSwitch(cx, cg, pn, &stmtInfo);        break;#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 = EmitJump(cx, cg, JSOP_IFEQ, 0);        if (beq < 0)            return JS_FALSE;        if (!js_EmitTree(cx, cg, pn->pn_right))            return JS_FALSE;        jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg));        if (jmp < 0)            return JS_FALSE;        CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);        if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))            return JS_FALSE;        ok = js_PopStatementCG(cx, cg);        break;#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;        /*         * No source note needed, because JSOP_IFNE is used only for do-while.         * If we ever use JSOP_IFNE for other purposes, we can still avoid yet         * another note here, by storing (jmp - top) in the SRC_WHILE note's         * offset, and fetching that delta in order to decompile recursively.         */        if (EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg)) < 0)            return JS_FALSE;        ok = js_PopStatementCG(cx, cg);        break;#endif /* JS_HAS_DO_WHILE_LOOP */      case TOK_FOR:        beq = 0;                /* suppress gcc warnings */        pn2 = pn->pn_left;        js_PushStatement(&cg->treeContext, &stmtInfo, STMT_FOR_LOOP, top);        if (pn2->pn_type == TOK_IN) {            JSBool emitIFEQ;            /* Set stmtInfo type for later testing. */            stmtInfo.type = STMT_FOR_IN_LOOP;            noteIndex = -1;            /*             * If the left part is 'var x', emit code to define x if necessary             * using a prolog opcode, but do not emit a pop.  If the left part             * is 'var x = i', emit prolog code to define x if necessary; then             * emit code to evaluate i, assign the result to x, and pop the             * result off the stack.             *             * All the logic to do this is implemented in the outer switch's             * TOK_VAR case, conditioned on pn_extra flags set by the parser.             *             * In the 'for (var x = i in o) ...' case, the js_EmitTree(...pn3)             * called here will generate the SRC_VAR note for the assignment             * op that sets x = i, hoisting the initialized var declaration             * out of the loop: 'var x = i; for (x in o) ...'.             *             * In the 'for (var x in o) ...' case, nothing but the prolog op             * (if needed) should be generated here, we must emit the SRC_VAR             * just before the JSOP_FOR* opcode in the switch on pn3->pn_type             * a bit below, so nothing is hoisted: 'for (var x in o) ...'.             */            pn3 = pn2->pn_left;            if (pn3->pn_type == TOK_VAR && !js_EmitTree(cx, cg, pn3))                return JS_FALSE;            /* Emit a push to allocate the iterator. */            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);#if JS_HAS_XML_SUPPORT            /* Emit a prefix opcode if 'for each (... in ...)' was used. */            if (pn->pn_op != JSOP_NOP && js_Emit1(cx, cg, pn->pn_op) < 0)                return JS_FALSE;#endif            /* Compile a JSOP_FOR* bytecode based on the left hand side. */            emitIFEQ = JS_TRUE;            switch (pn3->pn_type) {              case TOK_VAR:                pn3 = pn3->pn_head;                JS_ASSERT(pn3->pn_type == TOK_NAME);                if (!pn3->pn_expr && js_NewSrcNote(cx, cg, SRC_VAR) < 0)                    return JS_FALSE;                /* FALL THROUGH */              case TOK_NAME:                if (pn3->pn_slot >= 0) {                    op = pn3->pn_op;                    switch (op) {                      case JSOP_GETARG:  /* FALL THROUGH */                      case JSOP_SETARG:  op = JSOP_FORARG; break;                      case JSOP_GETVAR:  /* FALL THROUGH */                      case JSOP_SETVAR:  op = JSOP_FORVAR; break;                      case JSOP_GETGVAR:                      case JSOP_SETGVAR: op = JSOP_FORNAME; break;                      default:           JS_ASSERT(0);                    }                } else {                    pn3->pn_op = JSOP_FORNAME;                    if (!LookupArgOrVar(cx, &cg->treeContext, pn3))                        return JS_FALSE;                    op = pn3->pn_op;                }                if (pn3->pn_slot >= 0) {                    if (pn3->pn_attrs & JSPROP_READONLY)                        op = JSOP_GETVAR;                    atomIndex = (jsatomid) pn3->pn_slot;                    EMIT_UINT16_IMM_OP(op, atomIndex);                } else {                    if (!EmitAtomOp(cx, pn3, op, cg))                        return JS_FALSE;                }                break;              case TOK_DOT:                useful = JS_TRUE;                if (!CheckSideEffects(cx, &cg->treeContext, pn3->pn_expr,                                      &useful)) {                    return JS_FALSE;                }                if (!useful) {                    if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg))                        return JS_FALSE;                    break;                }                /* FALL THROUGH */              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).                 */                emitIFEQ = JS_FALSE;                if (!js_Emit1(cx, cg, JSOP_FORELEM))                    return JS_FALSE;                /*                 * Emit a SRC_WHILE note with offset telling the distance to                 * the loop-closing jump (we can't reckon from the branch at                 * the top of the loop, because the loop-closing jump might                 * need to be an extended jump, independent of whether the                 * branch is short or long).                 */                noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);                if (noteIndex < 0)                    return JS_FALSE;                beq = EmitJump(cx, cg, JSOP_IFEQ, 0);                if (beq < 0)                    return JS_FALSE;                /* Now that we're safely past the IFEQ, commit side effects. */                if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))                    return JS_FALSE;                break;              default:                JS_ASSERT(0);            }            if (emitIFEQ) {                /* Annotate so the decompiler can find the loop-closing jump. */                noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);                if (noteIndex < 0)                    return JS_FALSE;                /* Pop and test the loop condition generated by JSOP_FOR*. */                beq = EmitJump(cx, cg, JSOP_IFEQ, 0);                if (beq < 0)                    return JS_FALSE;            }        } else {            if (!pn2->pn_kid1) {                /* No initializer: emit an annotated nop for the decompiler. */                op = JSOP_NOP;            } else {                if (!js_EmitTree(cx, cg, pn2->pn_kid1))                    return JS_FALSE;                op = JSOP_POP;            }            noteIndex = js_NewSrcNote(cx, cg, SRC_FOR);            if (noteIndex < 0 ||                js_Emit1(cx, cg, op) < 0) {                return JS_FALSE;            }            top = CG_OFFSET(cg);            SET_STATEMENT_TOP(&stmtInfo, top);            if (!pn2->pn_kid2) {                /* No loop condition: flag this fact in the source notes. */                if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, 0))                    return JS_FALSE;            } else {                if (!js_EmitTree(cx, cg, pn2->pn_kid2))                    return JS_FALSE;                if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,                                         CG_OFFSET(cg) - top)) {                    return JS_FALSE;                }                beq = EmitJump(cx, cg, JSOP_IFEQ, 0);                if (beq < 0)                    return JS_FALSE;            }            /* Set pn3 (used below) here to avoid spurious gcc warnings. */            pn3 = pn2->pn_kid3;        }        /* Emit code for the loop body. */        if (!js_EmitTree(cx, cg, pn->pn_right))            return JS_FALSE;        if (pn2->pn_type != TOK_IN) {            /* Set the second note offset so we can find the update part. */            JS_ASSERT(noteIndex != -1);            if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,                                     CG_OFFSET(cg) - top)) {                return JS_FALSE;            }            if (pn3) {                /* Set loop and enclosing "update" offsets, for continue. */                stmt = &stmtInfo;                do {                    stmt->update = CG_OFFSET(cg);                } while ((stmt = stmt->down) != NULL &&                         stmt->type == STMT_LABEL);                if (!js_EmitTree(cx, cg, pn3))                    return JS_FALSE;                if (js_Emit1(cx, cg, JSOP_POP) < 0)                    return JS_FALSE;                /* Restore the absolute line number for source note readers. */                off = (ptrdiff_t) pn->pn_pos.end.lineno;                if (CG_CURRENT_LINE(cg) != (uintN) off) {                    if (js_NewSrcNote2(cx, cg, SRC_SETLINE, off) < 0)                        return JS_FALSE;                    CG_CURRENT_LINE(cg) = (uintN) off;                }            }            /* The third note offset helps us find the loop-closing jump. */            if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2,                                     CG_OFFSET(cg) - top)) {                return JS_FALSE;            }        }        /* Emit the loop-closing jump and fixup all jump offsets. */        jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg));        if (jmp < 0)            return JS_FALSE;        if (beq > 0)            CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);        if (pn2->pn_type == TOK_IN) {            /* Set the SRC_WHILE note offset so we can find the closing jump. */            JS_ASSERT(noteIndex != -1);            if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, jmp - beq))                return JS_FALSE;        }        /* Now fixup all breaks and continues (before for/in's final POP2). */        if (!js_PopStatementCG(cx, cg))            return JS_FALSE;        if (pn2->pn_type == TOK_IN) {            if (js_Emit1(cx, cg, JSOP_POP2) < 0)                return JS_FALSE;        }        break;      case TOK_BREAK:        stmt = cg->treeContext.topStmt;        atom = pn->pn_atom;        if (atom) {            ale = js_IndexAtom(cx, atom, &cg->atomList);            if (!ale)                return JS_FALSE;            while (stmt->type != STMT_LABEL || stmt->label != atom)                stmt = stmt->down;            noteType = SRC_BREAK2LABEL;        } else {            ale = NULL;            while (!STMT_IS_LOOP(stmt) && stmt->type != STMT_SWITCH)                stmt = stmt->down;            noteType = SRC_NULL;        }        if (EmitGoto(cx, cg, stmt, &stmt->breaks, ale, noteType) < 0)            return JS_FALSE;        break;      case TOK_CONTINUE:        stmt = cg->treeContext.topStmt;        atom = pn->pn_atom;        if (atom) {            /* Find the loop statement enclosed by the matching label. */            JSStmtInfo *loop = NULL;            ale = js_IndexAtom(cx, atom, &cg->atomList);            if (!ale)                return JS_FALSE;            while (stmt->type != STMT_LABEL || stmt->label != atom) {                if (STMT_IS_LOOP(stmt))                    loop = stmt;                stmt = stmt->down;            }            stmt = loop;            noteType = SRC_CONT2LABEL;        } else {            ale = NULL;            while (!STMT_IS_LOOP(stmt))                stmt = stmt->down;            noteType = SRC_CONTINUE;        }        if (EmitGoto(cx, cg, stmt, &stmt->continues, ale, noteType) < 0)            return JS_FALSE;        break;      case TOK_WITH:        if (!js_EmitTree(cx, cg, pn->pn_left))            return JS_FALSE;        js_PushStatement(&cg->treeContext, &stmtInfo, STMT_WITH, CG_OFFSET(cg));        if (js_Emit1(cx, cg, JSOP_ENTERWITH) < 0)            return JS_FALSE;        if (!js_EmitTree(cx, cg, pn->pn_right))            return JS_FALSE;        if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0)            return JS_FALSE;        ok = js_PopStatementCG(cx, cg);        break;#if JS_HAS_EXCEPTIONS      case TOK_TRY:      {        ptrdiff_t start, end, catchStart, finallyCatch, catchJump;        JSParseNode *iter;        intN depth;        /* Quell GCC overwarnings. */        end = catchStart = finallyCatch = catchJump = -1;        /*         * Push stmtInfo to track jumps-over-catches and gosubs-to-finally         * for later fixup.         *         * When a finally block is `active' (STMT_FINALLY on the treeContext),         * non-local jumps (including jumps-over-catches) result in a GOSUB         * being written into the bytecode stream and fixed-up later (c.f.         * EmitBackPatchOp and BackPatch).         */        js_PushStatement(&cg->treeContext, &stmtInfo,                         pn->pn_kid3 ? STMT_FINALLY : STMT_BLOCK,                         CG_OFFSET(cg));        /*         * About JSOP_SETSP: an exception can be thrown while the stack is in         * an unbalanced state, and this imbalance causes problems with things         * like function invocation later on.         *         * To fix this, we compute the `balanced' stack depth upon try entry,         * and then restore the stack to this depth when we hit the first catch         * or finally block.  We can't just zero the stack, because things like         * for/in and with that are active upon entry to the block keep state         * variables on the stack.         */        depth = cg->stackDepth;        /* Mark try location for decompilation, then emit try block. */        if (js_Emit1(cx, cg, JSOP_TRY) < 0)            return JS_FALSE;        start = CG_OFFSET(cg);        if (!js_EmitTree(cx, cg, pn->pn_kid1))            return JS_FALSE;        /* GOSUB to finally, if present. */        if (pn->pn_kid3) {            if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)                return JS_FALSE;            jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH_PUSH, &stmtInfo.gosub);            if (jmp < 0)                return JS_FALSE;        }        /* Emit (hidden) jump over catch and/or finally. */        if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)            return JS_FALSE;        jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &stmtInfo.catchJump);        if (jmp < 0)            return JS_FALSE;        end = CG_OFFSET(cg);        /* If this try has a catch block, emit it. */        iter = pn->pn_kid2;        if (iter) {            catchStart = end;            /*             * The emitted code for a catch block looks like:             *             * [ popscope ]                        only if 2nd+ catch block             * name Object             * pushobj             * newinit             * exception             * initcatchvar <atom>             * enterwith             * [< catchguard code >]               if there's a catchguard             * [ifeq <offset to next catch block>]         " "             * < catch block contents >             * leavewith             * goto <end of catch blocks>          non-local; finally applies             *             * If there's no catch block without a catchguard, the last             * <offset to next catch block> points to rethrow code.  This             * code will GOSUB to the finally code if appropriate, and is             * also used for the catch-all trynote for capturing exceptions             * thrown from catch{} blocks.             */            for (;;) {                JSStmtInfo stmtInfo2;                JSParseNode *disc;                ptrdiff_t guardnote;                if (!UpdateLineNumberNotes(cx, cg, iter))                    return JS_FALSE;                if (catchJump != -1) {                    /* Fix up and clean up previous catch block. */                    CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchJump);                    /* Compensate for the [leavewith]. */                    cg->stackDepth++;                    JS_ASSERT((uintN) cg->stackDepth <= cg->maxStackDepth);                    if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||                        js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) {                        return JS_FALSE;                    }                } else {                    /* Set stack to original depth (see SETSP comment above). */                    EMIT_UINT16_IMM_OP(JSOP_SETSP, (jsatomid)depth);                    cg->stackDepth = depth;                }                /* Non-negative guardnote offset is length of catchguard. */                guardnote = js_NewSrcNote2(cx, cg, SRC_CATCH, 0);                if (guardnote < 0 ||                    js_Emit1(cx, cg, JSOP_NOP) < 0) {                    return JS_FALSE;                }                /* Construct the scope holder and push it on. */                ale = js_IndexAtom(cx, cx->runtime->atomState.ObjectAtom,                                   &cg->atomList);                if (!ale)                    return JS_FALSE;                EMIT_ATOM_INDEX_OP(JSOP_NAME, ALE_INDEX(ale));                if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0 ||                    js_Emit1(cx, cg, JSOP_NEWINIT) < 0 ||                    js_Emit1(cx, cg, JSOP_EXCEPTION) < 0) {                    return JS_FALSE;                }                /* initcatchvar <atomIndex> */                disc = iter->pn_kid1;                ale = js_IndexAtom(cx, disc->pn_atom, &cg->atomList);                if (!ale)                    return JS_FALSE;                EMIT_ATOM_INDEX_OP(JSOP_INITCATCHVAR, ALE_INDEX(ale));                if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||                    js_Emit1(cx, cg, JSOP_ENTERWITH) < 0) {                    return JS_FALSE;                }                /* boolean_expr */                if (disc->pn_expr) {                    ptrdiff_t guardstart = CG_OFFSET(cg);                    if (!js_EmitTree(cx, cg, disc->pn_expr))                        return JS_FALSE;                    if (!js_SetSrcNoteOffset(cx, cg, guardnote, 0,                                             CG_OFFSET(cg) - guardstart)) {                        return JS_FALSE;                    }                    /* ifeq <next block> */                    catchJump = EmitJump(cx, cg, JSOP_IFEQ, 0);                    if (catchJump < 0)                        return JS_FALSE;                }                /* Emit catch block. */                js_PushStatement(&cg->treeContext, &stmtInfo2, STMT_CATCH,                                 CG_OFFSET(cg));                stmtInfo2.label = disc->pn_atom;                if (!js_EmitTree(cx, cg, iter->pn_kid3))                    return JS_FALSE;                js_PopStatementCG(cx, cg);                /*                 * Jump over the remaining catch blocks.                 * This counts as a non-local jump, so do the finally thing.                 */                /* leavewith, annotated so the decompiler knows to pop  */                off = cg->stackDepth - 1;                if (js_NewSrcNote2(cx, cg, SRC_CATCH, off) < 0 ||                    js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) {                    return JS_FALSE;                }                /* gosub <finally>, if required */                if (pn->pn_kid3) {                    jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH_PUSH,                                          &stmtInfo.gosub);                    if (jmp < 0)                        return JS_FALSE;                }                /* This will get fixed up to jump to after catch/finally. */                if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)                    return JS_FALSE;                jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH,                                      &stmtInfo.catchJump);                if (jmp < 0)                    return JS_FALSE;                if (!iter->pn_kid2)     /* leave iter at last catch */                    break;                iter = iter->pn_kid2;            }        }        /*         * We use a [setsp],[gosub],rethrow block for rethrowing when         * there's no unguarded catch, and also for running finally code         * while letting an uncaught exception pass through.         */        if (pn->pn_kid3 ||            (catchJump != -1 && iter->pn_kid1->pn_expr)) {            /*             * Emit another stack fixup, because the catch could itself             * throw an exception in an unbalanced state, and the finally             * may need to call functions.  If there is no finally, only             * guarded catches, the rethrow code below nevertheless needs             * stack fixup.             */            finallyCatch = CG_OFFSET(cg);            EMIT_UINT16_IMM_OP(JSOP_SETSP, (jsatomid)depth);            cg->stackDepth = depth;            /* Last discriminant jumps to rethrow if none match. */            if (catchJump != -1 && iter->pn_kid1->pn_expr)                CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchJump);            if (pn->pn_kid3) {                jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH_PUSH,                                      &stmtInfo.gosub);                if (jmp < 0)                    return JS_FALSE;                cg->stackDepth = depth;            }            if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||                js_Emit1(cx, cg, JSOP_EXCEPTION) < 0 ||                js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||                js_Emit1(cx, cg, JSOP_THROW) < 0) {                return JS_FALSE;            }            JS_ASSERT(cg->stackDepth == depth);        }        /*         * If we have a finally, it belongs here, and we have to fix up the         * gosubs that might have been emitted before non-local jumps.         */        if (pn->pn_kid3) {            if (!BackPatch(cx, cg, stmtInfo.gosub, CG_NEXT(cg), JSOP_GOSUB))                return JS_FALSE;            /*             * The stack budget must be balanced at this point, and we need             * one more slot for the JSOP_RETSUB return address pushed by a             * JSOP_GOSUB opcode that calls this finally clause.             */            JS_ASSERT(cg->stackDepth == depth);            if ((uintN)++cg->stackDepth > cg->maxStackDepth)                cg->maxStackDepth = cg->stackDepth;            /* Now indicate that we're emitting a subroutine body. */            stmtInfo.type = STMT_SUBROUTINE;            if (!UpdateLineNumberNotes(cx, cg, pn->pn_kid3))                return JS_FALSE;            if (js_Emit1(cx, cg, JSOP_FINALLY) < 0 ||                !js_EmitTree(cx, cg, pn->pn_kid3) ||                js_Emit1(cx, cg, JSOP_RETSUB) < 0) {                return JS_FALSE;            }        }        js_PopStatementCG(cx, cg);        if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 ||            js_Emit1(cx, cg, JSOP_NOP) < 0) {            return JS_FALSE;        }        /* Fix up the end-of-try/catch jumps to come here. */        if (!BackPatch(cx, cg, stmtInfo.catchJump, CG_NEXT(cg), JSOP_GOTO))            return JS_FALSE;        /*         * Add the try note last, to let post-order give us the right ordering         * (first to last for a given nesting level, inner to outer by level).         */        if (pn->pn_kid2) {            JS_ASSERT(end != -1 && catchStart != -1);            if (!js_NewTryNote(cx, cg, start, end, catchStart))                return JS_FALSE;        }        /*         * If we've got a finally, mark try+catch region with additional         * trynote to catch exceptions (re)thrown from a catch block or         * for the try{}finally{} case.         */        if (pn->pn_kid3) {            JS_ASSERT(finallyCatch != -1);            if (!js_NewTryNote(cx, cg, start, finallyCatch, finallyCatch))                return JS_FALSE;        }        break;      }#endif /* JS_HAS_EXCEPTIONS */      case TOK_VAR:        off = noteIndex = -1;        for (pn2 = pn->pn_head; ; pn2 = pn2->pn_next) {            JS_ASSERT(pn2->pn_type == TOK_NAME);            if (!LookupArgOrVar(cx, &cg->treeContext, pn2))                return JS_FALSE;            op = pn2->pn_op;            if (op == JSOP_ARGUMENTS) {                JS_ASSERT(!pn2->pn_expr); /* JSOP_ARGUMENTS => no initializer */#ifdef __GNUC__                atomIndex = 0;            /* quell GCC overwarning */#endif            } else {                if (pn2->pn_slot >= 0) {                    atomIndex = (jsatomid) pn2->pn_slot;                } else {                    ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);                    if (!ale)                        return JS_FALSE;                    atomIndex = ALE_INDEX(ale);                }                if ((js_CodeSpec[op].format & JOF_TYPEMASK) == JOF_CONST &&                    (!(cg->treeContext.flags & TCF_IN_FUNCTION) ||                     (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT))) {                    /* Emit a prolog bytecode to predefine the variable. */                    CG_SWITCH_TO_PROLOG(cg);                    if (!UpdateLineNumberNotes(cx, cg, pn2))                        return JS_FALSE;                    EMIT_ATOM_INDEX_OP(pn->pn_op, atomIndex);                    CG_SWITCH_TO_MAIN(cg);                }                if (pn2->pn_expr) {                    if (op == JSOP_SETNAME)                        EMIT_ATOM_INDEX_OP(JSOP_BINDNAME, atomIndex);                    pn3 = pn2->pn_expr;                    if (pn->pn_op == JSOP_DEFCONST &&                        !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom,                                                      pn3)) {                        return JS_FALSE;                    }                    if (!js_EmitTree(cx, cg, pn3))                        return JS_FALSE;                }            }            /*             * 'for (var x in o) ...' and 'for (var x = i in o) ...' call the             * TOK_VAR case, but only the initialized case (a strange one that             * falls out of ECMA-262's grammar) wants to run past this point.             * Both cases must conditionally emit a JSOP_DEFVAR, above.  Note             * that the parser error-checks to ensure that pn->pn_count is 1.             *             * XXX Narcissus keeps track of variable declarations in the node             * for the script being compiled, so there's no need to share any             * conditional prolog code generation there.  We could do likewise,             * but it's a big change, requiring extra allocation, so probably             * not worth the trouble for SpiderMonkey.             */            if ((pn->pn_extra & PNX_FORINVAR) && !pn2->pn_expr)                break;            if (pn2 == pn->pn_head &&                js_NewSrcNote(cx, cg,                              (pn->pn_op == JSOP_DEFCONST)                              ? SRC_CONST                              : SRC_VAR) < 0) {                return JS_FALSE;            }            if (op == JSOP_ARGUMENTS) {                if (js_Emit1(cx, cg, op) < 0)                    return JS_FALSE;            } else if (pn2->pn_slot >= 0) {                EMIT_UINT16_IMM_OP(op, atomIndex);            } else {                EMIT_ATOM_INDEX_OP(op, atomIndex);            }            tmp = CG_OFFSET(cg);            if (noteIndex >= 0) {                if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))                    return JS_FALSE;            }            if (!pn2->pn_next)                break;            off = tmp;            noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);            if (noteIndex < 0 ||                js_Emit1(cx, cg, JSOP_POP) < 0) {                return JS_FALSE;            }        }        if (pn->pn_extra & PNX_POPVAR) {            if (js_Emit1(cx, cg, JSOP_POP) < 0)                return JS_FALSE;        }        break;      case TOK_RETURN:        /* Push a return value */        pn2 = pn->pn_kid;        if (pn2) {            if (!js_EmitTree(cx, cg, pn2))                return JS_FALSE;        } else {            if (js_Emit1(cx, cg, JSOP_PUSH) < 0)                return JS_FALSE;        }        /*         * EmitNonLocalJumpFixup mutates op to JSOP_RETRVAL after emitting a         * JSOP_SETRVAL if there are open try blocks having finally clauses.         * We can't simply transfer control flow to our caller in that case,         * because we must gosub to those clauses from inner to outer, with         * the correct stack pointer (i.e., after popping any with, for/in,         * etc., slots nested inside the finally's try).         */        op = JSOP_RETURN;        if (!EmitNonLocalJumpFixup(cx, cg, NULL, &op))            return JS_FALSE;        if (js_Emit1(cx, cg, op) < 0)            return JS_FALSE;        break;      case TOK_LC:#if JS_HAS_XML_SUPPORT        if (pn->pn_arity == PN_UNARY) {            if (!js_EmitTree(cx, cg, pn->pn_kid))                return JS_FALSE;            if (js_Emit1(cx, cg, pn->pn_op) < 0)                return JS_FALSE;            break;        }#endif        JS_ASSERT(pn->pn_arity == PN_LIST);        js_PushStatement(&cg->treeContext, &stmtInfo, STMT_BLOCK, top);        for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {            if (!js_EmitTree(cx, cg, pn2))                return JS_FALSE;        }        ok = js_PopStatementCG(cx, cg);        break;      case TOK_SEMI:        pn2 = pn->pn_kid;        if (pn2) {            /*             * Top-level or called-from-a-native JS_Execute/EvaluateScript,             * debugger, and eval frames may need the value of the ultimate             * expression statement as the script's result, despite the fact             * that it appears useless to the compiler.             */            useful = wantval = !cx->fp->fun ||                               !cx->fp->fun->interpreted ||                               (cx->fp->flags & JSFRAME_SPECIAL);            if (!useful) {                if (!CheckSideEffects(cx, &cg->treeContext, pn2, &useful))                    return JS_FALSE;            }            if (!useful) {                CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno;                if (!js_ReportCompileErrorNumber(cx, cg,                                                 JSREPORT_CG |                                                 JSREPORT_WARNING |                                                 JSREPORT_STRICT,                                                 JSMSG_USELESS_EXPR)) {                    return JS_FALSE;                }            } else {                if (!js_EmitTree(cx, cg, pn2))                    return JS_FALSE;                if (js_Emit1(cx, cg, wantval ? JSOP_POPV : JSOP_POP) < 0)                    return JS_FALSE;            }        }        break;      case TOK_COLON:        /* Emit an annotated nop so we know to decompile a label. */        atom = pn->pn_atom;        ale = js_IndexAtom(cx, atom, &cg->atomList);        if (!ale)            return JS_FALSE;        pn2 = pn->pn_expr;        noteIndex = js_NewSrcNote2(cx, cg,                                   (pn2->pn_type == TOK_LC)                                   ? SRC_LABELBRACE                                   : SRC_LABEL,                                   (ptrdiff_t) ALE_INDEX(ale));        if (noteIndex < 0 ||            js_Emit1(cx, cg, JSOP_NOP) < 0) {            return JS_FALSE;        }        /* Emit code for the labeled statement. */        js_PushStatement(&cg->treeContext, &stmtInfo, STMT_LABEL,                         CG_OFFSET(cg));        stmtInfo.label = atom;        if (!js_EmitTree(cx, cg, pn2))            return JS_FALSE;        if (!js_PopStatementCG(cx, cg))            return JS_FALSE;        /* If the statement was compound, emit a note for the end brace. */        if (pn2->pn_type == TOK_LC) {            if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 ||                js_Emit1(cx, cg, JSOP_NOP) < 0) {                return JS_FALSE;            }        }        break;      case TOK_COMMA:        /*         * Emit SRC_PCDELTA notes on each JSOP_POP between comma operands.         * These notes help the decompiler bracket the bytecodes generated         * from each sub-expression that follows a comma.         */        off = noteIndex = -1;        for (pn2 = pn->pn_head; ; pn2 = pn2->pn_next) {            if (!js_EmitTree(cx, cg, pn2))                return JS_FALSE;            tmp = CG_OFFSET(cg);            if (noteIndex >= 0) {                if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))                    return JS_FALSE;            }            if (!pn2->pn_next)                break;            off = tmp;            noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);            if (noteIndex < 0 ||                js_Emit1(cx, cg, JSOP_POP) < 0) {                return JS_FALSE;            }        }        break;      case TOK_ASSIGN:        /*         * Check left operand type and generate specialized code for it.         * Specialize to avoid ECMA "reference type" values on the operand         * stack, which impose pervasive runtime "GetValue" costs.         */        pn2 = pn->pn_left;        JS_ASSERT(pn2->pn_type != TOK_RP);        atomIndex = (jsatomid) -1; /* Suppress warning. */        switch (pn2->pn_type) {          case TOK_NAME:            if (!LookupArgOrVar(cx, &cg->treeContext, pn2))                return JS_FALSE;            if (pn2->pn_slot >= 0) {                atomIndex = (jsatomid) pn2->pn_slot;            } else {                ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);                if (!ale)                    return JS_FALSE;                atomIndex = ALE_INDEX(ale);                EMIT_ATOM_INDEX_OP(JSOP_BINDNAME, atomIndex);            }            break;          case TOK_DOT:            if (!js_EmitTree(cx, cg, pn2->pn_expr))                return JS_FALSE;            ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);            if (!ale)                return JS_FALSE;            atomIndex = ALE_INDEX(ale);            break;          case TOK_LB:            JS_ASSERT(pn->pn_arity == PN_BINARY);            if (!js_EmitTree(cx, cg, pn2->pn_left))                return JS_FALSE;            if (!js_EmitTree(cx, cg, pn2->pn_right))                return JS_FALSE;            break;#if JS_HAS_LVALUE_RETURN          case TOK_LP:            if (!js_EmitTree(cx, cg, pn2))                return JS_FALSE;            break;#endif#if JS_HAS_XML_SUPPORT          case TOK_UNARYOP:            JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME);            if (!js_EmitTree(cx, cg, pn2->pn_kid))                return JS_FALSE;            if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0)                return JS_FALSE;            break;#endif          default:            JS_ASSERT(0);        }        op = pn->pn_op;#if JS_HAS_GETTER_SETTER        if (op == JSOP_GETTER || op == JSOP_SETTER) {            /* We'll emit these prefix bytecodes after emitting the r.h.s. */        } else#endif        /* If += or similar, dup the left operand and get its value. */        if (op != JSOP_NOP) {            switch (pn2->pn_type) {              case TOK_NAME:                if (pn2->pn_op != JSOP_SETNAME) {                    EMIT_UINT16_IMM_OP((pn2->pn_op == JSOP_SETGVAR)                                       ? JSOP_GETGVAR                                       : (pn2->pn_op == JSOP_SETARG)                                       ? JSOP_GETARG                                       : JSOP_GETVAR,                                       atomIndex);                    break;                }                /* FALL THROUGH */              case TOK_DOT:                if (js_Emit1(cx, cg, JSOP_DUP) < 0)                    return JS_FALSE;                EMIT_ATOM_INDEX_OP(JSOP_GETPROP, atomIndex);                break;              case TOK_LB:#if JS_HAS_LVALUE_RETURN              case TOK_LP:#endif#if JS_HAS_XML_SUPPORT              case TOK_UNARYOP:#endif                if (js_Emit1(cx, cg, JSOP_DUP2) < 0)                    return JS_FALSE;                if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)                    return JS_FALSE;                break;              default:;            }        }        /* Now emit the right operand (it may affect the namespace). */        if (!js_EmitTree(cx, cg, pn->pn_right))            return JS_FALSE;        /* If += etc., emit the binary operator with a decompiler note. */        if (op != JSOP_NOP) {            if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0 ||                js_Emit1(cx, cg, op) < 0) {                return JS_FALSE;            }        }        /* Left parts such as a.b.c and a[b].c need a decompiler note. */        if (pn2->pn_type != TOK_NAME) {            if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)                return JS_FALSE;        }        /* Finally, emit the specialized assignment bytecode. */        switch (pn2->pn_type) {          case TOK_NAME:            if (pn2->pn_slot < 0 || !(pn2->pn_attrs & JSPROP_READONLY)) {                if (pn2->pn_slot >= 0) {                    EMIT_UINT16_IMM_OP(pn2->pn_op, atomIndex);                } else {          case TOK_DOT:                    EMIT_ATOM_INDEX_OP(pn2->pn_op, atomIndex);                }            }            break;          case TOK_LB:#if JS_HAS_LVALUE_RETURN          case TOK_LP:#endif            if (js_Emit1(cx, cg, JSOP_SETELEM) < 0)                return JS_FALSE;            break;#if JS_HAS_XML_SUPPORT          case TOK_UNARYOP:            if (js_Emit1(cx, cg, JSOP_SETXMLNAME) < 0)                return JS_FALSE;            break;#endif          default:;        }        break;      case TOK_HOOK:        /* Emit the condition, then branch if false to the else part. */        if (!js_EmitTree(cx, cg, pn->pn_kid1))            return JS_FALSE;        noteIndex = js_NewSrcNote(cx, cg, SRC_COND);        if (noteIndex < 0)            return JS_FALSE;        beq = EmitJump(cx, cg, JSOP_IFEQ, 0);        if (beq < 0 || !js_EmitTree(cx, cg, pn->pn_kid2))            return JS_FALSE;        /* Jump around else, fixup the branch, emit else, fixup jump. */        jmp = EmitJump(cx, cg, JSOP_GOTO, 0);        if (jmp < 0)            return JS_FALSE;        CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);        if (!js_EmitTree(cx, cg, pn->pn_kid3))            return JS_FALSE;        CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);        if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))            return JS_FALSE;        /*         * Because each branch pushes a single value, but our stack budgeting         * analysis ignores branches, we now have two values accounted for in         * cg->stackDepth.  Execution will follow only one path, so we must         * decrement cg->stackDepth here.  Failing to do this will foil code,         * such as the try/catch/finally exception handling code generator,         * that samples cg->stackDepth for use at runtime (JSOP_SETSP).         */        JS_ASSERT(cg->stackDepth > 1);        cg->stackDepth--;        break;      case TOK_OR:      case TOK_AND:        /*         * JSOP_OR converts the operand on the stack to boolean, and if true,         * leaves the original operand value on the stack and jumps; otherwise         * it pops and falls into the next bytecode, which evaluates the right         * operand.  The jump goes around the right operand evaluation.         *         * JSOP_AND converts the operand on the stack to boolean, and if false,         * leaves the original operand value on the stack and jumps; otherwise         * it pops and falls into the right operand's bytecode.         *         * Avoid tail recursion for long ||...|| expressions and long &&...&&         * expressions or long mixtures of ||'s and &&'s that can easily blow         * the stack, by forward-linking and then backpatching all the JSOP_OR         * and JSOP_AND bytecodes' immediate jump-offset operands.         */        pn3 = pn;        if (!js_EmitTree(cx, cg, pn->pn_left))            return JS_FALSE;        top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);        if (top < 0)            return JS_FALSE;        jmp = top;        pn2 = pn->pn_right;        while (pn2->pn_type == TOK_OR || pn2->pn_type == TOK_AND) {            pn = pn2;            if (!js_EmitTree(cx, cg, pn->pn_left))                return JS_FALSE;            off = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);            if (off < 0)                return JS_FALSE;            if (!SetBackPatchDelta(cx, cg, CG_CODE(cg, jmp), off - jmp))                return JS_FALSE;            jmp = off;            pn2 = pn->pn_right;        }        if (!js_EmitTree(cx, cg, pn2))            return JS_FALSE;        off = CG_OFFSET(cg);        do {            pc = CG_CODE(cg, top);            tmp = GetJumpOffset(cg, pc);            CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top);            *pc = pn3->pn_op;            top += tmp;        } while ((pn3 = pn3->pn_right) != pn2);        break;      case TOK_BITOR:      case TOK_BITXOR:      case TOK_BITAND:      case TOK_EQOP:      case TOK_RELOP:#if JS_HAS_IN_OPERATOR      case TOK_IN:#endif#if JS_HAS_INSTANCEOF      case TOK_INSTANCEOF:#endif      case TOK_SHOP:      case TOK_PLUS:      case TOK_MINUS:      case TOK_STAR:      case TOK_DIVOP:        if (pn->pn_arity == PN_LIST) {            /* Left-associative operator chain: avoid too much recursion. */            pn2 = pn->pn_head;            if (!js_EmitTree(cx, cg, pn2))                return JS_FALSE;            op = pn->pn_op;            while ((pn2 = pn2->pn_next) != NULL) {                if (!js_EmitTree(cx, cg, pn2))                    return JS_FALSE;                if (js_Emit1(cx, cg, op) < 0)                    return JS_FALSE;            }        } else {#if JS_HAS_XML_SUPPORT      case TOK_DBLCOLON:            if (pn->pn_arity == PN_NAME) {                if (!js_EmitTree(cx, cg, pn->pn_expr))                    return JS_FALSE;                if (!EmitAtomOp(cx, pn, pn->pn_op, cg))                    return JS_FALSE;                break;            }#endif            /* Binary operators that evaluate both operands unconditionally. */            if (!js_EmitTree(cx, cg, pn->pn_left))                return JS_FALSE;            if (!js_EmitTree(cx, cg, pn->pn_right))                return JS_FALSE;            if (js_Emit1(cx, cg, pn->pn_op) < 0)                return JS_FALSE;        }        break;#if JS_HAS_EXCEPTIONS      case TOK_THROW:#endif#if JS_HAS_XML_SUPPORT      case TOK_AT:      case TOK_DEFAULT:        JS_ASSERT(pn->pn_arity == PN_UNARY);        /* FALL THROUGH */#endif      case TOK_UNARYOP:        /* Unary op, including unary +/-. */        pn2 = pn->pn_kid;        if (!js_EmitTree(cx, cg, pn2))            return JS_FALSE;        op = pn->pn_op;#if JS_HAS_XML_SUPPORT        if (op == JSOP_XMLNAME &&            js_NewSrcNote2(cx, cg, SRC_PCBASE,                           CG_OFFSET(cg) - pn2->pn_offset) < 0) {            return JS_FALSE;        }#endif        if (js_Emit1(cx, cg, op) < 0)            return JS_FALSE;        break;      case TOK_INC:      case TOK_DEC:        /* Emit lvalue-specialized code for ++/-- operators. */        pn2 = pn->pn_kid;        JS_ASSERT(pn2->pn_type != TOK_RP);        op = pn->pn_op;        switch (pn2->pn_type) {          case TOK_NAME:            pn2->pn_op = op;            if (!LookupArgOrVar(cx, &cg->treeContext, pn2))                return JS_FALSE;            op = pn2->pn_op;            if (pn2->pn_slot >= 0) {                if (pn2->pn_attrs & JSPROP_READONLY) {                    /* Incrementing a declared const: just get its value. */                    op = ((js_CodeSpec[op].format & JOF_TYPEMASK) == JOF_CONST)                         ? JSOP_GETGVAR                         : JSOP_GETVAR;                }                atomIndex = (jsatomid) pn2->pn_slot;                EMIT_UINT16_IMM_OP(op, atomIndex);            } else {                if (!EmitAtomOp(cx, pn2, op, cg))                    return JS_FALSE;            }            break;          case TOK_DOT:            if (!EmitPropOp(cx, pn2, op, cg))                return JS_FALSE;            break;          case TOK_LB:            if (!EmitElemOp(cx, pn2, op, cg))                return JS_FALSE;            break;#if JS_HAS_LVALUE_RETURN          case TOK_LP:            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 (js_Emit1(cx, cg, op) < 0)                return JS_FALSE;            break;#endif#if JS_HAS_XML_SUPPORT          case TOK_UNARYOP:            JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME);            if (!js_EmitTree(cx, cg, pn2->pn_kid))                return JS_FALSE;            if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0)                return JS_FALSE;            if (js_Emit1(cx, cg, op) < 0)                return JS_FALSE;            break;#endif          default:            JS_ASSERT(0);        }        break;      case TOK_DELETE:        /*         * Under ECMA 3, deleting a non-reference returns true -- but alas we         * must evaluate the operand if it appears it might have side effects.         */        pn2 = pn->pn_kid;        switch (pn2->pn_type) {          case TOK_NAME:            pn2->pn_op = JSOP_DELNAME;            if (!LookupArgOrVar(cx, &cg->treeContext, pn2))                return JS_FALSE;            op = pn2->pn_op;            if (op == JSOP_FALSE) {                if (js_Emit1(cx, cg, op) < 0)                    return JS_FALSE;            } else {                if (!EmitAtomOp(cx, pn2, op, cg))                    return JS_FALSE;            }            break;          case TOK_DOT:            if (!EmitPropOp(cx, pn2, JSOP_DELPROP, cg))                return JS_FALSE;            break;#if JS_HAS_XML_SUPPORT          case TOK_DBLDOT:            if (!EmitElemOp(cx, pn2, JSOP_DELDESC, cg))                return JS_FALSE;            break;#endif          case TOK_LB:            if (!EmitElemOp(cx, pn2, JSOP_DELELEM, cg))                return JS_FALSE;            break;          default:            useful = JS_FALSE;            if (!CheckSideEffects(cx, &cg->treeContext, pn2, &useful))                return JS_FALSE;            if (useful) {                if (!js_EmitTree(cx, cg, pn2))                    return JS_FALSE;                if (js_Emit1(cx, cg, JSOP_POP) < 0)                    return JS_FALSE;            }            if (js_Emit1(cx, cg, JSOP_TRUE) < 0)                return JS_FALSE;        }        break;#if JS_HAS_XML_SUPPORT      case TOK_FILTER:        if (!js_EmitTree(cx, cg, pn->pn_left))            return JS_FALSE;        jmp = js_Emit3(cx, cg, JSOP_FILTER, 0, 0);        if (jmp < 0)            return JS_FALSE;        if (!js_EmitTree(cx, cg, pn->pn_right))            return JS_FALSE;        if (js_Emit1(cx, cg, JSOP_ENDFILTER) < 0)            return JS_FALSE;        CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);        break;#endif      case TOK_DOT:        /*         * Pop a stack operand, convert it to object, get a property named by         * this bytecode's immediate-indexed atom operand, and push its value         * (not a reference to it).  This bytecode sets the virtual machine's         * "obj" register to the left operand's ToObject conversion result,         * for use by JSOP_PUSHOBJ.         */        ok = EmitPropOp(cx, pn, pn->pn_op, cg);        break;      case TOK_LB:#if JS_HAS_XML_SUPPORT      case TOK_DBLDOT:#endif        /*         * Pop two operands, convert the left one to object and the right one         * to property name (atom or tagged int), get the named property, and         * push its value.  Set the "obj" register to the result of ToObject         * on the left operand.         */        ok = EmitElemOp(cx, pn, pn->pn_op, cg);        break;      case TOK_NEW:      case TOK_LP:        /*         * Emit function call or operator new (constructor call) code.         * First, emit code for the left operand to evaluate the callable or         * constructable object expression.         *         * For E4X, if calling rather than constructing (TOK_LP), and if this         * expression is a member reference, select JSOP_GETMETHOD instead of         * JSOP_GETPROP.  ECMA-357 separates XML method lookup from the normal         * property lookup done for native objects.         */        pn2 = pn->pn_head;#if JS_HAS_XML_SUPPORT        if (pn2->pn_type == TOK_DOT && pn2->pn_op != JSOP_GETMETHOD) {            JS_ASSERT(pn2->pn_op == JSOP_GETPROP);            pn2->pn_op = JSOP_GETMETHOD;        }#endif        if (!js_EmitTree(cx, cg, pn2))            return JS_FALSE;        /*         * Push the virtual machine's "obj" register, which was set by a         * name, property, or element get (or set) bytecode.         */        if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)            return JS_FALSE;        /* Remember start of callable-object bytecode for decompilation hint. */        off = top;        /*         * Emit code for each argument in order, then emit the JSOP_*CALL* or         * JSOP_NEW bytecode with a two-byte immediate telling how many args         * were pushed on the operand stack.         */        for (pn2 = pn2->pn_next; pn2; pn2 = pn2->pn_next) {            if (!js_EmitTree(cx, cg, pn2))                return JS_FALSE;        }        if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)            return JS_FALSE;        argc = pn->pn_count - 1;        if (js_Emit3(cx, cg, pn->pn_op, ARGC_HI(argc), ARGC_LO(argc)) < 0)            return JS_FALSE;        break;#if JS_HAS_INITIALIZERS      case TOK_RB:        /*         * Emit code for [a, b, c] of the form:         *   t = new Array; t[0] = a; t[1] = b; t[2] = c; t;         * but use a stack slot for t and avoid dup'ing and popping it via         * the JSOP_NEWINIT and JSOP_INITELEM bytecodes.         */        ale = js_IndexAtom(cx, cx->runtime->atomState.ArrayAtom,                           &cg->atomList);        if (!ale)            return JS_FALSE;        EMIT_ATOM_INDEX_OP(JSOP_NAME, ALE_INDEX(ale));        if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)            return JS_FALSE;        if (js_Emit1(cx, cg, JSOP_NEWINIT) < 0)            return JS_FALSE;        pn2 = pn->pn_head;#if JS_HAS_SHARP_VARS        if (pn2 && pn2->pn_type == TOK_DEFSHARP) {            EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);            pn2 = pn2->pn_next;        }#endif        for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {            if (!EmitNumberOp(cx, atomIndex, cg))                return JS_FALSE;            /* FIXME 260106: holes in a sparse initializer are void-filled. */            if (pn2->pn_type == TOK_COMMA) {                if (js_Emit1(cx, cg, JSOP_PUSH) < 0)                    return JS_FALSE;            } else {                if (!js_EmitTree(cx, cg, pn2))                    return JS_FALSE;            }            if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)                return JS_FALSE;        }        if (pn->pn_extra & PNX_ENDCOMMA) {            /* Emit a source note so we know to decompile an extra comma. */            if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0)                return JS_FALSE;        }        /* Emit an op for sharp array cleanup and decompilation. */        if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)            return JS_FALSE;        break;      case TOK_RC:        /*         * Emit code for {p:a, '%q':b, 2:c} of the form:         *   t = new Object; t.p = a; t['%q'] = b; t[2] = c; t;         * but use a stack slot for t and avoid dup'ing and popping it via         * the JSOP_NEWINIT and JSOP_INITELEM bytecodes.         */        ale = js_IndexAtom(cx, cx->runtime->atomState.ObjectAtom,                           &cg->atomList);        if (!ale)            return JS_FALSE;        EMIT_ATOM_INDEX_OP(JSOP_NAME, ALE_INDEX(ale));        if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)            return JS_FALSE;        if (js_Emit1(cx, cg, JSOP_NEWINIT) < 0)            return JS_FALSE;        pn2 = pn->pn_head;#if JS_HAS_SHARP_VARS        if (pn2 && pn2->pn_type == TOK_DEFSHARP) {            EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);            pn2 = pn2->pn_next;        }#endif        for (; pn2; pn2 = pn2->pn_next) {            /* Emit an index for t[2], else map an atom for t.p or t['%q']. */            pn3 = pn2->pn_left;            switch (pn3->pn_type) {              case TOK_NUMBER:                if (!EmitNumberOp(cx, pn3->pn_dval, cg))                    return JS_FALSE;                break;              case TOK_NAME:              case TOK_STRING:                ale = js_IndexAtom(cx, pn3->pn_atom, &cg->atomList);                if (!ale)                    return JS_FALSE;                break;              default:                JS_ASSERT(0);            }            /* Emit code for the property initializer. */            if (!js_EmitTree(cx, cg, pn2->pn_right))                return JS_FALSE;#if JS_HAS_GETTER_SETTER            op = pn2->pn_op;            if (op == JSOP_GETTER || op == JSOP_SETTER) {                if (js_Emit1(cx, cg, op) < 0)                    return JS_FALSE;            }#endif            /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */            if (pn3->pn_type == TOK_NUMBER) {                if (js_NewSrcNote2(cx, cg, SRC_LABEL, 0) < 0)                    return JS_FALSE;                if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)                    return JS_FALSE;            } else {                EMIT_ATOM_INDEX_OP(JSOP_INITPROP, ALE_INDEX(ale));            }        }        /* Emit an op for sharpArray cleanup and decompilation. */        if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)            return JS_FALSE;        break;#if JS_HAS_SHARP_VARS      case TOK_DEFSHARP:        if (!js_EmitTree(cx, cg, pn->pn_kid))            return JS_FALSE;        EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) pn->pn_num);        break;      case TOK_USESHARP:        EMIT_UINT16_IMM_OP(JSOP_USESHARP, (jsatomid) pn->pn_num);        break;#endif /* JS_HAS_SHARP_VARS */#endif /* JS_HAS_INITIALIZERS */      case TOK_RP:        /*         * The node for (e) has e as its kid, enabling users who want to nest         * assignment expressions in conditions to avoid the error correction         * done by Condition (from x = y to x == y) by double-parenthesizing.         */        if (!js_EmitTree(cx, cg, pn->pn_kid))            return JS_FALSE;        if (js_Emit1(cx, cg, JSOP_GROUP) < 0)            return JS_FALSE;        break;      case TOK_NAME:        if (!LookupArgOrVar(cx, &cg->treeContext, pn))            return JS_FALSE;        op = pn->pn_op;        if (op == JSOP_ARGUMENTS) {            if (js_Emit1(cx, cg, op) < 0)                return JS_FALSE;            break;        }        if (pn->pn_slot >= 0) {            atomIndex = (jsatomid) pn->pn_slot;            EMIT_UINT16_IMM_OP(op, atomIndex);            break;        }        /* FALL THROUGH */#if JS_HAS_XML_SUPPORT      case TOK_XMLATTR:      case TOK_XMLTEXT:      case TOK_XMLCDATA:      case TOK_XMLCOMMENT:#endif      case TOK_STRING:      case TOK_OBJECT:        /*         * The scanner and parser associate JSOP_NAME with TOK_NAME, although         * other bytecodes may result instead (JSOP_BINDNAME/JSOP_SETNAME,         * JSOP_FORNAME, etc.).  Among JSOP_*NAME* variants, only JSOP_NAME         * may generate the first operand of a call or new expression, so only         * it sets the "obj" virtual machine register to the object along the         * scope chain in which the name was found.         *         * Token types for STRING and OBJECT have corresponding bytecode ops         * in pn_op and emit the same format as NAME, so they share this code.         */        ok = EmitAtomOp(cx, pn, pn->pn_op, cg);        break;      case TOK_NUMBER:        ok = EmitNumberOp(cx, pn->pn_dval, cg);        break;#if JS_HAS_XML_SUPPORT      case TOK_ANYNAME:#endif      case TOK_PRIMARY:        if (js_Emit1(cx, cg, pn->pn_op) < 0)            return JS_FALSE;        break;#if JS_HAS_DEBUGGER_KEYWORD      case TOK_DEBUGGER:        if (js_Emit1(cx, cg, JSOP_DEBUGGER) < 0)            return JS_FALSE;        break;#endif /* JS_HAS_DEBUGGER_KEYWORD */#if JS_HAS_XML_SUPPORT      case TOK_XMLELEM:      case TOK_XMLLIST:        if (pn->pn_op == JSOP_XMLOBJECT) {            ok = EmitAtomOp(cx, pn, pn->pn_op, cg);            break;        }        JS_ASSERT(pn->pn_type == TOK_XMLLIST || pn->pn_count != 0);        for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {            if (!js_EmitTree(cx, cg, pn2))                return JS_FALSE;            if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)                return JS_FALSE;        }        if (pn->pn_extra & PNX_XMLROOT) {            if (pn->pn_count == 0) {                JS_ASSERT(pn->pn_type == TOK_XMLLIST);                atom = cx->runtime->atomState.emptyAtom;                ale = js_IndexAtom(cx, atom, &cg->atomList);                if (!ale)                    return JS_FALSE;                EMIT_ATOM_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));            }            if (js_Emit1(cx, cg, pn->pn_op) < 0)                return JS_FALSE;        }#ifdef DEBUG        else            JS_ASSERT(pn->pn_count != 0);#endif        break;      case TOK_XMLPTAGC:        if (pn->pn_op == JSOP_XMLOBJECT) {            ok = EmitAtomOp(cx, pn, pn->pn_op, cg);            break;        }        /* FALL THROUGH */      case TOK_XMLSTAGO:      case TOK_XMLETAGO:      {        uint32 i;        ale = js_IndexAtom(cx,                           (pn->pn_type == TOK_XMLETAGO)                           ? cx->runtime->atomState.etagoAtom                           : cx->runtime->atomState.stagoAtom,                           &cg->atomList);        if (!ale)            return JS_FALSE;        EMIT_ATOM_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));        JS_ASSERT(pn->pn_count != 0);        pn2 = pn->pn_head;        if (!js_EmitTree(cx, cg, pn2))            return JS_FALSE;        if (js_Emit1(cx, cg, JSOP_ADD) < 0)            return JS_FALSE;        for (pn2 = pn2->pn_next, i = 0; pn2; pn2 = pn2->pn_next, i++) {            if (!js_EmitTree(cx, cg, pn2))                return JS_FALSE;            if ((i & 1) && pn2->pn_type == TOK_LC) {                if (js_Emit1(cx, cg, JSOP_TOATTRVAL) < 0)                    return JS_FALSE;            }            if (js_Emit1(cx, cg,                         (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0) {                return JS_FALSE;            }        }        ale = js_IndexAtom(cx,                           (pn->pn_type == TOK_XMLPTAGC)                           ? cx->runtime->atomState.ptagcAtom                           : cx->runtime->atomState.tagcAtom,                           &cg->atomList);        if (!ale)            return JS_FALSE;        EMIT_ATOM_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));        if (js_Emit1(cx, cg, JSOP_ADD) < 0)            return JS_FALSE;        if ((pn->pn_extra & PNX_XMLROOT) && js_Emit1(cx, cg, pn->pn_op) < 0)            return JS_FALSE;        break;      }      case TOK_XMLNAME:        if (pn->pn_arity == PN_LIST) {            JS_ASSERT(pn->pn_count != 0);            for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {                if (!js_EmitTree(cx, cg, pn2))                    return JS_FALSE;                if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)                    return JS_FALSE;            }        } else {            JS_ASSERT(pn->pn_arity == PN_NULLARY);            ok = EmitAtomOp(cx, pn, pn->pn_op, cg);        }        break;      case TOK_XMLPI:        ale = js_IndexAtom(cx, pn->pn_atom2, &cg->atomList);        if (!ale)            return JS_FALSE;        if (!EmitAtomIndexOp(cx, JSOP_STRING, ALE_INDEX(ale), cg))            return JS_FALSE;        if (!EmitAtomOp(cx, pn, JSOP_XMLPI, cg))            return JS_FALSE;        break;#endif /* JS_HAS_XML_SUPPORT */      default:        JS_ASSERT(0);    }    if (ok && --cg->emitLevel == 0 && cg->spanDeps)        ok = OptimizeSpanDeps(cx, cg);    return ok;}