JS_ASSERT(sprop && pobj == obj); slot = sprop->shortid; OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);
JS_ASSERT(prop && pobj == obj); slot = ((JSScopeProperty *) prop)->shortid; OBJ_DROP_PROPERTY(cx, pobj, prop);
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;        /* 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 = 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;            JSScopeProperty *sprop;            uintN slot;            obj = OBJ_GET_PARENT(cx, fun->object);            if (!js_LookupProperty(cx, obj, (jsid)fun->atom, &pobj,                                   (JSProperty **)&sprop)) {                return JS_FALSE;            }            JS_ASSERT(sprop && pobj == obj);            slot = sprop->shortid;            OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);            /* Emit [JSOP_DEFLOCALFUN, local variable 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) {            /* Set stmtInfo type for later testing. */            stmtInfo.type = STMT_FOR_IN_LOOP;            noteIndex = -1;            /* 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);            }            /* 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);            /* 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:                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_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;                /*                 * 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 (pn3->pn_type != TOK_LB) {                /* 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 {