* The for loop body length can now be adjusted to account for * the length of the indexing expression.
* The for loop body net and gross lengths can now be adjusted * to account for the length of the indexing expression that * came after JSOP_FORELEM and before JSOP_ENUMELEM.
Decompile(SprintStack *ss, jsbytecode *pc, intN nb){    JSContext *cx;    JSPrinter *jp, *jp2;    jsbytecode *endpc, *done, *forelem_done;    ptrdiff_t len, todo, oplen, cond, next, tail;    JSOp op, lastop, saveop;    const JSCodeSpec *cs, *topcs;    jssrcnote *sn, *sn2;    const char *lval, *rval, *xval;    jsint i, argc;    char **argv;    JSAtom *atom;    JSObject *obj;    JSFunction *fun;    JSString *str;    JSBool ok;    jsval val;/* * Local macros */#define DECOMPILE_CODE(pc,nb)	if (!Decompile(ss, pc, nb)) return JS_FALSE#define POP_STR()		OFF2STR(&ss->sprinter, PopOff(ss, op))#define LOCAL_ASSERT(expr)	JS_ASSERT(expr); if (!(expr)) return JS_FALSE    cx = ss->sprinter.context;    jp = ss->printer;    endpc = pc + nb;    forelem_done = NULL;    todo = -2;			/* NB: different from Sprint() error return. */    tail = -1;    op = JSOP_NOP;    sn = NULL;    rval = NULL;    while (pc < endpc) {        lastop = op;        op = saveop = (JSOp) *pc;        if (op >= JSOP_LIMIT) {            switch (op) {              case JSOP_GETPROP2:                saveop = JSOP_GETPROP;                break;              case JSOP_GETELEM2:                saveop = JSOP_GETELEM;                break;              default:;            }        }        cs = &js_CodeSpec[saveop];        len = oplen = cs->length;        if (cs->token) {            switch (cs->nuses) {              case 2:                rval = POP_STR();                lval = POP_STR();                if ((sn = js_GetSrcNote(jp->script, pc)) != NULL &&                    SN_TYPE(sn) == SRC_ASSIGNOP) {                    /* Print only the right operand of the assignment-op. */                    todo = SprintPut(&ss->sprinter, rval, strlen(rval));                } else {                    todo = Sprint(&ss->sprinter, "%s %s %s",                                  lval, cs->token, rval);                }                break;              case 1:                rval = POP_STR();                todo = Sprint(&ss->sprinter, "%s%s", cs->token, rval);                break;              case 0:#if JS_HAS_GETTER_SETTER                if (op == JSOP_GETTER || op == JSOP_SETTER) {                    todo = -2;                    break;                }#endif                todo = SprintPut(&ss->sprinter, cs->token, strlen(cs->token));                break;              default:                todo = -2;                break;            }        } else {            switch (op) {              case JSOP_NOP:                /*                 * Check for a do-while loop, a for-loop with an empty                 * initializer part, a labeled statement, a function                 * definition, or try/finally.                 */                sn = js_GetSrcNote(jp->script, pc);                todo = -2;                switch (sn ? SN_TYPE(sn) : SRC_NULL) {#if JS_HAS_DO_WHILE_LOOP                  case SRC_WHILE:                    js_printf(jp, "\tdo {\n");                    jp->indent += 4;                    break;#endif /* JS_HAS_DO_WHILE_LOOP */                  case SRC_FOR:                    rval = "";                  do_forloop:                    /* Skip the JSOP_NOP or JSOP_POP bytecode. */                    pc++;                    /* Get the cond, next, and loop-closing tail offsets. */                    cond = js_GetSrcNoteOffset(sn, 0);                    next = js_GetSrcNoteOffset(sn, 1);                    tail = js_GetSrcNoteOffset(sn, 2);                    LOCAL_ASSERT(tail + GetJumpOffset(pc+tail, pc+tail) == 0);                    /* Print the keyword and the possibly empty init-part. */                    js_printf(jp, "\tfor (%s;", rval);                    if (pc[cond] == JSOP_IFEQ || pc[cond] == JSOP_IFEQX) {                        /* Decompile the loop condition. */                        DECOMPILE_CODE(pc, cond);                        js_printf(jp, " %s", POP_STR());                    }                    /* Need a semicolon whether or not there was a cond. */                    js_puts(jp, ";");                    if (pc[next] != JSOP_GOTO && pc[next] != JSOP_GOTOX) {                        /* Decompile the loop updater. */                        DECOMPILE_CODE(pc + next, tail - next - 1);                        js_printf(jp, " %s", POP_STR());                    }                    /* Do the loop body. */                    js_puts(jp, ") {\n");                    jp->indent += 4;                    oplen = (cond) ? js_CodeSpec[pc[cond]].length : 0;                    DECOMPILE_CODE(pc + cond + oplen, next - cond - oplen);                    jp->indent -= 4;                    js_printf(jp, "\t}\n");                    /* Set len so pc skips over the entire loop. */                    len = tail + js_CodeSpec[pc[tail]].length;                    break;                  case SRC_LABEL:                    atom = js_GetAtom(cx, &jp->script->atomMap,                                      (jsatomid) js_GetSrcNoteOffset(sn, 0));                    jp->indent -= 4;                    rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                    if (!rval)                        return JS_FALSE;                    RETRACT(&ss->sprinter, rval);                    js_printf(jp, "\t%s:\n", rval);                    jp->indent += 4;                    break;                  case SRC_LABELBRACE:                    atom = js_GetAtom(cx, &jp->script->atomMap,                                      (jsatomid) js_GetSrcNoteOffset(sn, 0));                    rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                    if (!rval)                        return JS_FALSE;                    RETRACT(&ss->sprinter, rval);                    js_printf(jp, "\t%s: {\n", rval);                    jp->indent += 4;                    break;                  case SRC_ENDBRACE:                    jp->indent -= 4;                    js_printf(jp, "\t}\n");                    break;                  case SRC_CATCH:                    jp->indent -= 4;                    sn = js_GetSrcNote(jp->script, pc);                    pc += oplen;                    js_printf(jp, "\t} catch (");                    LOCAL_ASSERT(*pc == JSOP_NAME);                    pc += js_CodeSpec[JSOP_NAME].length;                    LOCAL_ASSERT(*pc == JSOP_PUSHOBJ);                    pc += js_CodeSpec[JSOP_PUSHOBJ].length;                    LOCAL_ASSERT(*pc == JSOP_NEWINIT);                    pc += js_CodeSpec[JSOP_NEWINIT].length;                    LOCAL_ASSERT(*pc == JSOP_EXCEPTION);                    pc += js_CodeSpec[JSOP_EXCEPTION].length;                    LOCAL_ASSERT(*pc == JSOP_INITCATCHVAR);                    atom = GET_ATOM(cx, jp->script, pc);                    rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                    if (!rval)                        return JS_FALSE;                    RETRACT(&ss->sprinter, rval);                    js_printf(jp, "%s", rval);                    pc += js_CodeSpec[JSOP_INITCATCHVAR].length;                    LOCAL_ASSERT(*pc == JSOP_ENTERWITH);                    pc += js_CodeSpec[JSOP_ENTERWITH].length;                    len = js_GetSrcNoteOffset(sn, 0);                    if (len) {                        js_printf(jp, " if ");                        DECOMPILE_CODE(pc, len);                        js_printf(jp, "%s", POP_STR());                        pc += len;                        LOCAL_ASSERT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX);                        pc += js_CodeSpec[*pc].length;                    }                    js_printf(jp, ") {\n");                    jp->indent += 4;                    len = 0;                    break;                  case SRC_FUNCDEF:                    atom = js_GetAtom(cx, &jp->script->atomMap,                                      (jsatomid) js_GetSrcNoteOffset(sn, 0));                    JS_ASSERT(ATOM_IS_OBJECT(atom));                  do_function:                    obj = ATOM_TO_OBJECT(atom);                    fun = (JSFunction *) JS_GetPrivate(cx, obj);                    jp2 = js_NewPrinter(cx, JS_GetFunctionName(fun),                                        jp->indent, jp->pretty);                    if (!jp2)                        return JS_FALSE;                    jp2->scope = jp->scope;                    if (js_DecompileFunction(jp2, fun)) {                        str = js_GetPrinterOutput(jp2);                        if (str)                            js_printf(jp, "%s\n", JS_GetStringBytes(str));                    }                    js_DestroyPrinter(jp2);                    break;                  default:;                }              case JSOP_RETRVAL:                break;              case JSOP_GROUP:                /* Use last real op so PopOff adds parens if needed. */                todo = PopOff(ss, lastop);                /* Now add user-supplied parens only if PopOff did not. */                cs    = &js_CodeSpec[lastop];                topcs = &js_CodeSpec[ss->opcodes[ss->top]];                if (topcs->prec >= cs->prec) {                    todo = Sprint(&ss->sprinter, "(%s)",                                  OFF2STR(&ss->sprinter, todo));                }                break;              case JSOP_PUSH:              case JSOP_PUSHOBJ:              case JSOP_BINDNAME:                todo = Sprint(&ss->sprinter, "");                break;#if JS_HAS_EXCEPTIONS              case JSOP_TRY:                js_printf(jp, "\ttry {\n");                jp->indent += 4;                todo = -2;                break;            {              static const char finally_cookie[] = "finally-cookie";              case JSOP_FINALLY:                jp->indent -= 4;                js_printf(jp, "\t} finally {\n");                jp->indent += 4;                /*                 * We must push an empty string placeholder for gosub's return                 * address, popped by JSOP_RETSUB and counted by script->depth                 * but not by ss->top (see JSOP_SETSP, below).                 */                todo = Sprint(&ss->sprinter, finally_cookie);                break;              case JSOP_RETSUB:                rval = POP_STR();                LOCAL_ASSERT(strcmp(rval, finally_cookie) == 0);                todo = -2;                break;            }              case JSOP_SWAP:                /*                 * We don't generate this opcode currently, and previously we                 * did not need to decompile it.  If old, serialized bytecode                 * uses it still, we should fall through and set todo = -2.                 */                /* FALL THROUGH */              case JSOP_GOSUB:              case JSOP_GOSUBX:                /*                 * JSOP_GOSUB and GOSUBX have no effect on the decompiler's                 * string stack because the next op in bytecode order finds                 * the stack balanced by a JSOP_RETSUB executed elsewhere.                 */                todo = -2;                break;              case JSOP_SETSP:                /*                 * The compiler models operand stack depth and fixes the stack                 * pointer on entry to a catch clause based on its depth model.                 * The decompiler must match the code generator's model, which                 * is why JSOP_FINALLY pushes a cookie that JSOP_RETSUB pops.                 */                ss->top = (uintN) GET_ATOM_INDEX(pc);                break;              case JSOP_EXCEPTION:                /*                 * The only other JSOP_EXCEPTION case occurs as part of a code                 * sequence that follows a SRC_CATCH-annotated JSOP_NOP.                 */                sn = js_GetSrcNote(jp->script, pc);                LOCAL_ASSERT(sn && SN_TYPE(sn) == SRC_HIDDEN);                todo = -2;                break;#endif /* JS_HAS_EXCEPTIONS */              case JSOP_POP:              case JSOP_POPV:                sn = js_GetSrcNote(jp->script, pc);                switch (sn ? SN_TYPE(sn) : SRC_NULL) {                  case SRC_FOR:                    rval = POP_STR();                    todo = -2;                    goto do_forloop;                  case SRC_PCDELTA:                    /* Pop and save to avoid blowing stack depth budget. */                    lval = JS_strdup(cx, POP_STR());                    if (!lval)                        return JS_FALSE;                    /*                     * The offset tells distance to the end of the right-hand                     * operand of the comma operator.                     */                    done = pc + len;                    pc += js_GetSrcNoteOffset(sn, 0);                    len = 0;                    if (!Decompile(ss, done, pc - done)) {                        JS_free(cx, (char *)lval);                        return JS_FALSE;                    }                    /* Pop Decompile result and print comma expression. */                    rval = POP_STR();                    todo = Sprint(&ss->sprinter, "%s, %s", lval, rval);                    JS_free(cx, (char *)lval);                    break;                  case SRC_HIDDEN:                    /* Hide this pop, it's from a goto in a with or for/in. */                    todo = -2;                    break;                  default:                    rval = POP_STR();                    if (*rval != '\0')                        js_printf(jp, "\t%s;\n", rval);                    todo = -2;                    break;                }                break;              case JSOP_POP2:                (void) PopOff(ss, op);                (void) PopOff(ss, op);                todo = -2;                break;            {              static const char with_cookie[] = "with-cookie";              case JSOP_ENTERWITH:                sn = js_GetSrcNote(jp->script, pc);                if (sn && SN_TYPE(sn) == SRC_HIDDEN) {                    todo = -2;                    break;                }                rval = POP_STR();                js_printf(jp, "\twith (%s) {\n", rval);                jp->indent += 4;                todo = Sprint(&ss->sprinter, with_cookie);                break;              case JSOP_LEAVEWITH:                sn = js_GetSrcNote(jp->script, pc);                todo = -2;                if (sn && SN_TYPE(sn) == SRC_HIDDEN)                    break;                rval = POP_STR();                LOCAL_ASSERT(strcmp(rval, with_cookie) == 0);                jp->indent -= 4;                js_printf(jp, "\t}\n");                break;            }              case JSOP_SETRVAL:              case JSOP_RETURN:                rval = POP_STR();                if (*rval != '\0')                    js_printf(jp, "\t%s %s;\n", cs->name, rval);                else                    js_printf(jp, "\t%s;\n", cs->name);                todo = -2;                break;#if JS_HAS_EXCEPTIONS              case JSOP_THROW:                sn = js_GetSrcNote(jp->script, pc);                todo = -2;                if (sn && SN_TYPE(sn) == SRC_HIDDEN)                    break;                rval = POP_STR();                js_printf(jp, "\t%s %s;\n", cs->name, rval);                break;#endif /* JS_HAS_EXCEPTIONS */              case JSOP_GOTO:              case JSOP_GOTOX:                sn = js_GetSrcNote(jp->script, pc);                switch (sn ? SN_TYPE(sn) : SRC_NULL) {                  case SRC_CONT2LABEL:                    atom = js_GetAtom(cx, &jp->script->atomMap,                                      (jsatomid) js_GetSrcNoteOffset(sn, 0));                    rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                    if (!rval)                        return JS_FALSE;                    RETRACT(&ss->sprinter, rval);                    js_printf(jp, "\tcontinue %s;\n", rval);                    break;                  case SRC_CONTINUE:                    js_printf(jp, "\tcontinue;\n");                    break;                  case SRC_BREAK2LABEL:                    atom = js_GetAtom(cx, &jp->script->atomMap,                                      (jsatomid) js_GetSrcNoteOffset(sn, 0));                    rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                    if (!rval)                        return JS_FALSE;                    RETRACT(&ss->sprinter, rval);                    js_printf(jp, "\tbreak %s;\n", rval);                    break;                  case SRC_HIDDEN:                    break;                  default:                    js_printf(jp, "\tbreak;\n");                    break;                }                todo = -2;                break;              case JSOP_IFEQ:              case JSOP_IFEQX:                len = GetJumpOffset(pc, pc);                sn = js_GetSrcNote(jp->script, pc);                switch (sn ? SN_TYPE(sn) : SRC_NULL) {                  case SRC_IF:                  case SRC_IF_ELSE:                    rval = POP_STR();                    js_printf(jp, "\tif (%s) {\n", rval);                    jp->indent += 4;                    if (SN_TYPE(sn) == SRC_IF) {                        DECOMPILE_CODE(pc + oplen, len - oplen);                    } else {                        len = js_GetSrcNoteOffset(sn, 0);                        DECOMPILE_CODE(pc + oplen, len - oplen);                        jp->indent -= 4;                        pc += len;                        LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);                        oplen = js_CodeSpec[*pc].length;                        len = GetJumpOffset(pc, pc);                        js_printf(jp, "\t} else {\n");                        jp->indent += 4;                        DECOMPILE_CODE(pc + oplen, len - oplen);                    }                    jp->indent -= 4;                    js_printf(jp, "\t}\n");                    todo = -2;                    break;                  case SRC_WHILE:                    rval = POP_STR();                    js_printf(jp, "\twhile (%s) {\n", rval);                    jp->indent += 4;                    tail = js_GetSrcNoteOffset(sn, 0);                    DECOMPILE_CODE(pc + oplen, tail - oplen);                    jp->indent -= 4;                    js_printf(jp, "\t}\n");                    todo = -2;                    break;                  case SRC_COND:                    xval = JS_strdup(cx, POP_STR());                    if (!xval)                        return JS_FALSE;                    len = js_GetSrcNoteOffset(sn, 0);                    DECOMPILE_CODE(pc + oplen, len - oplen);                    lval = JS_strdup(cx, POP_STR());                    if (!lval) {                        JS_free(cx, (void *)xval);                        return JS_FALSE;                    }                    pc += len;                    LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);                    oplen = js_CodeSpec[*pc].length;                    len = GetJumpOffset(pc, pc);                    DECOMPILE_CODE(pc + oplen, len - oplen);                    rval = POP_STR();                    todo = Sprint(&ss->sprinter, "%s ? %s : %s",                                  xval, lval, rval);                    JS_free(cx, (void *)xval);                    JS_free(cx, (void *)lval);                    break;                  default:                    break;                }                break;              case JSOP_IFNE:              case JSOP_IFNEX:#if JS_HAS_DO_WHILE_LOOP                /* Currently, this must be a do-while loop's upward branch. */                jp->indent -= 4;                js_printf(jp, "\t} while (%s);\n", POP_STR());                todo = -2;#else                JS_ASSERT(0);#endif /* JS_HAS_DO_WHILE_LOOP */                break;              case JSOP_OR:              case JSOP_ORX:                xval = "||";              do_logical_connective:                /* Top of stack is the first clause in a disjunction (||). */                lval = JS_strdup(cx, POP_STR());                if (!lval)                    return JS_FALSE;                done = pc + GetJumpOffset(pc, pc);                pc += len;                len = PTRDIFF(done, pc, jsbytecode);                DECOMPILE_CODE(pc, len);                rval = POP_STR();                if (jp->pretty &&                    jp->indent + 4 + strlen(lval) + 4 + strlen(rval) > 75) {                    rval = JS_strdup(cx, rval);                    if (!rval) {                        tail = -1;                    } else {                        todo = Sprint(&ss->sprinter, "%s %s\n", lval, xval);                        tail = Sprint(&ss->sprinter, "%*s%s",                                      jp->indent + 4, "", rval);                        JS_free(cx, (char *)rval);                    }                    if (tail < 0)                        todo = -1;                } else {                    todo = Sprint(&ss->sprinter, "%s %s %s", lval, xval, rval);                }                JS_free(cx, (char *)lval);                break;              case JSOP_AND:              case JSOP_ANDX:                xval = "&&";                goto do_logical_connective;              case JSOP_FORARG:                atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));                LOCAL_ASSERT(atom);                lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!lval)                    return JS_FALSE;                RETRACT(&ss->sprinter, lval);                goto do_fornameinloop;              case JSOP_FORVAR:                atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));                LOCAL_ASSERT(atom);                lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!lval)                    return JS_FALSE;                RETRACT(&ss->sprinter, lval);                goto do_fornameinloop;              case JSOP_FORNAME:                atom = GET_ATOM(cx, jp->script, pc);                lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!lval)                    return JS_FALSE;                RETRACT(&ss->sprinter, lval);              do_fornameinloop:                sn = js_GetSrcNote(jp->script, pc);                xval = NULL;                atom = NULL;                goto do_forinloop;              case JSOP_FORPROP:                xval = NULL;                atom = GET_ATOM(cx, jp->script, pc);                lval = POP_STR();                sn = NULL;              do_forinloop:                pc += oplen;                LOCAL_ASSERT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX);                oplen = js_CodeSpec[*pc].length;                len = GetJumpOffset(pc, pc);                sn2 = js_GetSrcNote(jp->script, pc);                tail = js_GetSrcNoteOffset(sn2, 0);              do_forinbody:                js_printf(jp, "\tfor (%s%s", VarPrefix(sn), lval);                if (atom) {                    lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                    if (!lval)                        return JS_FALSE;                    RETRACT(&ss->sprinter, lval);                    js_printf(jp, ".%s", lval);                } else if (xval) {                    js_printf(jp, "[%s]", xval);                }                rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-1]);                js_printf(jp, " in %s) {\n", rval);                jp->indent += 4;                DECOMPILE_CODE(pc + oplen, tail - oplen);                jp->indent -= 4;                js_printf(jp, "\t}\n");                todo = -2;                break;              case JSOP_FORELEM:                pc++;                LOCAL_ASSERT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX);                len = js_CodeSpec[*pc].length;                /*                 * Set tail for use by do_forinbody: code that uses it to find                 * the loop-closing jump (whatever its format, short or long),                 * in order to bound the recursively decompiled loop body.                 */                sn = js_GetSrcNote(jp->script, pc);                tail = js_GetSrcNoteOffset(sn, 0) - oplen;                /*                 * This gets a little wacky.  Only the length of the for loop                 * body PLUS the element-indexing expression is known here, so                 * we pass the after-loop pc to the JSOP_ENUMELEM case, which                 * is immediately below, to decompile that helper bytecode via                 * the 'forelem_done' local.                 */                JS_ASSERT(!forelem_done);                forelem_done = pc + GetJumpOffset(pc, pc);                break;              case JSOP_ENUMELEM:                /*                 * The stack has the object under the (top) index expression.                 * The "rval" property id is underneath those two on the stack.                 * The for loop body length can now be adjusted to account for                 * the length of the indexing expression.                 */                atom = NULL;                xval = POP_STR();                lval = POP_STR();                rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-1]);                JS_ASSERT(forelem_done > pc);                len = forelem_done - pc;                forelem_done = NULL;                goto do_forinbody;              case JSOP_DUP2:                rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-2]);                todo = SprintPut(&ss->sprinter, rval, strlen(rval));                if (todo < 0 || !PushOff(ss, todo, ss->opcodes[ss->top-2]))                    return JS_FALSE;                /* FALL THROUGH */              case JSOP_DUP:                rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-1]);                op = ss->opcodes[ss->top-1];                todo = SprintPut(&ss->sprinter, rval, strlen(rval));                break;              case JSOP_SETARG:                atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));                LOCAL_ASSERT(atom);                goto do_setname;              case JSOP_SETVAR:                atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));                LOCAL_ASSERT(atom);                goto do_setname;              case JSOP_SETCONST:              case JSOP_SETNAME:                atom = GET_ATOM(cx, jp->script, pc);              do_setname:                lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!lval)                    return JS_FALSE;                rval = POP_STR();                if (op == JSOP_SETNAME)                    (void) PopOff(ss, op);              do_setlval:                if ((sn = js_GetSrcNote(jp->script, pc - 1)) != NULL &&                    SN_TYPE(sn) == SRC_ASSIGNOP) {                    todo = Sprint(&ss->sprinter, "%s %s= %s",                                  lval, js_CodeSpec[lastop].token, rval);                } else {                    sn = js_GetSrcNote(jp->script, pc);                    todo = Sprint(&ss->sprinter, "%s%s = %s",                                  VarPrefix(sn), lval, rval);                }                break;              case JSOP_NEW:              case JSOP_CALL:              case JSOP_EVAL:#if JS_HAS_LVALUE_RETURN              case JSOP_SETCALL:#endif                saveop = op;                op = JSOP_NOP;           /* turn off parens */                argc = GET_ARGC(pc);                argv = (char **)                    JS_malloc(cx, (size_t)(argc + 1) * sizeof *argv);                if (!argv)                    return JS_FALSE;                ok = JS_TRUE;                for (i = argc; i > 0; i--) {                    argv[i] = JS_strdup(cx, POP_STR());                    if (!argv[i]) {                        ok = JS_FALSE;                        break;                    }                }                /* Skip the JSOP_PUSHOBJ-created empty string. */                LOCAL_ASSERT(ss->top >= 2);                (void) PopOff(ss, op);                /* Get the callee's decompiled image in argv[0]. */                argv[0] = JS_strdup(cx, POP_STR());                if (!argv[i])                    ok = JS_FALSE;                lval = "(", rval = ")";                if (saveop == JSOP_NEW) {                    todo = Sprint(&ss->sprinter, "%s %s%s",                                  js_new_str, argv[0], lval);                } else {                    todo = Sprint(&ss->sprinter, "%s%s",                                  argv[0], lval);                }                if (todo < 0)                    ok = JS_FALSE;                for (i = 1; i <= argc; i++) {                    if (!argv[i] ||                        Sprint(&ss->sprinter, "%s%s",                               argv[i], (i < argc) ? ", " : "") < 0) {                        ok = JS_FALSE;                        break;                    }                }                if (Sprint(&ss->sprinter, rval) < 0)                    ok = JS_FALSE;                for (i = 0; i <= argc; i++) {                    if (argv[i])                        JS_free(cx, argv[i]);                }                JS_free(cx, argv);                if (!ok)                    return JS_FALSE;                op = saveop;#if JS_HAS_LVALUE_RETURN                if (op == JSOP_SETCALL) {                    if (!PushOff(ss, todo, op))                        return JS_FALSE;                    todo = Sprint(&ss->sprinter, "");                }#endif                break;              case JSOP_DELNAME:                atom = GET_ATOM(cx, jp->script, pc);                lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!lval)                    return JS_FALSE;                RETRACT(&ss->sprinter, lval);                todo = Sprint(&ss->sprinter, "%s %s", js_delete_str, lval);                break;              case JSOP_DELPROP:                atom = GET_ATOM(cx, jp->script, pc);                rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!rval)                    return JS_FALSE;                lval = POP_STR();                todo = Sprint(&ss->sprinter, "%s %s.%s",                              js_delete_str, lval, rval);                break;              case JSOP_DELELEM:                xval = POP_STR();                lval = POP_STR();                todo = Sprint(&ss->sprinter, "%s %s[%s]",                              js_delete_str, lval, xval);                break;              case JSOP_TYPEOF:              case JSOP_VOID:                rval = POP_STR();                todo = Sprint(&ss->sprinter, "%s %s", cs->name, rval);                break;              case JSOP_INCARG:              case JSOP_DECARG:                atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));                LOCAL_ASSERT(atom);                goto do_incatom;              case JSOP_INCVAR:              case JSOP_DECVAR:                atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));                LOCAL_ASSERT(atom);                goto do_incatom;              case JSOP_INCNAME:              case JSOP_DECNAME:                atom = GET_ATOM(cx, jp->script, pc);              do_incatom:                lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!lval)                    return JS_FALSE;                RETRACT(&ss->sprinter, lval);                todo = Sprint(&ss->sprinter, "%s%s",                              js_incop_str[!(cs->format & JOF_INC)], lval);                break;              case JSOP_INCPROP:              case JSOP_DECPROP:                atom = GET_ATOM(cx, jp->script, pc);                rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!rval)                    return JS_FALSE;                lval = POP_STR();                todo = Sprint(&ss->sprinter, "%s%s.%s",                              js_incop_str[!(cs->format & JOF_INC)],                              lval, rval);                break;              case JSOP_INCELEM:              case JSOP_DECELEM:                xval = POP_STR();                lval = POP_STR();                todo = Sprint(&ss->sprinter, "%s%s[%s]",                              js_incop_str[!(cs->format & JOF_INC)],                              lval, xval);                break;              case JSOP_ARGINC:              case JSOP_ARGDEC:                atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));                LOCAL_ASSERT(atom);                goto do_atominc;              case JSOP_VARINC:              case JSOP_VARDEC:                atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));                LOCAL_ASSERT(atom);                goto do_atominc;              case JSOP_NAMEINC:              case JSOP_NAMEDEC:                atom = GET_ATOM(cx, jp->script, pc);              do_atominc:                lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!lval)                    return JS_FALSE;                todo = STR2OFF(&ss->sprinter, lval);                SprintPut(&ss->sprinter,                          js_incop_str[!(cs->format & JOF_INC)],                          2);                break;              case JSOP_PROPINC:              case JSOP_PROPDEC:                atom = GET_ATOM(cx, jp->script, pc);                rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!rval)                    return JS_FALSE;                lval = POP_STR();                todo = Sprint(&ss->sprinter, "%s.%s%s",                              lval, rval,                              js_incop_str[!(cs->format & JOF_INC)]);                break;              case JSOP_ELEMINC:              case JSOP_ELEMDEC:                xval = POP_STR();                lval = POP_STR();                todo = Sprint(&ss->sprinter, "%s[%s]%s",                              lval, xval,                              js_incop_str[!(cs->format & JOF_INC)]);                break;              case JSOP_GETPROP2:                op = JSOP_GETPROP;                (void) PopOff(ss, lastop);                /* FALL THROUGH */              case JSOP_GETPROP:                atom = GET_ATOM(cx, jp->script, pc);                str = ATOM_TO_STRING(atom);                if (!ATOM_KEYWORD(atom) && IsASCIIIdentifier(str)) {                    lval = POP_STR();                    todo = Sprint(&ss->sprinter, "%s.%s",                                  lval, JS_GetStringBytes(str));                } else {                    xval = QuoteString(&ss->sprinter, str, (jschar)'\'');                    lval = POP_STR();                    todo = Sprint(&ss->sprinter, "%s[%s]", lval, xval);                }                break;              case JSOP_SETPROP:                sn = js_GetSrcNote(jp->script, pc - 1);                atom = GET_ATOM(cx, jp->script, pc);                str = ATOM_TO_STRING(atom);                if (!ATOM_KEYWORD(atom) && IsASCIIIdentifier(str)) {                    rval = POP_STR();                    lval = POP_STR();                    xval = JS_GetStringBytes(str);                    if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) {                        todo = Sprint(&ss->sprinter, "%s.%s %s= %s",                                      lval, xval,                                      js_CodeSpec[lastop].token, rval);                    } else {                        todo = Sprint(&ss->sprinter, "%s.%s = %s",                                      lval, xval, rval);                    }                } else {                    xval = QuoteString(&ss->sprinter, str, (jschar)'\'');                    rval = POP_STR();                    lval = POP_STR();                    if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) {                        todo = Sprint(&ss->sprinter, "%s[%s] %s= %s",                                      lval, xval,                                      js_CodeSpec[lastop].token, rval);                    } else {                        todo = Sprint(&ss->sprinter, "%s[%s] = %s",                                      lval, xval, rval);                    }                }                break;              case JSOP_GETELEM2:                op = JSOP_GETELEM;                (void) PopOff(ss, lastop);                /* FALL THROUGH */              case JSOP_GETELEM:                op = JSOP_NOP;           /* turn off parens */                xval = POP_STR();                op = JSOP_GETELEM;                lval = POP_STR();                if (*xval == '\0')                    todo = Sprint(&ss->sprinter, "%s", lval);                else                    todo = Sprint(&ss->sprinter, "%s[%s]", lval, xval);                break;              case JSOP_SETELEM:                op = JSOP_NOP;           /* turn off parens */                rval = POP_STR();                xval = POP_STR();                op = JSOP_SETELEM;                lval = POP_STR();                if (*xval == '\0')                    goto do_setlval;                if ((sn = js_GetSrcNote(jp->script, pc - 1)) != NULL &&                    SN_TYPE(sn) == SRC_ASSIGNOP) {                    todo = Sprint(&ss->sprinter, "%s[%s] %s= %s",                                  lval, xval,                                  js_CodeSpec[lastop].token, rval);                } else {                    todo = Sprint(&ss->sprinter, "%s[%s] = %s",                                  lval, xval, rval);                }                break;              case JSOP_ARGSUB:                i = (jsint) GET_ATOM_INDEX(pc);                todo = Sprint(&ss->sprinter, "%s[%d]",                              js_arguments_str, (int) i);                break;              case JSOP_ARGCNT:                todo = Sprint(&ss->sprinter, "%s.%s",                              js_arguments_str, js_length_str);                break;              case JSOP_GETARG:                atom = GetSlotAtom(jp, js_GetArgument, GET_ARGNO(pc));                LOCAL_ASSERT(atom);                goto do_name;              case JSOP_GETVAR:                atom = GetSlotAtom(jp, js_GetLocalVariable, GET_VARNO(pc));                LOCAL_ASSERT(atom);                goto do_name;              case JSOP_NAME:                atom = GET_ATOM(cx, jp->script, pc);              do_name:                sn = js_GetSrcNote(jp->script, pc);                rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!rval)                    return JS_FALSE;                RETRACT(&ss->sprinter, rval);                todo = Sprint(&ss->sprinter, "%s%s", VarPrefix(sn), rval);                break;              case JSOP_UINT16:                i = (jsint) GET_ATOM_INDEX(pc);                todo = Sprint(&ss->sprinter, "%u", (unsigned) i);                break;              case JSOP_NUMBER:                atom = GET_ATOM(cx, jp->script, pc);                val = ATOM_KEY(atom);                if (JSVAL_IS_INT(val)) {                    long ival = (long)JSVAL_TO_INT(val);                    todo = Sprint(&ss->sprinter, "%ld", ival);                } else {                    char buf[DTOSTR_STANDARD_BUFFER_SIZE];                    char *numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD,                                             0, *JSVAL_TO_DOUBLE(val));                    if (!numStr) {                        JS_ReportOutOfMemory(cx);                        return JS_FALSE;                    }                    todo = Sprint(&ss->sprinter, numStr);                }                break;              case JSOP_STRING:                atom = GET_ATOM(cx, jp->script, pc);                rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom),                                   (jschar)'"');                if (!rval)                    return JS_FALSE;                todo = STR2OFF(&ss->sprinter, rval);                break;              case JSOP_OBJECT:              case JSOP_ANONFUNOBJ:              case JSOP_NAMEDFUNOBJ:                atom = GET_ATOM(cx, jp->script, pc);                if (op == JSOP_OBJECT) {                    str = js_ValueToSource(cx, ATOM_KEY(atom));                    if (!str)                        return JS_FALSE;                } else {                    if (!js_fun_toString(cx, ATOM_TO_OBJECT(atom),                                         JS_DONT_PRETTY_PRINT, 0, NULL,                                         &val)) {                        return JS_FALSE;                    }                    str = JSVAL_TO_STRING(val);                }                todo = SprintPut(&ss->sprinter, JS_GetStringBytes(str),                                 JSSTRING_LENGTH(str));                break;#if JS_HAS_SWITCH_STATEMENT              case JSOP_TABLESWITCH:              case JSOP_TABLESWITCHX:              {                jsbytecode *pc2;                ptrdiff_t off, off2;                jsint j, n, low, high;                TableEntry *table;                sn = js_GetSrcNote(jp->script, pc);                JS_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);                len = js_GetSrcNoteOffset(sn, 0);                pc2 = pc;                off = GetJumpOffset(pc, pc2);                pc2 += JUMP_OFFSET_LEN;                low = GetJumpOffset(pc, pc2);                pc2 += JUMP_OFFSET_LEN;                high = GetJumpOffset(pc, pc2);                n = high - low + 1;                if (n == 0) {                    table = NULL;                    j = 0;                } else {                    table = (TableEntry *)                            JS_malloc(cx, (size_t)n * sizeof *table);                    if (!table)                        return JS_FALSE;                    for (i = j = 0; i < n; i++) {                        pc2 += JUMP_OFFSET_LEN;                        off2 = GetJumpOffset(pc, pc2);                        if (off2) {                            table[j].key = INT_TO_JSVAL(low + i);                            table[j++].offset = off2;                        }                    }                    js_HeapSort(table, (size_t) j, sizeof *table,                                CompareOffsets, NULL);                }                ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off,                                     JS_FALSE);                JS_free(cx, table);                if (!ok)                    return ok;                todo = -2;                break;              }              case JSOP_LOOKUPSWITCH:              case JSOP_LOOKUPSWITCHX:              {                jsbytecode *pc2;                ptrdiff_t off, off2;                jsint npairs;                TableEntry *table;                sn = js_GetSrcNote(jp->script, pc);                JS_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);                len = js_GetSrcNoteOffset(sn, 0);                pc2 = pc;                off = GetJumpOffset(pc, pc2);                pc2 += JUMP_OFFSET_LEN;                npairs = (jsint) GET_ATOM_INDEX(pc2);                pc2 += ATOM_INDEX_LEN;                table = (TableEntry *)                    JS_malloc(cx, (size_t)npairs * sizeof *table);                if (!table)                    return JS_FALSE;                for (i = 0; i < npairs; i++) {                    atom = GET_ATOM(cx, jp->script, pc2);                    pc2 += ATOM_INDEX_LEN;                    off2 = GetJumpOffset(pc, pc2);                    pc2 += JUMP_OFFSET_LEN;                    table[i].key = ATOM_KEY(atom);                    table[i].offset = off2;                }                ok = DecompileSwitch(ss, table, (uintN)npairs, pc, len, off,                                     JS_FALSE);                JS_free(cx, table);                if (!ok)                    return ok;                todo = -2;                break;              }              case JSOP_CONDSWITCH:              {                jsbytecode *pc2;                ptrdiff_t off, off2, caseOff;                jsint ncases;                TableEntry *table;                sn = js_GetSrcNote(jp->script, pc);                JS_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);                len = js_GetSrcNoteOffset(sn, 0);                off = js_GetSrcNoteOffset(sn, 1);                /*                 * Count the cases using offsets from switch to first case,                 * and case to case, stored in srcnote immediates.                 */                pc2 = pc;                off2 = off;                for (ncases = 0; off2 != 0; ncases++) {                    pc2 += off2;                    JS_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT ||                              *pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX);                    if (*pc2 == JSOP_DEFAULT || *pc2 == JSOP_DEFAULTX) {                        /* End of cases, but count default as a case. */                        off2 = 0;                    } else {                        sn = js_GetSrcNote(jp->script, pc2);                        JS_ASSERT(sn && SN_TYPE(sn) == SRC_PCDELTA);                        off2 = js_GetSrcNoteOffset(sn, 0);                    }                }                /*                 * Allocate table and rescan the cases using their srcnotes,                 * stashing each case's delta from switch top in table[i].key,                 * and the distance to its statements in table[i].offset.                 */                table = (TableEntry *)                    JS_malloc(cx, (size_t)ncases * sizeof *table);                if (!table)                    return JS_FALSE;                pc2 = pc;                off2 = off;                for (i = 0; i < ncases; i++) {                    pc2 += off2;                    JS_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT ||                              *pc2 == JSOP_CASEX || *pc2 == JSOP_DEFAULTX);                    caseOff = pc2 - pc;                    table[i].key = INT_TO_JSVAL((jsint) caseOff);                    table[i].offset = caseOff + GetJumpOffset(pc2, pc2);                    if (*pc2 == JSOP_CASE || *pc2 == JSOP_CASEX) {                        sn = js_GetSrcNote(jp->script, pc2);                        JS_ASSERT(sn && SN_TYPE(sn) == SRC_PCDELTA);                        off2 = js_GetSrcNoteOffset(sn, 0);                    }                }                /*                 * Find offset of default code by fetching the default offset                 * from the end of table.  JSOP_CONDSWITCH always has a default                 * case at the end.                 */                off = JSVAL_TO_INT(table[ncases-1].key);                pc2 = pc + off;                off += GetJumpOffset(pc2, pc2);                ok = DecompileSwitch(ss, table, (uintN)ncases, pc, len, off,                                     JS_TRUE);                JS_free(cx, table);                if (!ok)                    return ok;                todo = -2;                break;              }              case JSOP_CASE:              case JSOP_CASEX:              {                lval = POP_STR();                if (!lval)                    return JS_FALSE;                js_printf(jp, "\tcase %s:\n", lval);                todo = -2;                break;              }#endif /* JS_HAS_SWITCH_STATEMENT */#if !JS_BUG_FALLIBLE_EQOPS              case JSOP_NEW_EQ:              case JSOP_NEW_NE:                rval = POP_STR();                lval = POP_STR();                todo = Sprint(&ss->sprinter, "%s %c%s %s",                              lval,                              (op == JSOP_NEW_EQ) ? '=' : '!',#if JS_HAS_TRIPLE_EQOPS                              JSVERSION_IS_ECMA(cx->version) ? "==" :#endif                              "=",                              rval);                break;#endif /* !JS_BUG_FALLIBLE_EQOPS */#if JS_HAS_LEXICAL_CLOSURE              case JSOP_CLOSURE:                atom = GET_ATOM(cx, jp->script, pc);                JS_ASSERT(ATOM_IS_OBJECT(atom));                goto do_function;#endif /* JS_HAS_LEXICAL_CLOSURE */#if JS_HAS_EXPORT_IMPORT              case JSOP_EXPORTALL:                js_printf(jp, "\texport *\n");                todo = -2;                break;              case JSOP_EXPORTNAME:                atom = GET_ATOM(cx, jp->script, pc);                rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!rval)                    return JS_FALSE;                RETRACT(&ss->sprinter, rval);                js_printf(jp, "\texport %s\n", rval);                todo = -2;                break;              case JSOP_IMPORTALL:                lval = POP_STR();                js_printf(jp, "\timport %s.*\n", lval);                todo = -2;                break;              case JSOP_IMPORTPROP:                atom = GET_ATOM(cx, jp->script, pc);                rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!rval)                    return JS_FALSE;                lval = POP_STR();                js_printf(jp, "\timport %s.%s\n", lval, rval);                todo = -2;                break;              case JSOP_IMPORTELEM:                xval = POP_STR();                op = JSOP_GETELEM;                lval = POP_STR();                js_printf(jp, "\timport %s[%s]\n", lval, xval);                todo = -2;                break;#endif /* JS_HAS_EXPORT_IMPORT */              case JSOP_TRAP:                op = JS_GetTrapOpcode(cx, jp->script, pc);                if (op == JSOP_LIMIT)                    return JS_FALSE;                *pc = op;                cs = &js_CodeSpec[op];                len = cs->length;                DECOMPILE_CODE(pc, len);                *pc = JSOP_TRAP;                todo = -2;                break;#if JS_HAS_INITIALIZERS              case JSOP_NEWINIT:                LOCAL_ASSERT(ss->top >= 2);                (void) PopOff(ss, op);                lval = POP_STR();#if JS_HAS_SHARP_VARS                op = (JSOp)pc[len];                if (op == JSOP_DEFSHARP) {                    pc += len;                    cs = &js_CodeSpec[op];                    len = cs->length;                    i = (jsint) GET_ATOM_INDEX(pc);                    todo = Sprint(&ss->sprinter, "#%u=%c",                                  (unsigned) i,                                  (*lval == 'O') ? '{' : '[');                } else#endif /* JS_HAS_SHARP_VARS */                {                    todo = Sprint(&ss->sprinter, (*lval == 'O') ? "{" : "[");                }                break;              case JSOP_ENDINIT:                rval = POP_STR();                sn = js_GetSrcNote(jp->script, pc);                todo = Sprint(&ss->sprinter, "%s%s%c",                              rval,                              (sn && SN_TYPE(sn) == SRC_CONTINUE) ? ", " : "",                              (*rval == '{') ? '}' : ']');                break;              case JSOP_INITPROP:              case JSOP_INITCATCHVAR:                atom = GET_ATOM(cx, jp->script, pc);                xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);                if (!xval)                    return JS_FALSE;                rval = POP_STR();                lval = POP_STR();              do_initprop:#ifdef OLD_GETTER_SETTER                todo = Sprint(&ss->sprinter, "%s%s%s%s%s:%s",                              lval,                              (lval[1] != '\0') ? ", " : "",                              xval,                              (lastop == JSOP_GETTER || lastop == JSOP_SETTER)                              ? " " : "",                              (lastop == JSOP_GETTER) ? js_getter_str :                              (lastop == JSOP_SETTER) ? js_setter_str :                              "",                              rval);#else                if (lastop == JSOP_GETTER || lastop == JSOP_SETTER) {                    todo = Sprint(&ss->sprinter, "%s%s%s %s%s",                                  lval,                                  (lval[1] != '\0') ? ", " : "",                                  (lastop == JSOP_GETTER)                                  ? js_get_str : js_set_str,                                  xval,                                  rval + strlen(js_function_str) + 1);                } else {                    todo = Sprint(&ss->sprinter, "%s%s%s:%s",                                  lval,                                  (lval[1] != '\0') ? ", " : "",                                  xval,                                  rval);                }#endif                break;              case JSOP_INITELEM:                rval = POP_STR();                xval = POP_STR();                lval = POP_STR();                sn = js_GetSrcNote(jp->script, pc);                if (sn && SN_TYPE(sn) == SRC_LABEL)                    goto do_initprop;                todo = Sprint(&ss->sprinter, "%s%s%s",                              lval,                              (lval[1] != '\0' || *xval != '0') ? ", " : "",                              rval);                break;#if JS_HAS_SHARP_VARS              case JSOP_DEFSHARP:                i = (jsint) GET_ATOM_INDEX(pc);                rval = POP_STR();                todo = Sprint(&ss->sprinter, "#%u=%s", (unsigned) i, rval);                break;              case JSOP_USESHARP:                i = (jsint) GET_ATOM_INDEX(pc);                todo = Sprint(&ss->sprinter, "#%u#", (unsigned) i);                break;#endif /* JS_HAS_SHARP_VARS */#endif /* JS_HAS_INITIALIZERS */#if JS_HAS_DEBUGGER_KEYWORD              case JSOP_DEBUGGER:                js_printf(jp, "\tdebugger;\n");                todo = -2;                break;#endif /* JS_HAS_DEBUGGER_KEYWORD */              default:                todo = -2;                break;            }        }        if (todo < 0) {            /* -2 means "don't push", -1 means reported error. */            if (todo == -1)                return JS_FALSE;        } else {            if (!PushOff(ss, todo, op))                return JS_FALSE;        }        pc += len;    }/* * Undefine local macros. */#undef DECOMPILE_CODE#undef POP_STR#undef LOCAL_ASSERT    return JS_TRUE;}