home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / js / src / jsopcode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  44.6 KB  |  1,826 lines

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * JS bytecode descriptors, disassemblers, and decompilers.
  21.  */
  22. #include <memory.h>
  23. #include <stdarg.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include "prtypes.h"
  28. #ifndef NSPR20
  29. #include "prarena.h"
  30. #else
  31. #include "plarena.h"
  32. #endif
  33. #include "prlog.h"
  34. #include "prdtoa.h"
  35. #include "prprf.h"
  36. #include "jsapi.h"
  37. #include "jsarray.h"
  38. #include "jsatom.h"
  39. #include "jscntxt.h"
  40. #include "jsconfig.h"
  41. #include "jsdbgapi.h"
  42. #include "jsemit.h"
  43. #include "jsfun.h"
  44. #include "jslock.h"
  45. #include "jsobj.h"
  46. #include "jsopcode.h"
  47. #include "jsscope.h"
  48. #include "jsscript.h"
  49. #include "jsstr.h"
  50.  
  51. char js_new_str[]     = "new";
  52. char js_delete_str[]  = "delete";
  53. char js_typeof_str[]  = "typeof";
  54. char js_void_str[]    = "void";
  55. char js_null_str[]    = "null";
  56. char js_this_str[]    = "this";
  57. char js_false_str[]   = "false";
  58. char js_true_str[]    = "true";
  59.  
  60. char *js_incop_str[]  = {"++", "--"};
  61.  
  62. /* Pollute the namespace locally for MSVC Win16, but not for WatCom.  */
  63. #ifdef __WINDOWS_386__
  64.     #ifdef FAR
  65.     #undef FAR
  66.     #endif
  67. #else  /* !__WINDOWS_386__ */
  68.     #ifndef FAR
  69.     #define FAR
  70.     #endif
  71. #endif /* !__WINDOWS_386__ */
  72.  
  73. JSCodeSpec FAR js_CodeSpec[] = {
  74. #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
  75.     {name,token,length,nuses,ndefs,prec,format},
  76. #include "jsopcode.def"
  77. #undef OPDEF
  78. };
  79.  
  80. uintN js_NumCodeSpecs = sizeof js_CodeSpec / sizeof js_CodeSpec[0];
  81.  
  82. /************************************************************************/
  83.  
  84. #ifdef DEBUG
  85.  
  86. void
  87. js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp)
  88. {
  89.     jsbytecode *pc, *end;
  90.     uintN len;
  91.  
  92.     pc = script->code;
  93.     end = pc + script->length;
  94.     while (pc < end) {
  95.     len = js_Disassemble1(cx, script, pc, pc - script->code, lines, fp);
  96.     if (!len)
  97.         return;
  98.     pc += len;
  99.     }
  100. }
  101.  
  102. uintN
  103. js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
  104.         JSBool lines, FILE *fp)
  105. {
  106.     JSOp op;
  107.     JSCodeSpec *cs;
  108.     intN len, off;
  109.     JSAtom *atom;
  110.     JSString *str;
  111.     char *cstr;
  112.  
  113.     op = *pc;
  114.     if (op >= JSOP_LIMIT) {
  115.     JS_ReportError(cx, "bytecode %d too large", op);
  116.     return 0;
  117.     }
  118.     cs = &js_CodeSpec[op];
  119.     len = (intN)cs->length;
  120.     fprintf(fp, "%05u:", loc);
  121.     if (lines)
  122.     fprintf(fp, "%4u", JS_PCToLineNumber(cx, script, pc));
  123.     fprintf(fp, "  %s", cs->name);
  124.     switch (cs->format & JOF_TYPEMASK) {
  125.       case JOF_BYTE:
  126.     if (op == JSOP_TRAP) {
  127.         op = JS_GetTrapOpcode(cx, script, pc);
  128.         if (op == JSOP_LIMIT)
  129.         return 0;
  130.         len = (intN)js_CodeSpec[op].length;
  131.     }
  132.     break;
  133.  
  134.       case JOF_JUMP:
  135.     off = GET_JUMP_OFFSET(pc);
  136.     fprintf(fp, " %u (%d)", loc + off, off);
  137.     break;
  138.  
  139.       case JOF_CONST:
  140.     atom = GET_ATOM(cx, script, pc);
  141.     str = js_ValueToString(cx, ATOM_KEY(atom));
  142.     if (!str)
  143.         return 0;
  144.     cstr = js_DeflateString(cx, str->chars, str->length);
  145.     if (!cstr)
  146.         return 0;
  147.     fprintf(fp, (op == JSOP_STRING) ? " \"%s\"" : " %s", cstr);
  148.     JS_free(cx, cstr);
  149.     break;
  150.  
  151.       case JOF_UINT16:
  152.     fprintf(fp, " %u", GET_ARGC(pc));
  153.     break;
  154.  
  155. #if JS_HAS_SWITCH_STATEMENT
  156.       case JOF_TABLESWITCH:
  157.       {
  158.     jsbytecode *pc2, *end;
  159.     jsint i, low, high;
  160.  
  161.     pc2 = pc;
  162.     off = GET_JUMP_OFFSET(pc2);
  163.     end = pc + off;
  164.     pc2 += 2;
  165.     low = GET_JUMP_OFFSET(pc2);
  166.     pc2 += 2;
  167.     high = GET_JUMP_OFFSET(pc2);
  168.     pc2 += 2;
  169.     fprintf(fp, " defaultOffset %d low %d high %d", off, low, high);
  170.     if (pc2 + 1 < end) {
  171.         for (i = low; i <= high; i++) {
  172.         off = GET_JUMP_OFFSET(pc2);
  173.         fprintf(fp, "\n\t%d: %d", i, off);
  174.         pc2 += 2;
  175.         }
  176.     }
  177.     len = 1 + pc2 - pc;
  178.     break;
  179.       }
  180.  
  181.       case JOF_LOOKUPSWITCH:
  182.       {
  183.     jsbytecode *pc2 = pc;
  184.     uintN npairs;
  185.     jsval key;
  186.  
  187.     off = GET_JUMP_OFFSET(pc2);
  188.     pc2 += 2;
  189.     npairs = (uintN) GET_ATOM_INDEX(pc2);
  190.     pc2 += 2;
  191.     fprintf(fp, " defaultOffset %d npairs %u", off, npairs);
  192.     while (npairs) {
  193.         atom = GET_ATOM(cx, script, pc2);
  194.         pc2 += 2;
  195.         off = GET_JUMP_OFFSET(pc2);
  196.         pc2 += 2;
  197.  
  198.         key = ATOM_KEY(atom);
  199.         str = js_ValueToString(cx, key);
  200.         if (!str)
  201.         return 0;
  202.         cstr = js_DeflateString(cx, str->chars, str->length);
  203.         if (!cstr)
  204.         return 0;
  205.         if (JSVAL_IS_STRING(key))
  206.         fprintf(fp, "\n\t\"%s\": %d", cstr, off);
  207.         else
  208.         fprintf(fp, "\n\t%s: %d", cstr, off);
  209.         JS_free(cx, cstr);
  210.         npairs--;
  211.     }
  212.     len = 1 + pc2 - pc;
  213.     break;
  214.       }
  215. #endif /* JS_HAS_SWITCH_STATEMENT */
  216.  
  217.       case JOF_QARG:
  218.     fprintf(fp, " %u", GET_ARGNO(pc));
  219.     break;
  220.  
  221.       case JOF_QVAR:
  222.     fprintf(fp, " %u", GET_VARNO(pc));
  223.     break;
  224.  
  225.       default:
  226.     JS_ReportError(cx, "unknown bytecode format %x", cs->format);
  227.     return 0;
  228.     }
  229.     fputs("\n", fp);
  230.     return len;
  231. }
  232.  
  233. #endif /* DEBUG */
  234.  
  235. /************************************************************************/
  236.  
  237. /*
  238.  * Sprintf, but with unlimited and automatically allocated buffering.
  239. */
  240. typedef struct Sprinter {
  241.     JSContext       *context;       /* context executing the decompiler */
  242.     PRArenaPool     *pool;          /* string allocation pool */
  243.     char            *base;          /* base address of buffer in pool */
  244.     size_t          size;           /* size of buffer allocated at base */
  245.     ptrdiff_t       offset;         /* offset of next free char in buffer */
  246. } Sprinter;
  247.  
  248. #define INIT_SPRINTER(cx, sp, ap, off) \
  249.     ((sp)->context = cx, (sp)->pool = ap, (sp)->base = NULL, (sp)->size = 0,  \
  250.      (sp)->offset = off)
  251.  
  252. #define OFF2STR(sp,off) ((sp)->base + (off))
  253. #define STR2OFF(sp,str) ((str) - (sp)->base)
  254.  
  255. static JSBool
  256. SprintAlloc(Sprinter *sp, size_t nb)
  257. {
  258.     if (!sp->base) {
  259.     PR_ARENA_ALLOCATE(sp->base, sp->pool, nb);
  260.     } else {
  261.     PR_ARENA_GROW(sp->base, sp->pool, sp->size, nb);
  262.     }
  263.     if (!sp->base) {
  264.     JS_ReportOutOfMemory(sp->context);
  265.     return JS_FALSE;
  266.     }
  267.     sp->size += nb;
  268.     return JS_TRUE;
  269. }
  270.  
  271. static ptrdiff_t
  272. SprintPut(Sprinter *sp, const char *s, size_t len)
  273. {
  274.     ptrdiff_t nb, offset;
  275.     char *bp;
  276.  
  277.     /* Allocate space for s, including the '\0' at the end. */
  278.     nb = (sp->offset + len + 1) - sp->size;
  279.     if (nb > 0 && !SprintAlloc(sp, nb))
  280.     return -1;
  281.  
  282.     /* Advance offset and copy s into sp's buffer. */
  283.     offset = sp->offset;
  284.     sp->offset += len;
  285.     bp = sp->base + offset;
  286.     memcpy(bp, s, len);
  287.     bp[len] = 0;
  288.     return offset;
  289. }
  290.  
  291. static ptrdiff_t
  292. Sprint(Sprinter *sp, const char *format, ...)
  293. {
  294.     va_list ap;
  295.     char *bp;
  296.     ptrdiff_t offset;
  297.  
  298.     va_start(ap, format);
  299.     bp = PR_vsmprintf(format, ap);    /* XXX vsaprintf */
  300.     va_end(ap);
  301.     if (!bp) {
  302.     JS_ReportOutOfMemory(sp->context);
  303.     return -1;
  304.     }
  305.     offset = SprintPut(sp, bp, strlen(bp));
  306.     free(bp);
  307.     return offset;
  308. }
  309.  
  310. jschar js_EscapeMap[] = {
  311.     '\b', 'b',
  312.     '\f', 'f',
  313.     '\n', 'n',
  314.     '\r', 'r',
  315.     '\t', 't',
  316.     '\v', 'v',
  317.     '"',  '"',
  318.     '\'', '\''
  319. };
  320.  
  321. static char *
  322. EscapeString(Sprinter *sp, JSString *str, jschar quote)
  323. {
  324.     ptrdiff_t off, len, nb;
  325.     const jschar *s, *t, *u;
  326.     char *bp;
  327.     jschar c;
  328.     JSBool ok;
  329.  
  330.     off = sp->offset;
  331.     s = str->chars;
  332.     t = s;
  333.     c = *t;
  334.     do {
  335.     while (JS_ISPRINT(c) && c != quote && !(c >> 8))
  336.         c = *++t;
  337.     len = t - s;
  338.  
  339.     /* Allocate space for s, including the '\0' at the end. */
  340.     nb = (sp->offset + len + 1) - sp->size;
  341.     if (nb > 0 && !SprintAlloc(sp, nb))
  342.         return NULL;
  343.  
  344.     /* Advance sp->offset and copy s into sp's buffer. */
  345.     bp = sp->base + sp->offset;
  346.     sp->offset += len;
  347.     while (--len >= 0)
  348.         *bp++ = (char) *s++;
  349.     *bp = '\0';
  350.  
  351.     if (c == 0)
  352.         break;
  353.     if ((u = js_strchr(js_EscapeMap, c)) != NULL)
  354.         ok = Sprint(sp, "\\%c", (char)u[1]) >= 0;
  355.     else
  356.         ok = Sprint(sp, (c >> 8) ? "\\u%04X" : "\\x%02X", c) >= 0;
  357.     if (!ok)
  358.         return NULL;
  359.     s = ++t;
  360.     c = *t;
  361.     } while (c != 0);
  362.     return OFF2STR(sp, off);
  363. }
  364.  
  365. JSString *
  366. js_EscapeString(JSContext *cx, JSString *str, jschar quote)
  367. {
  368.     void *mark;
  369.     Sprinter sprinter;
  370.     char *bytes;
  371.     JSString *escstr;
  372.  
  373.     mark = PR_ARENA_MARK(&cx->tempPool);
  374.     INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
  375.     bytes = EscapeString(&sprinter, str, quote);
  376.     escstr = bytes ? JS_NewStringCopyZ(cx, bytes) : NULL;
  377.     PR_ARENA_RELEASE(&cx->tempPool, mark);
  378.     return escstr;
  379. }
  380.  
  381. /************************************************************************/
  382.  
  383. struct JSPrinter {
  384.     Sprinter        sprinter;       /* base class state */
  385.     PRArenaPool     pool;           /* string allocation pool */
  386.     uintN           indent;         /* indentation in spaces */
  387.     JSScript        *script;        /* script being printed */
  388. };
  389.  
  390. JSPrinter *
  391. js_NewPrinter(JSContext *cx, const char *name, uintN indent)
  392. {
  393.     JSPrinter *jp;
  394.  
  395.     jp = JS_malloc(cx, sizeof(JSPrinter));
  396.     if (!jp)
  397.     return NULL;
  398.     INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0);
  399.     PR_InitArenaPool(&jp->pool, name, 256, 1);
  400.     jp->indent = indent;
  401.     jp->script = NULL;
  402.     return jp;
  403. }
  404.  
  405. void
  406. js_DestroyPrinter(JSPrinter *jp)
  407. {
  408.     PR_FinishArenaPool(&jp->pool);
  409.     JS_free(jp->sprinter.context, jp);
  410. }
  411.  
  412. JSString *
  413. js_GetPrinterOutput(JSPrinter *jp)
  414. {
  415.     JSContext *cx;
  416.     JSString *str;
  417.  
  418.     cx = jp->sprinter.context;
  419.     if (!jp->sprinter.base)
  420.     return cx->runtime->emptyString;
  421.     str = JS_NewStringCopyZ(cx, jp->sprinter.base);
  422.     if (!str)
  423.     return NULL;
  424.     PR_FreeArenaPool(&jp->pool);
  425.     INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0);
  426.     return str;
  427. }
  428.  
  429. int
  430. js_printf(JSPrinter *jp, char *format, ...)
  431. {
  432.     va_list ap;
  433.     char *bp;
  434.     int cc;
  435.  
  436.     va_start(ap, format);
  437.  
  438.     /* Expand magic tab into a run of jp->indent spaces. */
  439.     if (*format == '\t') {
  440.     if (Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0)
  441.         return -1;
  442.     format++;
  443.     }
  444.  
  445.     /* Allocate temp space, convert format, and put. */
  446.     bp = PR_vsmprintf(format, ap);    /* XXX vsaprintf */
  447.     if (!bp) {
  448.     JS_ReportOutOfMemory(jp->sprinter.context);
  449.     return -1;
  450.     }
  451.     cc = strlen(bp);
  452.     if (SprintPut(&jp->sprinter, bp, (size_t)cc) < 0)
  453.     cc = -1;
  454.     free(bp);
  455.  
  456.     va_end(ap);
  457.     return cc;
  458. }
  459.  
  460. JSBool
  461. js_puts(JSPrinter *jp, char *s)
  462. {
  463.     return SprintPut(&jp->sprinter, s, strlen(s)) >= 0;
  464. }
  465.  
  466. /************************************************************************/
  467.  
  468. typedef struct SprintStack {
  469.     Sprinter    sprinter;       /* sprinter for postfix to infix buffering */
  470.     ptrdiff_t   *offsets;       /* stack of postfix string offsets */
  471.     jsbytecode  *opcodes;       /* parallel stack of JS opcodes */
  472.     uintN       top;            /* top of stack index */
  473.     JSPrinter   *printer;       /* permanent output goes here */
  474. } SprintStack;
  475.  
  476. /* Gap between stacked strings to allow for insertion of parens and commas. */
  477. #define PAREN_SLOP    (2 + 1)
  478.  
  479. /*
  480.  * These pseudo-ops help js_ValueToSource decompile JSOP_SETNAME, JSOP_SETPROP,
  481.  * and JSOP_SETELEM, respectively.  See the first assertion in PushOff.
  482.  */
  483. #define JSOP_GETPROP2   (JSOP_GETPROP + 128)
  484. #define JSOP_GETELEM2   (JSOP_GETELEM + 128)
  485.  
  486. static JSBool
  487. PushOff(SprintStack *ss, ptrdiff_t off, JSOp op)
  488. {
  489.     PR_ASSERT(JSOP_LIMIT <= 128);
  490.     if (!SprintAlloc(&ss->sprinter, PAREN_SLOP))
  491.     return JS_FALSE;
  492.     PR_ASSERT(ss->top < ss->printer->script->depth);
  493.     ss->offsets[ss->top] = off;
  494.     ss->opcodes[ss->top++] = (op >= 128) ? op - 128 : op;
  495.     ss->sprinter.offset += PAREN_SLOP;
  496.     return JS_TRUE;
  497. }
  498.  
  499. static ptrdiff_t
  500. PopOff(SprintStack *ss, JSOp op)
  501. {
  502.     uintN top;
  503.     JSCodeSpec *cs, *topcs;
  504.     ptrdiff_t off;
  505.  
  506.     top   = --ss->top;
  507.     cs    = &js_CodeSpec[op];
  508.     topcs = &js_CodeSpec[ss->opcodes[top]];
  509.     if (topcs->prec != 0 && topcs->prec < cs->prec) {
  510.     ss->offsets[top] -= 2;
  511.     ss->sprinter.offset = ss->offsets[top];
  512.     off = Sprint(&ss->sprinter, "(%s)",
  513.              OFF2STR(&ss->sprinter, ss->sprinter.offset + 2));
  514.     } else {
  515.     off = ss->sprinter.offset = ss->offsets[top];
  516.     }
  517.     return off;
  518. }
  519.  
  520. #if JS_HAS_SWITCH_STATEMENT
  521. typedef struct TableEntry {
  522.     jsval       key;
  523.     ptrdiff_t   offset;
  524. } TableEntry;
  525.  
  526. static int
  527. CompareOffsets(const void *v1, const void *v2, void *arg)
  528. {
  529.     const TableEntry *te1 = v1, *te2 = v2;
  530.  
  531.     return te1->offset - te2->offset;
  532. }
  533.  
  534. static JSBool
  535. Decompile(SprintStack *ss, jsbytecode *pc, intN nb);
  536.  
  537. static JSBool
  538. DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
  539.         jsbytecode *pc, ptrdiff_t switchLength, ptrdiff_t defaultOffset)
  540. {
  541.     JSContext *cx;
  542.     JSPrinter *jp;
  543.     char *lval, *rval;
  544.     uintN i;
  545.     ptrdiff_t diff, off, off2;
  546.     jsval key;
  547.     JSString *str;
  548.  
  549.     cx = ss->sprinter.context;
  550.     jp = ss->printer;
  551.  
  552.     lval = OFF2STR(&ss->sprinter, PopOff(ss, JSOP_NOP));
  553.     js_printf(jp, "\tswitch (%s) {\n", lval);
  554.  
  555.     if (tableLength) {
  556.     diff = table[0].offset - defaultOffset;
  557.     if (diff > 0) {
  558.         jp->indent += 2;
  559.         js_printf(jp, "\tdefault:\n");
  560.         jp->indent += 2;
  561.         if (!Decompile(ss, pc + defaultOffset, diff))
  562.         return JS_FALSE;
  563.         jp->indent -= 4;
  564.     }
  565.     for (i = 0; i < tableLength; i++) {
  566.         off = table[i].offset;
  567.         if (i + 1 < tableLength)
  568.         off2 = table[i + 1].offset;
  569.         else
  570.         off2 = switchLength;
  571.         key = table[i].key;
  572.         str = js_ValueToString(cx, key);
  573.         if (!str)
  574.         return JS_FALSE;
  575.         jp->indent += 2;
  576.         if (JSVAL_IS_STRING(key)) {
  577.         rval = EscapeString(&ss->sprinter, str, '"');
  578.         js_printf(jp, "\tcase \"%s\":\n", rval);
  579.         } else {
  580.         js_printf(jp, "\tcase %s:\n", JS_GetStringBytes(str));
  581.         }
  582.         jp->indent += 2;
  583.         if (off <= defaultOffset && defaultOffset < off2) {
  584.         diff = defaultOffset - off;
  585.         if (diff != 0) {
  586.             if (!Decompile(ss, pc + off, diff))
  587.             return JS_FALSE;
  588.             off = defaultOffset;
  589.         }
  590.         jp->indent -= 2;
  591.         js_printf(jp, "\tdefault:\n");
  592.         jp->indent += 2;
  593.         }
  594.         if (!Decompile(ss, pc + off, off2 - off))
  595.         return JS_FALSE;
  596.         jp->indent -= 4;
  597.     }
  598.     }
  599.     if (defaultOffset == switchLength) {
  600.     jp->indent += 2;
  601.     js_printf(jp, "\tdefault:\n");
  602.     jp->indent -= 2;
  603.     }
  604.     js_printf(jp, "\t}\n");
  605.     return JS_TRUE;
  606. }
  607. #endif
  608.  
  609. static JSAtom *
  610. GetSlotAtom(JSSymbol *sym, uintN slot)
  611. {
  612.     for (; sym; sym = sym->next) {
  613.     if ((uintN)JSVAL_TO_INT(sym_property(sym)->id) == slot)
  614.         return sym_atom(sym);
  615.     }
  616.     return NULL;
  617. }
  618.  
  619. static JSBool
  620. Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
  621. {
  622.     JSContext *cx;
  623.     JSPrinter *jp;
  624.     jsbytecode *endpc, *done;
  625.     ptrdiff_t len, todo, cond, next, tail;
  626.     JSOp op, lastop, saveop;
  627.     JSCodeSpec *cs, *topcs;
  628.     jssrcnote *sn;
  629.     const char *lval, *rval, *xval;
  630.     jsint i, argc;
  631.     char **argv;
  632.     JSAtom *atom;
  633.     JSBool ok;
  634.     jsval key;
  635.  
  636. /*
  637.  * Local macros
  638. */
  639. #define DECOMPILE_CODE(pc,nb)    if (!Decompile(ss, pc, nb)) return JS_FALSE
  640. #define POP_STR()        OFF2STR(&ss->sprinter, PopOff(ss, op))
  641. #define LOCAL_ASSERT(expr)    PR_ASSERT(expr); if (!(expr)) return JS_FALSE
  642.  
  643.     cx = ss->sprinter.context;
  644.     jp = ss->printer;
  645.     endpc = pc + nb;
  646.     todo = -2;            /* NB: different from Sprint() error return. */
  647.     op = JSOP_NOP;
  648.     while (pc < endpc) {
  649.     lastop = op;
  650.     op = *pc;
  651.     cs = &js_CodeSpec[op >= 128 ? op - 128 : op];
  652.     len = cs->length;
  653.  
  654.     if (cs->token) {
  655.         switch (cs->nuses) {
  656.           case 2:
  657.         rval = POP_STR();
  658.         lval = POP_STR();
  659.         if ((sn = js_GetSrcNote(jp->script, pc)) &&
  660.             SN_TYPE(sn) == SRC_ASSIGNOP) {
  661.             /* Print only the right operand of the assignment-op. */
  662.             todo = SprintPut(&ss->sprinter, rval, strlen(rval));
  663.         } else {
  664.             todo = Sprint(&ss->sprinter, "%s %s %s",
  665.                   lval, cs->token, rval);
  666.         }
  667.         break;
  668.  
  669.           case 1:
  670.         rval = POP_STR();
  671.         todo = Sprint(&ss->sprinter, "%s%s", cs->token, rval);
  672.         break;
  673.  
  674.           case 0:
  675.         todo = SprintPut(&ss->sprinter, cs->token, strlen(cs->token));
  676.         break;
  677.  
  678.           default:
  679.         todo = -2;
  680.         break;
  681.         }
  682.     } else {
  683.         switch (op) {
  684.           case JSOP_NOP:
  685.         /*
  686.          * Check for extra user parenthesization, a do-while loop,
  687.          * a for-loop with an empty initializer part, or a labeled
  688.          * statement.
  689.          */
  690.         sn = js_GetSrcNote(jp->script, pc);
  691.         todo = -2;
  692.         switch (sn ? SN_TYPE(sn) : SRC_NULL) {
  693.           case SRC_PAREN:
  694.             /* Use last real op so PopOff adds parens if needed. */
  695.             todo = PopOff(ss, lastop);
  696.  
  697.             /* Now add user-supplied parens only if PopOff did not. */
  698.             cs    = &js_CodeSpec[lastop];
  699.             topcs = &js_CodeSpec[ss->opcodes[ss->top]];
  700.             if (topcs->prec >= cs->prec) {
  701.             todo = Sprint(&ss->sprinter, "(%s)",
  702.                       OFF2STR(&ss->sprinter, todo));
  703.             }
  704.             break;
  705.  
  706. #if JS_HAS_DO_WHILE_LOOP
  707.           case SRC_WHILE:
  708.             js_printf(jp, "\tdo {\n");    /* balance} */
  709.             jp->indent += 4;
  710.             break;
  711. #endif /* JS_HAS_DO_WHILE_LOOP */
  712.  
  713.           case SRC_FOR:
  714.             rval = "";
  715.  
  716.           forloop:
  717.             /* Skip the JSOP_NOP or JSOP_POP bytecode. */
  718.             pc++;
  719.  
  720.             /* Get the cond, next, and loop-closing tail offsets. */
  721.             cond = js_GetSrcNoteOffset(sn, 0);
  722.             next = js_GetSrcNoteOffset(sn, 1);
  723.             tail = js_GetSrcNoteOffset(sn, 2);
  724.             LOCAL_ASSERT(tail + GET_JUMP_OFFSET(pc + tail) == 0);
  725.  
  726.             /* Print the keyword and the possibly empty init-part. */
  727.             js_printf(jp, "\tfor (%s;", rval);
  728.  
  729.             if (pc[cond] == JSOP_IFEQ) {
  730.             /* Decompile the loop condition. */
  731.             DECOMPILE_CODE(pc, cond);
  732.             js_printf(jp, " %s", POP_STR());
  733.             }
  734.  
  735.             /* Need a semicolon whether or not there was a cond. */
  736.             js_puts(jp, ";");
  737.  
  738.             if (pc[next] != JSOP_GOTO) {
  739.             /* Decompile the loop updater. */
  740.             DECOMPILE_CODE(pc + next, tail - next - 1);
  741.             js_printf(jp, " %s", POP_STR());
  742.             }
  743.  
  744.             /* Do the loop body. */
  745.             js_puts(jp, ") {\n");
  746.             jp->indent += 4;
  747.             DECOMPILE_CODE(pc + cond + 3, next - cond - 3);
  748.             jp->indent -= 4;
  749.             js_printf(jp, "\t}\n");
  750.  
  751.             /* Set len so pc skips over the entire loop. */
  752.             len = tail + 3;
  753.             break;
  754.  
  755.           case SRC_LABEL:
  756.             atom = js_GetAtom(cx, &jp->script->atomMap,
  757.                       (jsatomid) js_GetSrcNoteOffset(sn, 0));
  758.             jp->indent -= 4;
  759.             js_printf(jp, "\t%s:\n", ATOM_BYTES(atom));
  760.             jp->indent += 4;
  761.             break;
  762.  
  763.           case SRC_LABELBRACE:
  764.             atom = js_GetAtom(cx, &jp->script->atomMap,
  765.                       (jsatomid) js_GetSrcNoteOffset(sn, 0));
  766.             js_printf(jp, "\t%s: {\n", ATOM_BYTES(atom));
  767.             jp->indent += 4;
  768.             break;
  769.  
  770.           case SRC_ENDBRACE:
  771.             jp->indent -= 4;
  772.             js_printf(jp, "\t}\n");
  773.             break;
  774.  
  775.           default:;
  776.         }
  777.         break;
  778.  
  779.           case JSOP_PUSH:
  780.           case JSOP_PUSHOBJ:
  781.         todo = Sprint(&ss->sprinter, "");
  782.         break;
  783.  
  784.           case JSOP_POP:
  785.           case JSOP_POPV:
  786.         sn = js_GetSrcNote(jp->script, pc);
  787.         switch (sn ? SN_TYPE(sn) : SRC_NULL) {
  788.           case SRC_FOR:
  789.             rval = POP_STR();
  790.             todo = -2;
  791.             goto forloop;
  792.  
  793.           case SRC_COMMA:
  794.             /* Pop and save to avoid blowing stack depth budget. */
  795.             lval = JS_strdup(cx, POP_STR());
  796.             if (!lval)
  797.             return JS_FALSE;
  798.  
  799.             /* The offset tells distance to next comma, or to end. */
  800.             done = pc + len;
  801.             pc += js_GetSrcNoteOffset(sn, 0);
  802.             LOCAL_ASSERT(pc == endpc ||
  803.                  *pc == JSOP_POP || *pc == JSOP_POPV ||
  804.                  *pc == JSOP_NOP);
  805.  
  806.             if (!Decompile(ss, done, pc - done)) {
  807.             JS_free(cx, (char *)lval);
  808.             return JS_FALSE;
  809.             }
  810.  
  811.             /* Pop Decompile result and print comma expression. */
  812.             rval = POP_STR();
  813.             todo = Sprint(&ss->sprinter, "%s, %s", lval, rval);
  814.             JS_free(cx, (char *)lval);
  815.             len = 0;
  816.             break;
  817.  
  818.           case SRC_HIDDEN:
  819.             /* Hide this pop, it's from a goto in a with or for/in. */
  820.             todo = -2;
  821.             break;
  822.  
  823.           default:
  824.             rval = POP_STR();
  825.             if (*rval != '\0')
  826.             js_printf(jp, "\t%s;\n", rval);
  827.             todo = -2;
  828.             break;
  829.         }
  830.         break;
  831.  
  832.           case JSOP_ENTERWITH:
  833.         rval = POP_STR();
  834.         js_printf(jp, "\twith (%s) {\n", rval);
  835.         jp->indent += 4;
  836.         todo = -2;
  837.         break;
  838.  
  839.           case JSOP_LEAVEWITH:
  840.         sn = js_GetSrcNote(jp->script, pc);
  841.         todo = -2;
  842.         if (sn && SN_TYPE(sn) == SRC_HIDDEN)
  843.             break;
  844.         jp->indent -= 4;
  845.         js_printf(jp, "\t}\n");
  846.         break;
  847.  
  848.           case JSOP_RETURN:
  849.         rval = POP_STR();
  850.         if (*rval != '\0')
  851.             js_printf(jp, "\t%s %s;\n", cs->name, rval);
  852.         else
  853.             js_printf(jp, "\t%s;\n", cs->name);
  854.         todo = -2;
  855.         break;
  856.  
  857.           case JSOP_GOTO:
  858.         sn = js_GetSrcNote(jp->script, pc);
  859.         switch (sn ? SN_TYPE(sn) : SRC_NULL) {
  860.           case SRC_CONT2LABEL:
  861.             atom = js_GetAtom(cx, &jp->script->atomMap,
  862.                       (jsatomid) js_GetSrcNoteOffset(sn, 0));
  863.             js_printf(jp, "\tcontinue %s;\n", ATOM_BYTES(atom));
  864.             break;
  865.           case SRC_CONTINUE:
  866.             js_printf(jp, "\tcontinue;\n");
  867.             break;
  868.           case SRC_BREAK2LABEL:
  869.             atom = js_GetAtom(cx, &jp->script->atomMap,
  870.                       (jsatomid) js_GetSrcNoteOffset(sn, 0));
  871.             js_printf(jp, "\tbreak %s;\n", ATOM_BYTES(atom));
  872.             break;
  873.           default:
  874.             js_printf(jp, "\tbreak;\n");
  875.             break;
  876.         }
  877.         todo = -2;
  878.         break;
  879.  
  880.           case JSOP_IFEQ:
  881.         len = GET_JUMP_OFFSET(pc);
  882.         sn = js_GetSrcNote(jp->script, pc);
  883.  
  884.         switch (sn ? SN_TYPE(sn) : SRC_NULL) {
  885.           case SRC_IF:
  886.           case SRC_IF_ELSE:
  887.             rval = POP_STR();
  888.             js_printf(jp, "\tif (%s) {\n", rval);
  889.             jp->indent += 4;
  890.             if (SN_TYPE(sn) == SRC_IF) {
  891.             DECOMPILE_CODE(pc + 3, len - 3);
  892.             } else {
  893.             DECOMPILE_CODE(pc + 3, len - 6);
  894.             jp->indent -= 4;
  895.             pc += len - 3;
  896.             len = GET_JUMP_OFFSET(pc);
  897.             js_printf(jp, "\t} else {\n");
  898.             jp->indent += 4;
  899.             DECOMPILE_CODE(pc + 3, len - 3);
  900.             }
  901.             jp->indent -= 4;
  902.             js_printf(jp, "\t}\n");
  903.             todo = -2;
  904.             break;
  905.  
  906.           case SRC_WHILE:
  907.             rval = POP_STR();
  908.             js_printf(jp, "\twhile (%s) {\n", rval);
  909.             jp->indent += 4;
  910.             DECOMPILE_CODE(pc + 3, len - 6);
  911.             jp->indent -= 4;
  912.             js_printf(jp, "\t}\n");
  913.             todo = -2;
  914.             break;
  915.  
  916.           case SRC_COND:
  917.             xval = JS_strdup(cx, POP_STR());
  918.             if (!xval)
  919.             return JS_FALSE;
  920.             DECOMPILE_CODE(pc + 3, len - 6);
  921.             lval = JS_strdup(cx, POP_STR());
  922.             if (!lval) {
  923.             JS_free(cx, (void *)xval);
  924.             return JS_FALSE;
  925.             }
  926.             pc += len - 3;
  927.             LOCAL_ASSERT(*pc == JSOP_GOTO);
  928.             len = GET_JUMP_OFFSET(pc);
  929.             DECOMPILE_CODE(pc + 3, len - 3);
  930.             rval = POP_STR();
  931.             todo = Sprint(&ss->sprinter, "%s ? %s : %s",
  932.                   xval, lval, rval);
  933.             JS_free(cx, (void *)xval);
  934.             JS_free(cx, (void *)lval);
  935.             break;
  936.  
  937.           default:
  938. #if JS_BUG_SHORT_CIRCUIT
  939.             {
  940.             /* top is the first clause in a disjunction (||). */
  941.             jsbytecode *ifeq;
  942.  
  943.             lval = JS_strdup(cx, POP_STR());
  944.             if (!lval)
  945.                 return JS_FALSE;
  946.             ifeq = pc + len;
  947.             LOCAL_ASSERT(pc[3] == JSOP_TRUE);
  948.             pc += 4;
  949.             LOCAL_ASSERT(*pc == JSOP_GOTO);
  950.             done = pc + GET_JUMP_OFFSET(pc);
  951.             pc += 3;
  952.             DECOMPILE_CODE(pc, done - ifeq);
  953.             rval = POP_STR();
  954.             todo = Sprint(&ss->sprinter, "%s || %s", lval, rval);
  955.             JS_free(cx, (void *)lval);
  956.             len = done - pc;
  957.             }
  958. #endif
  959.             break;
  960.         }
  961.         break;
  962.  
  963.           case JSOP_IFNE:
  964. #if JS_HAS_DO_WHILE_LOOP
  965.         /* Check for a do-while loop's upward branch. */
  966.         sn = js_GetSrcNote(jp->script, pc);
  967.         if (sn && SN_TYPE(sn) == SRC_WHILE) {
  968.             jp->indent -= 4;
  969.             /* {balance: */
  970.             js_printf(jp, "\t} while (%s);\n", POP_STR());
  971.             todo = -2;
  972.             break;
  973.         }
  974. #endif /* JS_HAS_DO_WHILE_LOOP */
  975.  
  976. #if JS_BUG_SHORT_CIRCUIT
  977.         {
  978.             jsbytecode *ifne;
  979.  
  980.             /* This bytecode is used only for conjunction (&&). */
  981.             lval = JS_strdup(cx, POP_STR());
  982.             if (!lval)
  983.             return JS_FALSE;
  984.             ifne = pc + GET_JUMP_OFFSET(pc);
  985.             len++;
  986.             pc += len;
  987.             LOCAL_ASSERT(pc[-1] == JSOP_FALSE);
  988.             LOCAL_ASSERT(*pc == JSOP_GOTO);
  989.             done = pc + GET_JUMP_OFFSET(pc);
  990.             pc += 3;
  991.             DECOMPILE_CODE(pc, done - ifne);
  992.             rval = POP_STR();
  993.             todo = Sprint(&ss->sprinter, "%s && %s", lval, rval);
  994.             JS_free(cx, (void *)lval);
  995.             len = done - pc;
  996.         }
  997. #endif
  998.         break;
  999.  
  1000. #if !JS_BUG_SHORT_CIRCUIT
  1001.           case JSOP_OR:
  1002.         /* Top of stack is the first clause in a disjunction (||). */
  1003.         lval = JS_strdup(cx, POP_STR());
  1004.         if (!lval)
  1005.             return JS_FALSE;
  1006.         done = pc + GET_JUMP_OFFSET(pc);
  1007.         pc += len;
  1008.         len = done - pc;
  1009.         DECOMPILE_CODE(pc, len);
  1010.         rval = POP_STR();
  1011.         todo = Sprint(&ss->sprinter, "%s || %s", lval, rval);
  1012.         JS_free(cx, (char *)lval);
  1013.         break;
  1014.  
  1015.           case JSOP_AND:
  1016.         /* Top of stack is the first clause in a conjunction (&&). */
  1017.         lval = JS_strdup(cx, POP_STR());
  1018.         if (!lval)
  1019.             return JS_FALSE;
  1020.         done = pc + GET_JUMP_OFFSET(pc);
  1021.         pc += len;
  1022.         len = done - pc;
  1023.         DECOMPILE_CODE(pc, len);
  1024.         rval = POP_STR();
  1025.         todo = Sprint(&ss->sprinter, "%s && %s", lval, rval);
  1026.         JS_free(cx, (char *)lval);
  1027.         break;
  1028. #endif
  1029.  
  1030.           case JSOP_FORNAME:
  1031.         atom = GET_ATOM(cx, jp->script, pc);
  1032.         rval = POP_STR();
  1033.         xval = 0;
  1034.         lval = ATOM_BYTES(atom);
  1035.         sn = js_GetSrcNote(jp->script, pc);
  1036.         pc += 3;
  1037.         goto do_forinloop;
  1038.  
  1039.           case JSOP_FORPROP:
  1040.         atom = GET_ATOM(cx, jp->script, pc);
  1041.         rval = POP_STR();
  1042.         xval = 0;
  1043.         lval = POP_STR();
  1044.         sn = NULL;
  1045.         pc += 3;
  1046.         goto do_forinloop;
  1047.  
  1048.           case JSOP_FORELEM:
  1049.         rval = POP_STR();
  1050.         xval = POP_STR();
  1051.         lval = POP_STR();
  1052.         sn = NULL;
  1053.         pc++;
  1054.  
  1055.           do_forinloop:
  1056.         LOCAL_ASSERT(*pc == JSOP_IFEQ);
  1057.         len = GET_JUMP_OFFSET(pc);
  1058.         js_printf(jp, "\tfor (%s%s",
  1059.               (sn && SN_TYPE(sn) == SRC_VAR) ? "var " : "", lval);
  1060.         if (xval)
  1061.             js_printf(jp, "[%s]", xval);
  1062.         js_printf(jp, " in %s) {\n", rval);
  1063.         jp->indent += 4;
  1064.         DECOMPILE_CODE(pc + 3, len - 6);
  1065.         jp->indent -= 4;
  1066.         js_printf(jp, "\t}\n");
  1067.         todo = -2;
  1068.         break;
  1069.  
  1070.           case JSOP_DUP2:
  1071.         rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-2]);
  1072.         todo = SprintPut(&ss->sprinter, rval, strlen(rval));
  1073.         if (todo < 0 || !PushOff(ss, todo, op))
  1074.             return JS_FALSE;
  1075.         /* FALL THROUGH */
  1076.  
  1077.           case JSOP_DUP:
  1078.         rval = OFF2STR(&ss->sprinter, ss->offsets[ss->top-1]);
  1079.         todo = SprintPut(&ss->sprinter, rval, strlen(rval));
  1080.         break;
  1081.  
  1082.           case JSOP_SETARG:
  1083.         atom = GetSlotAtom(jp->script->args, GET_ARGNO(pc));
  1084.         LOCAL_ASSERT(atom);
  1085.         goto do_setname;
  1086.  
  1087.           case JSOP_SETVAR:
  1088.         atom = GetSlotAtom(jp->script->vars, GET_VARNO(pc));
  1089.         LOCAL_ASSERT(atom);
  1090.         goto do_setname;
  1091.  
  1092.           case JSOP_SETNAME:
  1093.         atom = GET_ATOM(cx, jp->script, pc);
  1094.           do_setname:
  1095.         lval = ATOM_BYTES(atom);
  1096.         rval = POP_STR();
  1097.         if ((sn = js_GetSrcNote(jp->script, pc - 1)) &&
  1098.             SN_TYPE(sn) == SRC_ASSIGNOP) {
  1099.             todo = Sprint(&ss->sprinter, "%s %s= %s",
  1100.                   lval, js_CodeSpec[pc[-1]].token, rval);
  1101.         } else {
  1102.             sn = js_GetSrcNote(jp->script, pc);
  1103.             todo = Sprint(&ss->sprinter, "%s%s = %s",
  1104.                   (sn && SN_TYPE(sn) == SRC_VAR) ? "var " : "",
  1105.                   lval, rval);
  1106.         }
  1107.         break;
  1108.  
  1109.           case JSOP_NEW:
  1110.           case JSOP_CALL:
  1111.         saveop = op;
  1112.         op = JSOP_NOP;           /* turn off parens */
  1113.         argc = GET_ARGC(pc);
  1114.         argv = JS_malloc(cx, (size_t)(argc + 1) * sizeof *argv);
  1115.         if (!argv)
  1116.             return JS_FALSE;
  1117.  
  1118.         ok = JS_TRUE;
  1119.         for (i = argc; i > 0; i--) {
  1120.             argv[i] = JS_strdup(cx, POP_STR());
  1121.             if (!argv[i]) {
  1122.             ok = JS_FALSE;
  1123.             break;
  1124.             }
  1125.         }
  1126.  
  1127.         /* Skip the JSOP_PUSHOBJ-created empty string. */
  1128.         LOCAL_ASSERT(ss->top >= 2);
  1129.         (void) PopOff(ss, op);
  1130.  
  1131.         /* Get the callee's decompiled image in argv[0]. */
  1132.         argv[0] = JS_strdup(cx, POP_STR());
  1133.         if (!argv[i])
  1134.             ok = JS_FALSE;
  1135.  
  1136.         lval = "(", rval = ")";
  1137.         if (saveop == JSOP_NEW) {
  1138.             todo = Sprint(&ss->sprinter, "%s %s%s",
  1139.                   js_new_str, argv[0], lval);
  1140.         } else {
  1141.             todo = Sprint(&ss->sprinter, "%s%s",
  1142.                   argv[0], lval);
  1143.         }
  1144.         if (todo < 0)
  1145.             ok = JS_FALSE;
  1146.  
  1147.         for (i = 1; i <= argc; i++) {
  1148.             if (!argv[i] ||
  1149.             Sprint(&ss->sprinter, "%s%s",
  1150.                    argv[i], (i < argc) ? ", " : "") < 0) {
  1151.             ok = JS_FALSE;
  1152.             break;
  1153.             }
  1154.         }
  1155.         if (Sprint(&ss->sprinter, rval) < 0)
  1156.             ok = JS_FALSE;
  1157.  
  1158.         for (i = 0; i <= argc; i++) {
  1159.             if (argv[i])
  1160.             JS_free(cx, argv[i]);
  1161.         }
  1162.         JS_free(cx, argv);
  1163.         if (!ok)
  1164.             return JS_FALSE;
  1165.         op = saveop;
  1166.         break;
  1167.  
  1168.           case JSOP_DELNAME:
  1169.         atom = GET_ATOM(cx, jp->script, pc);
  1170.         lval = ATOM_BYTES(atom);
  1171.         todo = Sprint(&ss->sprinter, "%s %s", js_delete_str, lval);
  1172.         break;
  1173.  
  1174.           case JSOP_DELPROP:
  1175.         atom = GET_ATOM(cx, jp->script, pc);
  1176.         lval = POP_STR();
  1177.         todo = Sprint(&ss->sprinter, "%s %s.%s",
  1178.                   js_delete_str, lval, ATOM_BYTES(atom));
  1179.         break;
  1180.  
  1181.           case JSOP_DELELEM:
  1182.         xval = POP_STR();
  1183.         lval = POP_STR();
  1184.         todo = Sprint(&ss->sprinter, "%s %s[%s]",
  1185.                   js_delete_str, lval, xval);
  1186.         break;
  1187.  
  1188.           case JSOP_TYPEOF:
  1189.           case JSOP_VOID:
  1190.         rval = POP_STR();
  1191.         todo = Sprint(&ss->sprinter, "%s %s", cs->name, rval);
  1192.         break;
  1193.  
  1194.           case JSOP_INCARG:
  1195.           case JSOP_DECARG:
  1196.         atom = GetSlotAtom(jp->script->args, GET_ARGNO(pc));
  1197.         LOCAL_ASSERT(atom);
  1198.         goto do_incatom;
  1199.  
  1200.           case JSOP_INCVAR:
  1201.           case JSOP_DECVAR:
  1202.         atom = GetSlotAtom(jp->script->vars, GET_VARNO(pc));
  1203.         LOCAL_ASSERT(atom);
  1204.         goto do_incatom;
  1205.  
  1206.           case JSOP_INCNAME:
  1207.           case JSOP_DECNAME:
  1208.         atom = GET_ATOM(cx, jp->script, pc);
  1209.           do_incatom:
  1210.         lval = ATOM_BYTES(atom);
  1211.         todo = Sprint(&ss->sprinter, "%s%s",
  1212.                   js_incop_str[!(cs->format & JOF_INC)], lval);
  1213.         break;
  1214.  
  1215.           case JSOP_INCPROP:
  1216.           case JSOP_DECPROP:
  1217.         atom = GET_ATOM(cx, jp->script, pc);
  1218.         lval = POP_STR();
  1219.         todo = Sprint(&ss->sprinter, "%s%s.%s",
  1220.                   js_incop_str[!(cs->format & JOF_INC)],
  1221.                   lval, ATOM_BYTES(atom));
  1222.         break;
  1223.  
  1224.           case JSOP_INCELEM:
  1225.           case JSOP_DECELEM:
  1226.         xval = POP_STR();
  1227.         lval = POP_STR();
  1228.         todo = Sprint(&ss->sprinter, "%s%s[%s]",
  1229.                   js_incop_str[!(cs->format & JOF_INC)],
  1230.                   lval, xval);
  1231.         break;
  1232.  
  1233.           case JSOP_ARGINC:
  1234.           case JSOP_ARGDEC:
  1235.         atom = GetSlotAtom(jp->script->args, GET_ARGNO(pc));
  1236.         LOCAL_ASSERT(atom);
  1237.         goto do_atominc;
  1238.  
  1239.           case JSOP_VARINC:
  1240.           case JSOP_VARDEC:
  1241.         atom = GetSlotAtom(jp->script->vars, GET_VARNO(pc));
  1242.         LOCAL_ASSERT(atom);
  1243.         goto do_atominc;
  1244.  
  1245.           case JSOP_NAMEINC:
  1246.           case JSOP_NAMEDEC:
  1247.         atom = GET_ATOM(cx, jp->script, pc);
  1248.           do_atominc:
  1249.         lval = ATOM_BYTES(atom);
  1250.         todo = Sprint(&ss->sprinter, "%s%s",
  1251.                   lval, js_incop_str[!(cs->format & JOF_INC)]);
  1252.         break;
  1253.  
  1254.           case JSOP_PROPINC:
  1255.           case JSOP_PROPDEC:
  1256.         atom = GET_ATOM(cx, jp->script, pc);
  1257.         lval = POP_STR();
  1258.         todo = Sprint(&ss->sprinter, "%s.%s%s",
  1259.                   lval, ATOM_BYTES(atom),
  1260.                   js_incop_str[!(cs->format & JOF_INC)]);
  1261.         break;
  1262.  
  1263.           case JSOP_ELEMINC:
  1264.           case JSOP_ELEMDEC:
  1265.         xval = POP_STR();
  1266.         lval = POP_STR();
  1267.         todo = Sprint(&ss->sprinter, "%s[%s]%s",
  1268.                   lval, xval,
  1269.                   js_incop_str[!(cs->format & JOF_INC)]);
  1270.         break;
  1271.  
  1272.           case JSOP_GETPROP2:
  1273.         op = JSOP_GETPROP;
  1274.         (void) PopOff(ss, lastop);
  1275.         /* FALL THROUGH */
  1276.  
  1277.           case JSOP_GETPROP:
  1278.         atom = GET_ATOM(cx, jp->script, pc);
  1279.         lval = POP_STR();
  1280.         todo = Sprint(&ss->sprinter, "%s.%s", lval, ATOM_BYTES(atom));
  1281.         break;
  1282.  
  1283.           case JSOP_SETPROP:
  1284.         rval = POP_STR();
  1285.         atom = GET_ATOM(cx, jp->script, pc);
  1286.         lval = POP_STR();
  1287.         if ((sn = js_GetSrcNote(jp->script, pc - 1)) &&
  1288.             SN_TYPE(sn) == SRC_ASSIGNOP) {
  1289.             todo = Sprint(&ss->sprinter, "%s.%s %s= %s",
  1290.                   lval, ATOM_BYTES(atom),
  1291.                   js_CodeSpec[pc[-1]].token, rval);
  1292.         } else {
  1293.             todo = Sprint(&ss->sprinter, "%s.%s = %s",
  1294.                   lval, ATOM_BYTES(atom), rval);
  1295.         }
  1296.         break;
  1297.  
  1298.           case JSOP_GETELEM2:
  1299.         op = JSOP_GETELEM;
  1300.         (void) PopOff(ss, lastop);
  1301.         /* FALL THROUGH */
  1302.  
  1303.           case JSOP_GETELEM:
  1304.         op = JSOP_NOP;           /* turn off parens */
  1305.         xval = POP_STR();
  1306.         op = JSOP_GETELEM;
  1307.         lval = POP_STR();
  1308.         todo = Sprint(&ss->sprinter, "%s[%s]", lval, xval);
  1309.         break;
  1310.  
  1311.           case JSOP_SETELEM:
  1312.         op = JSOP_NOP;           /* turn off parens */
  1313.         rval = POP_STR();
  1314.         xval = POP_STR();
  1315.         op = JSOP_SETELEM;
  1316.         lval = POP_STR();
  1317.         if ((sn = js_GetSrcNote(jp->script, pc - 1)) &&
  1318.             SN_TYPE(sn) == SRC_ASSIGNOP) {
  1319.             todo = Sprint(&ss->sprinter, "%s[%s] %s= %s",
  1320.                   lval, xval,
  1321.                   js_CodeSpec[pc[-1]].token, rval);
  1322.         } else {
  1323.             todo = Sprint(&ss->sprinter, "%s[%s] = %s",
  1324.                   lval, xval, rval);
  1325.         }
  1326.         break;
  1327.  
  1328.           case JSOP_GETARG:
  1329.         atom = GetSlotAtom(jp->script->args, GET_ARGNO(pc));
  1330.         LOCAL_ASSERT(atom);
  1331.         goto do_name;
  1332.  
  1333.           case JSOP_GETVAR:
  1334.         atom = GetSlotAtom(jp->script->vars, GET_VARNO(pc));
  1335.         LOCAL_ASSERT(atom);
  1336.         goto do_name;
  1337.  
  1338.           case JSOP_NAME:
  1339.         atom = GET_ATOM(cx, jp->script, pc);
  1340.           do_name:
  1341.         sn = js_GetSrcNote(jp->script, pc);
  1342.         todo = Sprint(&ss->sprinter,
  1343.                   (sn && SN_TYPE(sn) == SRC_VAR) ? "var %s" : "%s",
  1344.                   ATOM_BYTES(atom));
  1345.         break;
  1346.  
  1347.           case JSOP_UINT16:
  1348.         i = (jsint) GET_ATOM_INDEX(pc);
  1349.         todo = Sprint(&ss->sprinter, "%u", (unsigned) i);
  1350.         break;
  1351.  
  1352.           case JSOP_NUMBER:
  1353.           case JSOP_STRING:
  1354.           case JSOP_OBJECT:
  1355.         atom = GET_ATOM(cx, jp->script, pc);
  1356.         key = ATOM_KEY(atom);
  1357.         if (JSVAL_IS_INT(key)) {
  1358.             long ival = (long)JSVAL_TO_INT(key);
  1359.             todo = Sprint(&ss->sprinter, "%ld", ival);
  1360.         } else if (JSVAL_IS_DOUBLE(key)) {
  1361.             char buf[32];
  1362.             PR_cnvtf(buf, sizeof buf, 20, *JSVAL_TO_DOUBLE(key));
  1363.             todo = Sprint(&ss->sprinter, buf);
  1364.         } else if (JSVAL_IS_STRING(key)) {
  1365.             rval = EscapeString(&ss->sprinter, ATOM_TO_STRING(atom),
  1366.                     '"');
  1367.             if (!rval)
  1368.             return JS_FALSE;
  1369.             todo = Sprint(&ss->sprinter, "\"%s\"", rval);
  1370.         } else if (JSVAL_IS_OBJECT(key)) {
  1371.             JSString *str = js_ObjectToString(cx, JSVAL_TO_OBJECT(key));
  1372.             if (!str)
  1373.             return JS_FALSE;
  1374.             todo = SprintPut(&ss->sprinter,
  1375.                      JS_GetStringBytes(str),
  1376.                      str->length);
  1377.         } else {
  1378.             todo = -2;
  1379.         }
  1380.         break;
  1381.  
  1382. #if JS_HAS_SWITCH_STATEMENT
  1383.           case JSOP_TABLESWITCH:
  1384.           {
  1385.         jsbytecode *pc2, *end;
  1386.         ptrdiff_t off, off2;
  1387.         jsint j, n, low, high;
  1388.         TableEntry *table;
  1389.  
  1390.         sn = js_GetSrcNote(jp->script, pc);
  1391.         len = js_GetSrcNoteOffset(sn, 0);
  1392.         pc2 = pc;
  1393.         off = GET_JUMP_OFFSET(pc2);
  1394.         end = pc + off;
  1395.         pc2 += 2;
  1396.         low = GET_JUMP_OFFSET(pc2);
  1397.         pc2 += 2;
  1398.         high = GET_JUMP_OFFSET(pc2);
  1399.  
  1400.         n = high - low + 1;
  1401.         table = JS_malloc(cx, (size_t)n * sizeof *table);
  1402.         if (!table)
  1403.             return JS_FALSE;
  1404.         if (pc2 + 3 >= end) {
  1405.             j = 0;
  1406.         } else {
  1407.             for (i = j = 0; i < n; i++) {
  1408.             pc2 += 2;
  1409.             off2 = GET_JUMP_OFFSET(pc2);
  1410.             if (off2) {
  1411.                 table[j].key = INT_TO_JSVAL(low + i);
  1412.                 table[j++].offset = off2;
  1413.             }
  1414.             }
  1415.         }
  1416.         js_qsort(table, (size_t)j, sizeof *table, CompareOffsets, NULL);
  1417.  
  1418.         ok = DecompileSwitch(ss, table, (uintN)j, pc, len, off);
  1419.         JS_free(cx, table);
  1420.         if (!ok)
  1421.             return ok;
  1422.         todo = -2;
  1423.         break;
  1424.           }
  1425.  
  1426.           case JSOP_LOOKUPSWITCH:
  1427.           {
  1428.         jsbytecode *pc2 = pc;
  1429.         ptrdiff_t off, off2;
  1430.         jsint npairs;
  1431.         TableEntry *table;
  1432.  
  1433.         sn = js_GetSrcNote(jp->script, pc);
  1434.         len = js_GetSrcNoteOffset(sn, 0);
  1435.         off = GET_JUMP_OFFSET(pc2);
  1436.         pc2 += 2;
  1437.         npairs = (jsint) GET_ATOM_INDEX(pc2);
  1438.  
  1439.         table = JS_malloc(cx, (size_t)npairs * sizeof *table);
  1440.         if (!table)
  1441.             return JS_FALSE;
  1442.         for (i = 0; i < npairs; i++) {
  1443.             pc2 += 2;
  1444.             atom = GET_ATOM(cx, jp->script, pc2);
  1445.             pc2 += 2;
  1446.             off2 = GET_JUMP_OFFSET(pc2);
  1447.             table[i].key = ATOM_KEY(atom);
  1448.             table[i].offset = off2;
  1449.         }
  1450.  
  1451.         ok = DecompileSwitch(ss, table, (uintN)npairs, pc, len, off);
  1452.         JS_free(cx, table);
  1453.         if (!ok)
  1454.             return ok;
  1455.         todo = -2;
  1456.         break;
  1457.           }
  1458. #endif /* JS_HAS_SWITCH_STATEMENT */
  1459.  
  1460. #if !JS_BUG_FALLIBLE_EQOPS
  1461.           case JSOP_NEW_EQ:
  1462.           case JSOP_NEW_NE:
  1463.         rval = POP_STR();
  1464.         lval = POP_STR();
  1465.         todo = Sprint(&ss->sprinter, "%s %c%s %s",
  1466.                   lval,
  1467.                   (op == JSOP_NEW_EQ) ? '=' : '!',
  1468. #if JS_HAS_TRIPLE_EQOPS
  1469.                   JSVERSION_IS_ECMA(cx->version) ? "==" :
  1470. #endif
  1471.                   "=",
  1472.                   rval);
  1473.         break;
  1474. #endif /* !JS_BUG_FALLIBLE_EQOPS */
  1475.  
  1476. #if JS_HAS_LEXICAL_CLOSURE
  1477.           case JSOP_CLOSURE:
  1478.           {
  1479.         JSObject *obj;
  1480.         JSFunction *fun;
  1481.         JSPrinter *jp2;
  1482.         JSString *str;
  1483.  
  1484.         atom = GET_ATOM(cx, jp->script, pc);
  1485.         PR_ASSERT(ATOM_IS_OBJECT(atom));
  1486.         obj = ATOM_TO_OBJECT(atom);
  1487.         fun = JS_GetPrivate(cx, obj);
  1488.         jp2 = js_NewPrinter(cx,
  1489.                     fun->atom ? ATOM_BYTES(fun->atom) : NULL,
  1490.                     jp->indent);
  1491.         if (!jp2)
  1492.             return JS_FALSE;
  1493.         todo = -1;
  1494.         if (js_DecompileFunction(jp2, fun, JS_FALSE)) {
  1495.             str = js_GetPrinterOutput(jp2);
  1496.             if (str) {
  1497.             todo = SprintPut(&ss->sprinter,
  1498.                      JS_GetStringBytes(str),
  1499.                      str->length);
  1500.             }
  1501.         }
  1502.         js_DestroyPrinter(jp2);
  1503.         break;
  1504.           }
  1505. #endif /* JS_HAS_LEXICAL_CLOSURE */
  1506.  
  1507. #if JS_HAS_EXPORT_IMPORT
  1508.           case JSOP_EXPORTALL:
  1509.         js_printf(jp, "\texport *\n");
  1510.         todo = -2;
  1511.         break;
  1512.  
  1513.           case JSOP_EXPORTNAME:
  1514.         atom = GET_ATOM(cx, jp->script, pc);
  1515.         js_printf(jp, "\texport %s\n", ATOM_BYTES(atom));
  1516.         todo = -2;
  1517.         break;
  1518.  
  1519.           case JSOP_IMPORTALL:
  1520.         lval = POP_STR();
  1521.         js_printf(jp, "\timport %s.*\n", lval);
  1522.         todo = -2;
  1523.         break;
  1524.  
  1525.           case JSOP_IMPORTPROP:
  1526.         atom = GET_ATOM(cx, jp->script, pc);
  1527.         lval = POP_STR();
  1528.         js_printf(jp, "\timport %s.%s\n", lval, ATOM_BYTES(atom));
  1529.         todo = -2;
  1530.         break;
  1531.  
  1532.           case JSOP_IMPORTELEM:
  1533.         xval = POP_STR();
  1534.         op = JSOP_GETELEM;
  1535.         lval = POP_STR();
  1536.         js_printf(jp, "\timport %s[%s]\n", lval, xval);
  1537.         todo = -2;
  1538.         break;
  1539. #endif /* JS_HAS_EXPORT_IMPORT */
  1540.  
  1541.           case JSOP_TRAP:
  1542.         op = JS_GetTrapOpcode(cx, jp->script, pc);
  1543.         if (op == JSOP_LIMIT)
  1544.             return JS_FALSE;
  1545.         *pc = op;
  1546.         cs = &js_CodeSpec[op];
  1547.         len = cs->length;
  1548.         DECOMPILE_CODE(pc, len);
  1549.         *pc = JSOP_TRAP;
  1550.         todo = -2;
  1551.         break;
  1552.  
  1553. #ifdef JS_HAS_OBJECT_LITERAL
  1554.           case JSOP_NEWINIT:
  1555.         LOCAL_ASSERT(ss->top >= 2);
  1556.         (void) PopOff(ss, op);
  1557.         lval = POP_STR();
  1558. #if JS_HAS_SHARP_VARS
  1559.         op = pc[len];
  1560.         if (op == JSOP_DEFSHARP) {
  1561.             pc += len;
  1562.             cs = &js_CodeSpec[op];
  1563.             len = cs->length;
  1564.             i = (jsint) GET_ATOM_INDEX(pc);
  1565.             todo = Sprint(&ss->sprinter, "#%u=%c",
  1566.                   (unsigned) i,
  1567.                   (*lval == 'O') ? '{' : '[');
  1568.             /* balance}] */
  1569.         } else
  1570. #endif /* JS_HAS_SHARP_VARS */
  1571.         {
  1572.             todo = Sprint(&ss->sprinter, (*lval == 'O') ? "{" : "[");
  1573.             /* balance}] */
  1574.         }
  1575.         break;
  1576.  
  1577.           case JSOP_ENDINIT:
  1578.         rval = POP_STR();
  1579.         sn = js_GetSrcNote(jp->script, pc);
  1580.         todo = Sprint(&ss->sprinter, "%s%s%c",
  1581.                   rval,
  1582.                   (sn && SN_TYPE(sn) == SRC_COMMA) ? ", " : "",
  1583.                   /* [balance */
  1584.                   (*rval == '{') ? '}' : ']');
  1585.         break;
  1586.  
  1587.           case JSOP_INITPROP:
  1588.         rval = POP_STR();
  1589.         atom = GET_ATOM(cx, jp->script, pc);
  1590.         xval = ATOM_BYTES(atom);
  1591.         lval = POP_STR();
  1592.           do_initprop:
  1593.         todo = Sprint(&ss->sprinter, "%s%s%s:%s",
  1594.                   lval, (lval[1] != '\0') ? ", " : "",
  1595.                   xval, rval);
  1596.         break;
  1597.  
  1598.           case JSOP_INITELEM:
  1599.         rval = POP_STR();
  1600.         xval = POP_STR();
  1601.         lval = POP_STR();
  1602.         sn = js_GetSrcNote(jp->script, pc);
  1603.         if (sn && SN_TYPE(sn) == SRC_LABEL)
  1604.             goto do_initprop;
  1605.         todo = Sprint(&ss->sprinter, "%s%s%s",
  1606.                   lval,
  1607.                   (lval[1] != '\0' || *xval != '0') ? ", " : "",
  1608.                   rval);
  1609.         break;
  1610.  
  1611. #if JS_HAS_SHARP_VARS
  1612.           case JSOP_USESHARP:
  1613.         i = (jsint) GET_ATOM_INDEX(pc);
  1614.         todo = Sprint(&ss->sprinter, "#%u#", (unsigned) i);
  1615. #endif /* JS_HAS_SHARP_VARS */
  1616. #endif /* JS_HAS_OBJECT_LITERAL */
  1617.  
  1618.           default:
  1619.         todo = -2;
  1620.         break;
  1621.         }
  1622.     }
  1623.  
  1624.     if (todo < 0) {
  1625.         if (todo == -1)
  1626.         return JS_FALSE;
  1627.     } else {
  1628.         if (!PushOff(ss, todo, op))
  1629.         return JS_FALSE;
  1630.     }
  1631.     pc += len;
  1632.     }
  1633.  
  1634. /*
  1635.  * Undefine local macros.
  1636.  */
  1637. #undef DECOMPILE_CODE
  1638. #undef POP_STR
  1639. #undef LOCAL_ASSERT
  1640.  
  1641.     return JS_TRUE;
  1642. }
  1643.  
  1644.  
  1645. JSBool
  1646. js_DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len)
  1647. {
  1648.     SprintStack ss;
  1649.     JSContext *cx;
  1650.     void *mark;
  1651.     JSScript *oldscript;
  1652.     JSBool ok;
  1653.     char *last;
  1654.  
  1655.     /* Initialize a sprinter for use with the offset stack. */
  1656.     ss.printer = jp;
  1657.     cx = jp->sprinter.context;
  1658.     mark = PR_ARENA_MARK(&cx->tempPool);
  1659.     INIT_SPRINTER(cx, &ss.sprinter, &cx->tempPool, PAREN_SLOP);
  1660.  
  1661.     /* Initialize the offset and opcode stacks. */
  1662.     ss.offsets = JS_malloc(cx, script->depth * sizeof *ss.offsets);
  1663.     ss.opcodes = JS_malloc(cx, script->depth * sizeof *ss.opcodes);
  1664.     if (!ss.offsets || !ss.opcodes) {
  1665.     if (ss.offsets)
  1666.         JS_free(cx, ss.offsets);
  1667.     return JS_FALSE;
  1668.     }
  1669.     ss.top = 0;
  1670.  
  1671.     /* Call recursive subroutine to do the hard work. */
  1672.     oldscript = jp->script;
  1673.     jp->script = script;
  1674.     ok = Decompile(&ss, pc, len);
  1675.     jp->script = oldscript;
  1676.  
  1677.     /* If the given code didn't empty the stack, do it now. */
  1678.     if (ss.top) {
  1679.     do {
  1680.         last = OFF2STR(&ss.sprinter, PopOff(&ss, JSOP_NOP));
  1681.     } while (ss.top);
  1682.     js_printf(jp, "%s", last);
  1683.     }
  1684.  
  1685.     /* Free and clear temporary stuff. */
  1686.     JS_free(cx, ss.offsets);
  1687.     JS_free(cx, ss.opcodes);
  1688.     PR_ARENA_RELEASE(&cx->tempPool, mark);
  1689.     return ok;
  1690. }
  1691.  
  1692. JSBool
  1693. js_DecompileScript(JSPrinter *jp, JSScript *script)
  1694. {
  1695.     PR_ASSERT(JS_IS_LOCKED(jp->sprinter.context));
  1696.     return js_DecompileCode(jp, script, script->code, (uintN)script->length);
  1697. }
  1698.  
  1699. JSBool
  1700. js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines)
  1701. {
  1702.     JSSymbol *arg;
  1703.     JSAtom *atom;
  1704.     uintN indent;
  1705.  
  1706.     PR_ASSERT(JS_IS_LOCKED(jp->sprinter.context));
  1707.     if (newlines) {
  1708.     js_puts(jp, "\n");
  1709.     js_printf(jp, "\t");
  1710.     }
  1711.     js_printf(jp, "function %s(", fun->atom ? ATOM_BYTES(fun->atom) : "");
  1712.     if (fun->script) {
  1713.     for (arg = fun->script->args; arg; arg = arg->next) {
  1714.         atom = sym_atom(arg);
  1715.         js_printf(jp, "%s%s", ATOM_BYTES(atom), arg->next ? ", " : "");
  1716.     }
  1717.     }
  1718.     js_puts(jp, ") {\n");
  1719.     indent = jp->indent;
  1720.     jp->indent += 4;
  1721.     if (fun->call) {
  1722.     js_printf(jp, "\t[native code]\n");
  1723.     } else {
  1724.     if (!js_DecompileScript(jp, fun->script)) {
  1725.         jp->indent = indent;
  1726.         return JS_FALSE;
  1727.     }
  1728.     }
  1729.     jp->indent -= 4;
  1730.     js_printf(jp, "\t}");
  1731.     if (newlines)
  1732.     js_puts(jp, "\n");
  1733.     return JS_TRUE;
  1734. }
  1735.  
  1736. JSString *
  1737. js_ValueToSource(JSContext *cx, jsval v)
  1738. {
  1739.     JSStackFrame *fp;
  1740.     JSScript *script;
  1741.     jsbytecode *pc, *begin, *end, *tmp;
  1742.     uint32 format, mode;
  1743.     intN depth;
  1744.     jsval *limit;
  1745.     jssrcnote *sn;
  1746.     uintN len;
  1747.     JSPrinter *jp;
  1748.     JSString *name;
  1749.  
  1750.     fp = cx->fp;
  1751.     script = fp->script;
  1752.     if (!script)
  1753.     return JS_ValueToString(cx, v);
  1754.  
  1755.     pc = fp->pc;
  1756.     format = js_CodeSpec[*pc].format;
  1757.     mode = (format & JOF_MODEMASK);
  1758.  
  1759.     /* Don't look on the stack for element ops, the index will throw us. */
  1760.     if (mode != JOF_ELEM) {
  1761.     limit = (jsval *)cx->stackPool.current->avail;
  1762.     depth = (intN)script->depth;
  1763.     if (fp->sp < limit && fp->sp[0] == v)
  1764.         pc = (jsbytecode *)fp->sp[0 - depth];
  1765.     if (!pc && fp->sp + 1 < limit && fp->sp[1] == v)
  1766.         pc = (jsbytecode *)fp->sp[1 - depth];
  1767.  
  1768.     if (pc != fp->pc) {
  1769.         if ((pruword)(pc - script->code) >= (pruword)script->length) {
  1770.         pc = fp->pc;
  1771.         } else {
  1772.         format = js_CodeSpec[*pc].format;
  1773.         mode = (format & JOF_MODEMASK);
  1774.         }
  1775.     }
  1776.     }
  1777.  
  1778.     if (mode != JOF_NAME &&
  1779.     (!(sn = js_GetSrcNote(script, pc)) ||
  1780.      SN_TYPE(sn) != SRC_PCBASE)) {
  1781.     return JS_ValueToString(cx, v);
  1782.     }
  1783.  
  1784.     if (mode == JOF_NAME) {
  1785.     begin = pc;
  1786.     end = pc + 3;
  1787.     } else {
  1788.     begin = pc - js_GetSrcNoteOffset(sn, 0);
  1789.     end = fp->pc;
  1790.     }
  1791.     len = end - begin;
  1792.  
  1793.     if (format & (JOF_SET | JOF_DEL | JOF_INCDEC | JOF_IMPORT)) {
  1794.     /* These ops require bytecode source extension. */
  1795.     tmp = JS_malloc(cx, (len + 3) * sizeof(jsbytecode));
  1796.     if (!tmp)
  1797.         return NULL;
  1798.     memcpy(tmp, begin, len * sizeof(jsbytecode));
  1799.     if (mode == JOF_NAME) {
  1800.         tmp[0] = JSOP_NAME;
  1801.     } else if (mode == JOF_PROP) {
  1802.         tmp[len++] = (format & JOF_SET) ? JSOP_GETPROP2 : JSOP_GETPROP;
  1803.         tmp[len++] = pc[1];
  1804.         tmp[len++] = pc[2];
  1805.     } else {
  1806.         tmp[len++] = (format & JOF_SET) ? JSOP_GETELEM2 : JSOP_GETELEM;
  1807.     }
  1808.     begin = tmp;
  1809.     } else {
  1810.     /* No need to extend script bytecode. */
  1811.     tmp = NULL;
  1812.     }
  1813.  
  1814.     JS_LOCK(cx);
  1815.     jp = js_NewPrinter(cx, "js_ValueToSource", 0);
  1816.     if (jp && js_DecompileCode(jp, script, begin, len))
  1817.     name = js_GetPrinterOutput(jp);
  1818.     else
  1819.     name = NULL;
  1820.     js_DestroyPrinter(jp);
  1821.     JS_UNLOCK(cx);
  1822.     if (tmp)
  1823.     JS_free(cx, tmp);
  1824.     return name;
  1825. }
  1826.