if (jp && js_DecompileCode(jp, script, begin, len)) name = js_GetPrinterOutput(jp); else name = NULL;
if (jp) { if (fp->fun && fp->fun->object) { JS_ASSERT(OBJ_IS_NATIVE(fp->fun->object)); jp->scope = OBJ_SCOPE(fp->fun->object); } if (js_DecompileCode(jp, script, begin, len)) name = js_GetPrinterOutput(jp); }
js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,                           JSString *fallback){    JSStackFrame *fp, *down;    jsbytecode *pc, *begin, *end, *tmp;    jsval *sp, *base, *limit;    JSScript *script;    JSOp op;    const JSCodeSpec *cs;    uint32 format, mode;    intN depth;    jssrcnote *sn;    uintN len, off;    JSPrinter *jp;    JSString *name;    fp = cx->fp;    if (!fp)        goto do_fallback;    /* Try to find sp's generating pc depth slots under it on the stack. */    pc = fp->pc;    if (spindex == JSDVG_SEARCH_STACK) {        if (!pc) {            /*             * Current frame is native: look under it for a scripted call             * in which a decompilable bytecode string that generated the             * value as an actual argument might exist.             */            JS_ASSERT(!fp->script && (!fp->fun || fp->fun->native));            down = fp->down;            if (!down)                goto do_fallback;            script = down->script;            base = fp->argv;            limit = base + fp->argc;        } else {            /*             * This should be a script activation, either a top-level             * script or a scripted function.  But be paranoid about calls             * to js_DecompileValueGenerator from code that hasn't fully             * initialized a (default-all-zeroes) frame.             */            script = fp->script;            base = fp->spbase;            limit = fp->sp;        }        /*         * Pure paranoia about default-zeroed frames being active while         * js_DecompileValueGenerator is called.  It can't hurt much now;         * error reporting performance is not an issue.         */        if (!script || !base || !limit)            goto do_fallback;        /*         * Try to find operand-generating pc depth slots below sp.         *         * In the native case, we know the arguments have generating pc's         * under them, on account of fp->down->script being non-null: all         * compiled scripts get depth slots for generating pc's allocated         * upon activation, at the top of js_Interpret.         *         * In the script or scripted function case, the same reasoning         * applies to fp rather than to fp->down.         */        for (sp = base; sp < limit; sp++) {            if (*sp == v) {                depth = (intN)script->depth;                pc = (jsbytecode *) sp[-depth];                break;            }        }    } else {        /*         * At this point, pc may or may not be null, i.e., we could be in         * a script activation, or we could be in a native frame that was         * called by another native function.  Check pc and script.         */        if (!pc)            goto do_fallback;        script = fp->script;        if (!script)            goto do_fallback;        if (spindex != JSDVG_IGNORE_STACK) {            JS_ASSERT(spindex < 0);            depth = (intN)script->depth;#if !JS_HAS_NO_SUCH_METHOD            JS_ASSERT(-depth <= spindex);#endif            spindex -= depth;            base = (jsval *) cx->stackPool.current->base;            limit = (jsval *) cx->stackPool.current->avail;            sp = fp->sp + spindex;            if (JS_UPTRDIFF(sp, base) < JS_UPTRDIFF(limit, base))                pc = (jsbytecode *) *sp;        }    }    /*     * Again, be paranoid, this time about possibly loading an invalid pc     * from sp[-(1+depth)].     */    if (JS_UPTRDIFF(pc, script->code) >= (jsuword)script->length) {        pc = fp->pc;        if (!pc)            goto do_fallback;    }    op = (JSOp) *pc;    if (op == JSOP_TRAP)        op = JS_GetTrapOpcode(cx, script, pc);    /* XXX handle null as a special case, to avoid calling null "object" */    if (op == JSOP_NULL)        return ATOM_TO_STRING(cx->runtime->atomState.nullAtom);    cs = &js_CodeSpec[op];    format = cs->format;    mode = (format & JOF_MODEMASK);    /* NAME ops are self-contained, but others require left context. */    if (mode == JOF_NAME) {        begin = pc;    } else {        sn = js_GetSrcNote(script, pc);        if (!sn || SN_TYPE(sn) != SRC_PCBASE)            goto do_fallback;        begin = pc - js_GetSrcNoteOffset(sn, 0);    }    end = pc + cs->length;    len = PTRDIFF(end, begin, jsbytecode);    if (format & (JOF_SET | JOF_DEL | JOF_INCDEC | JOF_IMPORT | JOF_FOR)) {        tmp = (jsbytecode *) JS_malloc(cx, len * sizeof(jsbytecode));        if (!tmp)            return NULL;        memcpy(tmp, begin, len * sizeof(jsbytecode));        if (mode == JOF_NAME) {            tmp[0] = JSOP_NAME;        } else {            /*             * We must replace the faulting pc's bytecode with a corresponding             * JSOP_GET* code.  For JSOP_SET{PROP,ELEM}, we must use the "2nd"             * form of JSOP_GET{PROP,ELEM}, to throw away the assignment op's             * right-hand operand and decompile it as if it were a GET of its             * left-hand operand.             */            off = len - cs->length;            JS_ASSERT(off == (uintN) PTRDIFF(pc, begin, jsbytecode));            if (mode == JOF_PROP) {                tmp[off] = (format & JOF_SET) ? JSOP_GETPROP2 : JSOP_GETPROP;            } else if (mode == JOF_ELEM) {                tmp[off] = (format & JOF_SET) ? JSOP_GETELEM2 : JSOP_GETELEM;            } else {                /*                 * A zero mode means precisely that op is uncategorized for our                 * purposes, so we must write per-op special case code here.                 */                switch (op) {                  case JSOP_ENUMELEM:                    tmp[off] = JSOP_GETELEM;                    break;#if JS_HAS_LVALUE_RETURN                  case JSOP_SETCALL:                    tmp[off] = JSOP_CALL;                    break;#endif                  default:                    JS_ASSERT(0);                }            }        }        begin = tmp;    } else {        /* No need to revise script bytecode. */        tmp = NULL;    }    jp = js_NewPrinter(cx, "js_DecompileValueGenerator", 0, JS_FALSE);    if (jp && js_DecompileCode(jp, script, begin, len))        name = js_GetPrinterOutput(jp);    else        name = NULL;    js_DestroyPrinter(jp);    if (tmp)        JS_free(cx, tmp);    return name;  do_fallback:    return fallback ? fallback : js_ValueToString(cx, v);}