/[jscoverage]/trunk/js/jsopcode.cpp
ViewVC logotype

Diff of /trunk/js/jsopcode.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 332 by siliconforks, Thu Oct 23 19:03:33 2008 UTC revision 399 by siliconforks, Tue Dec 9 03:37:47 2008 UTC
# Line 63  Line 63 
63  #include "jsemit.h"  #include "jsemit.h"
64  #include "jsfun.h"  #include "jsfun.h"
65  #include "jsiter.h"  #include "jsiter.h"
66    #include "jsnum.h"
67  #include "jsobj.h"  #include "jsobj.h"
68  #include "jsopcode.h"  #include "jsopcode.h"
69  #include "jsregexp.h"  #include "jsregexp.h"
# Line 71  Line 72 
72  #include "jsscript.h"  #include "jsscript.h"
73  #include "jsstr.h"  #include "jsstr.h"
74  #include "jsstaticcheck.h"  #include "jsstaticcheck.h"
75    #include "jstracer.h"
 #if JS_HAS_DESTRUCTURING  
 # include "jsnum.h"  
 #endif  
76    
77  #include "jsautooplen.h"  #include "jsautooplen.h"
78    
# Line 85  Line 83 
83  #undef OPDEF  #undef OPDEF
84    
85  static const char js_incop_strs[][3] = {"++", "--"};  static const char js_incop_strs[][3] = {"++", "--"};
86    static const char js_for_each_str[]  = "for each";
87    
88  const JSCodeSpec js_CodeSpec[] = {  const JSCodeSpec js_CodeSpec[] = {
89  #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \  #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
# Line 106  Line 105 
105  #undef OPDEF  #undef OPDEF
106  };  };
107    
108  #ifdef DEBUG  #if defined(DEBUG) || defined(JS_JIT_SPEW)
109  /*  /*
110   * Array of JS bytecode names used by DEBUG-only js_Disassemble.   * Array of JS bytecode names used by DEBUG-only js_Disassemble and by
111     * JIT debug spew.
112   */   */
113  const char *js_CodeName[] = {  const char *js_CodeName[] = {
114  #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \  #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
# Line 215  Line 215 
215        default:        default:
216          /* stack: fun, this, [argc arguments] */          /* stack: fun, this, [argc arguments] */
217          JS_ASSERT(op == JSOP_NEW || op == JSOP_CALL ||          JS_ASSERT(op == JSOP_NEW || op == JSOP_CALL ||
218                    op == JSOP_EVAL || op == JSOP_SETCALL);                    op == JSOP_EVAL || op == JSOP_SETCALL ||
219                      op == JSOP_APPLY);
220          return 2 + GET_ARGC(pc);          return 2 + GET_ARGC(pc);
221      }      }
222  }  }
# Line 684  Line 685 
685      JSPackedBool    grouped;        /* in parenthesized expression context */      JSPackedBool    grouped;        /* in parenthesized expression context */
686      JSScript        *script;        /* script being printed */      JSScript        *script;        /* script being printed */
687      jsbytecode      *dvgfence;      /* DecompileExpression fencepost */      jsbytecode      *dvgfence;      /* DecompileExpression fencepost */
688      jsbytecode      **pcstack;      /* DecompileExpression modelled stack */      jsbytecode      **pcstack;      /* DecompileExpression modeled stack */
689      JSFunction      *fun;           /* interpreted function */      JSFunction      *fun;           /* interpreted function */
690      jsuword         *localNames;    /* argument and variable names */      jsuword         *localNames;    /* argument and variable names */
691  };  };
# Line 968  Line 969 
969  }  }
970    
971  static ptrdiff_t  static ptrdiff_t
972  PopOff(SprintStack *ss, JSOp op)  PopOffPrec(SprintStack *ss, uint8 prec)
973  {  {
974      uintN top;      uintN top;
975      const JSCodeSpec *cs, *topcs;      const JSCodeSpec *topcs;
976      ptrdiff_t off;      ptrdiff_t off;
977    
978      /* ss->top points to the next free slot; be paranoid about underflow. */      /* ss->top points to the next free slot; be paranoid about underflow. */
# Line 983  Line 984 
984      ss->top = --top;      ss->top = --top;
985      off = GetOff(ss, top);      off = GetOff(ss, top);
986      topcs = &js_CodeSpec[ss->opcodes[top]];      topcs = &js_CodeSpec[ss->opcodes[top]];
987      cs = &js_CodeSpec[op];      if (topcs->prec != 0 && topcs->prec < prec) {
     if (topcs->prec != 0 && topcs->prec < cs->prec) {  
988          ss->sprinter.offset = ss->offsets[top] = off - 2;          ss->sprinter.offset = ss->offsets[top] = off - 2;
989          off = Sprint(&ss->sprinter, "(%s)", OFF2STR(&ss->sprinter, off));          off = Sprint(&ss->sprinter, "(%s)", OFF2STR(&ss->sprinter, off));
990      } else {      } else {
# Line 994  Line 994 
994  }  }
995    
996  static const char *  static const char *
997  PopStr(SprintStack *ss, JSOp op)  PopStrPrec(SprintStack *ss, uint8 prec)
998  {  {
999      ptrdiff_t off;      ptrdiff_t off;
1000    
1001      off = PopOff(ss, op);      off = PopOffPrec(ss, prec);
1002      return OFF2STR(&ss->sprinter, off);      return OFF2STR(&ss->sprinter, off);
1003  }  }
1004    
1005    static ptrdiff_t
1006    PopOff(SprintStack *ss, JSOp op)
1007    {
1008        return PopOffPrec(ss, js_CodeSpec[op].prec);
1009    }
1010    
1011    static const char *
1012    PopStr(SprintStack *ss, JSOp op)
1013    {
1014        return PopStrPrec(ss, js_CodeSpec[op].prec);
1015    }
1016    
1017  typedef struct TableEntry {  typedef struct TableEntry {
1018      jsval       key;      jsval       key;
1019      ptrdiff_t   offset;      ptrdiff_t   offset;
# Line 1270  Line 1282 
1282  #undef LOCAL_ASSERT  #undef LOCAL_ASSERT
1283  }  }
1284    
 #if JS_HAS_DESTRUCTURING  
   
 #define LOCAL_ASSERT(expr)  LOCAL_ASSERT_RV(expr, NULL)  
 #define LOAD_OP_DATA(pc)    (oplen = (cs = &js_CodeSpec[op=(JSOp)*pc])->length)  
   
1285  static JSBool  static JSBool
1286  IsVarSlot(JSPrinter *jp, jsbytecode *pc, jsint *indexp)  IsVarSlot(JSPrinter *jp, jsbytecode *pc, jsint *indexp)
1287  {  {
# Line 1294  Line 1301 
1301      return JS_FALSE;      return JS_FALSE;
1302  }  }
1303    
1304    #if JS_HAS_DESTRUCTURING
1305    
1306    #define LOCAL_ASSERT(expr)  LOCAL_ASSERT_RV(expr, NULL)
1307    #define LOAD_OP_DATA(pc)    (oplen = (cs = &js_CodeSpec[op=(JSOp)*pc])->length)
1308    
1309  static jsbytecode *  static jsbytecode *
1310  DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc);  DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc);
1311    
# Line 1709  Line 1721 
1721  {  {
1722      JSContext *cx;      JSContext *cx;
1723      JSPrinter *jp, *jp2;      JSPrinter *jp, *jp2;
1724      jsbytecode *startpc, *endpc, *pc2, *done, *forelem_tail, *forelem_done;      jsbytecode *startpc, *endpc, *pc2, *done;
1725      ptrdiff_t tail, todo, len, oplen, cond, next;      ptrdiff_t tail, todo, len, oplen, cond, next;
1726      JSOp op, lastop, saveop;      JSOp op, lastop, saveop;
1727      const JSCodeSpec *cs;      const JSCodeSpec *cs;
# Line 1731  Line 1743 
1743    
1744      static const char exception_cookie[] = "/*EXCEPTION*/";      static const char exception_cookie[] = "/*EXCEPTION*/";
1745      static const char retsub_pc_cookie[] = "/*RETSUB_PC*/";      static const char retsub_pc_cookie[] = "/*RETSUB_PC*/";
1746        static const char iter_cookie[]      = "/*ITER*/";
1747      static const char forelem_cookie[]   = "/*FORELEM*/";      static const char forelem_cookie[]   = "/*FORELEM*/";
1748      static const char with_cookie[]      = "/*WITH*/";      static const char with_cookie[]      = "/*WITH*/";
1749      static const char dot_format[]       = "%s.%s";      static const char dot_format[]       = "%s.%s";
# Line 1740  Line 1753 
1753      static const char preindex_format[]  = "%s%s[%s]";      static const char preindex_format[]  = "%s%s[%s]";
1754      static const char postindex_format[] = "%s[%s]%s";      static const char postindex_format[] = "%s[%s]%s";
1755      static const char ss_format[]        = "%s%s";      static const char ss_format[]        = "%s%s";
1756        static const char sss_format[]       = "%s%s%s";
1757    
1758      /* Argument and variables decompilation uses the following to share code. */      /* Argument and variables decompilation uses the following to share code. */
1759      JS_STATIC_ASSERT(ARGNO_LEN == SLOTNO_LEN);      JS_STATIC_ASSERT(ARGNO_LEN == SLOTNO_LEN);
# Line 1747  Line 1761 
1761  /*  /*
1762   * Local macros   * Local macros
1763   */   */
1764    #define LOCAL_ASSERT(expr)    LOCAL_ASSERT_RV(expr, NULL)
1765  #define DECOMPILE_CODE(pc,nb) if (!Decompile(ss, pc, nb, JSOP_NOP)) return NULL  #define DECOMPILE_CODE(pc,nb) if (!Decompile(ss, pc, nb, JSOP_NOP)) return NULL
1766  #define NEXT_OP(pc)           (((pc) + (len) == endpc) ? nextop : pc[len])  #define NEXT_OP(pc)           (((pc) + (len) == endpc) ? nextop : pc[len])
1767    #define TOP_STR()             GetStr(ss, ss->top - 1)
1768  #define POP_STR()             PopStr(ss, op)  #define POP_STR()             PopStr(ss, op)
1769  #define LOCAL_ASSERT(expr)    LOCAL_ASSERT_RV(expr, NULL)  #define POP_STR_PREC(prec)    PopStrPrec(ss, prec)
1770    
1771    /*
1772     * Pop a condition expression for if/for/while. JSOP_IFEQ's precedence forces
1773     * extra parens around assignment, which avoids a strict-mode warning.
1774     */
1775    #define POP_COND_STR()                                                        \
1776        PopStr(ss, (js_CodeSpec[ss->opcodes[ss->top - 1]].format & JOF_SET)       \
1777                   ? JSOP_IFEQ                                                    \
1778                   : JSOP_NOP)
1779    
1780  /*  /*
1781   * Callers know that ATOM_IS_STRING(atom), and we leave it to the optimizer to   * Callers know that ATOM_IS_STRING(atom), and we leave it to the optimizer to
# Line 1811  Line 1836 
1836          GET_QUOTE_AND_FMT(qfmt, ufmt, rval);                                  \          GET_QUOTE_AND_FMT(qfmt, ufmt, rval);                                  \
1837      JS_END_MACRO      JS_END_MACRO
1838    
1839    /*
1840     * Per spec, new x(y).z means (new x(y))).z. For example new (x(y).z) must
1841     * decompile with the constructor parenthesized, but new x.z should not. The
1842     * normal rules give x(y).z and x.z identical precedence: both are produced by
1843     * JSOP_GETPROP.
1844     *
1845     * Therefore, we need to know in case JSOP_NEW whether the constructor
1846     * expression contains any unparenthesized function calls. So when building a
1847     * MemberExpression or CallExpression, we set ss->opcodes[n] to JSOP_CALL if
1848     * this is true. x(y).z gets JSOP_CALL, not JSOP_GETPROP.
1849     */
1850    #define PROPAGATE_CALLNESS()                                                  \
1851        JS_BEGIN_MACRO                                                            \
1852            if (ss->opcodes[ss->top - 1] == JSOP_CALL)                            \
1853                saveop = JSOP_CALL;                                               \
1854        JS_END_MACRO
1855    
1856      cx = ss->sprinter.context;      cx = ss->sprinter.context;
1857      JS_CHECK_RECURSION(cx, return NULL);      JS_CHECK_RECURSION(cx, return NULL);
1858    
1859      jp = ss->printer;      jp = ss->printer;
1860      startpc = pc;      startpc = pc;
1861      endpc = (nb < 0) ? jp->script->code + jp->script->length : pc + nb;      endpc = (nb < 0) ? jp->script->code + jp->script->length : pc + nb;
     forelem_tail = forelem_done = NULL;  
1862      tail = -1;      tail = -1;
1863      todo = -2;                  /* NB: different from Sprint() error return. */      todo = -2;                  /* NB: different from Sprint() error return. */
1864      saveop = JSOP_NOP;      saveop = JSOP_NOP;
# Line 1987  Line 2028 
2028                       * problem).                       * problem).
2029                       */                       */
2030                      op = (JSOp) pc[oplen];                      op = (JSOp) pc[oplen];
2031                      LOCAL_ASSERT(op != saveop);                      rval = POP_STR();
2032                  }                      lval = POP_STR();
                 rval = POP_STR();  
                 lval = POP_STR();  
                 if (op != saveop) {  
2033                      /* Print only the right operand of the assignment-op. */                      /* Print only the right operand of the assignment-op. */
2034                      todo = SprintCString(&ss->sprinter, rval);                      todo = SprintCString(&ss->sprinter, rval);
2035                      op = saveop;                      op = saveop;
2036                  } else if (!inXML) {                  } else if (!inXML) {
2037                        rval = POP_STR_PREC(cs->prec + !!(cs->format & JOF_LEFTASSOC));
2038                        lval = POP_STR_PREC(cs->prec + !(cs->format & JOF_LEFTASSOC));
2039                      todo = Sprint(&ss->sprinter, "%s %s %s",                      todo = Sprint(&ss->sprinter, "%s %s %s",
2040                                    lval, token, rval);                                    lval, token, rval);
2041                  } else {                  } else {
2042                      /* In XML, just concatenate the two operands. */                      /* In XML, just concatenate the two operands. */
2043                      LOCAL_ASSERT(op == JSOP_ADD);                      LOCAL_ASSERT(op == JSOP_ADD);
2044                        rval = POP_STR();
2045                        lval = POP_STR();
2046                      todo = Sprint(&ss->sprinter, ss_format, lval, rval);                      todo = Sprint(&ss->sprinter, ss_format, lval, rval);
2047                  }                  }
2048                  break;                  break;
# Line 2038  Line 2080 
2080                      jp->indent += 4;                      jp->indent += 4;
2081                      DECOMPILE_CODE(pc, tail);                      DECOMPILE_CODE(pc, tail);
2082                      jp->indent -= 4;                      jp->indent -= 4;
2083                      js_printf(jp, "\t} while (%s);\n", POP_STR());                      js_printf(jp, "\t} while (%s);\n", POP_COND_STR());
2084                      pc += tail;                      pc += tail;
2085                      len = js_CodeSpec[*pc].length;                      len = js_CodeSpec[*pc].length;
2086                      todo = -2;                      todo = -2;
# Line 2048  Line 2090 
2090                      rval = "";                      rval = "";
2091    
2092                    do_forloop:                    do_forloop:
2093                        JS_ASSERT(SN_TYPE(sn) == SRC_FOR);
2094    
2095                      /* Skip the JSOP_NOP or JSOP_POP bytecode. */                      /* Skip the JSOP_NOP or JSOP_POP bytecode. */
2096                      pc++;                      pc += JSOP_NOP_LENGTH;
2097    
2098                      /* Get the cond, next, and loop-closing tail offsets. */                      /* Get the cond, next, and loop-closing tail offsets. */
2099                      cond = js_GetSrcNoteOffset(sn, 0);                      cond = js_GetSrcNoteOffset(sn, 0);
# Line 2060  Line 2104 
2104                       * If this loop has a condition, then pc points at a goto                       * If this loop has a condition, then pc points at a goto
2105                       * targeting the condition.                       * targeting the condition.
2106                       */                       */
2107                        pc2 = pc;
2108                      if (cond != tail) {                      if (cond != tail) {
2109                          LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);                          LOCAL_ASSERT(*pc == JSOP_GOTO || *pc == JSOP_GOTOX);
2110                          pc += (*pc == JSOP_GOTO)                          pc2 += (*pc == JSOP_GOTO) ? JSOP_GOTO_LENGTH : JSOP_GOTOX_LENGTH;
                               ? JSOP_GOTO_LENGTH  
                               : JSOP_GOTOX_LENGTH;  
2111                      }                      }
2112                      LOCAL_ASSERT(tail == -GetJumpOffset(pc+tail, pc+tail));                      LOCAL_ASSERT(tail + GetJumpOffset(pc+tail, pc+tail) == pc2 - pc);
2113    
2114                      /* Print the keyword and the possibly empty init-part. */                      /* Print the keyword and the possibly empty init-part. */
2115                      js_printf(jp, "\tfor (%s;", rval);                      js_printf(jp, "\tfor (%s;", rval);
# Line 2081  Line 2124 
2124                      js_puts(jp, ";");                      js_puts(jp, ";");
2125    
2126                      if (next != cond) {                      if (next != cond) {
2127                          /* Decompile the loop updater. */                          /*
2128                          DECOMPILE_CODE(pc + next,                           * Decompile the loop updater. It may end in a JSOP_POP
2129                                         cond - next - JSOP_POP_LENGTH);                           * that we skip; or in a JSOP_POPN that we do not skip,
2130                          js_printf(jp, " %s", POP_STR());                           * followed by a JSOP_NOP (skipped as if it's a POP).
2131                             * We cope with the difference between these two cases
2132                             * by checking for stack imbalance and popping if there
2133                             * is an rval.
2134                             */
2135                            uintN saveTop = ss->top;
2136    
2137                            DECOMPILE_CODE(pc + next, cond - next - JSOP_POP_LENGTH);
2138                            LOCAL_ASSERT(ss->top - saveTop <= 1U);
2139                            rval = (ss->top == saveTop)
2140                                   ? ss->sprinter.base + ss->sprinter.offset
2141                                   : POP_STR();
2142                            js_printf(jp, " %s", rval);
2143                      }                      }
2144    
2145                      /* Do the loop body. */                      /* Do the loop body. */
2146                      js_printf(jp, ") {\n");                      js_printf(jp, ") {\n");
2147                      jp->indent += 4;                      jp->indent += 4;
2148                      DECOMPILE_CODE(pc, next);                      next -= pc2 - pc;
2149                        DECOMPILE_CODE(pc2, next);
2150                      jp->indent -= 4;                      jp->indent -= 4;
2151                      js_printf(jp, "\t}\n");                      js_printf(jp, "\t}\n");
2152    
# Line 2156  Line 2212 
2212                  }                  }
2213                  break;                  break;
2214    
               case JSOP_GROUP:  
                 cs = &js_CodeSpec[lastop];  
                 if ((cs->prec != 0 &&  
                      cs->prec <= js_CodeSpec[NEXT_OP(pc)].prec) ||  
                     pc[JSOP_GROUP_LENGTH] == JSOP_NULL ||  
                     pc[JSOP_GROUP_LENGTH] == JSOP_NULLTHIS ||  
                     pc[JSOP_GROUP_LENGTH] == JSOP_DUP ||  
                     pc[JSOP_GROUP_LENGTH] == JSOP_IFEQ ||  
                     pc[JSOP_GROUP_LENGTH] == JSOP_IFNE) {  
                     /*  
                      * Force parens if this JSOP_GROUP forced re-association  
                      * against precedence, or if this is a call or constructor  
                      * expression, or if it is destructured (JSOP_DUP), or if  
                      * it is an if or loop condition test.  
                      *  
                      * This is necessary to handle the operator new grammar,  
                      * by which new x(y).z means (new x(y))).z.  For example  
                      * new (x(y).z) must decompile with the constructor  
                      * parenthesized, but normal precedence has JSOP_GETPROP  
                      * (for the final .z) higher than JSOP_NEW.  In general,  
                      * if the call or constructor expression is parenthesized,  
                      * we preserve parens.  
                      */  
                     op = JSOP_NAME;  
                     rval = POP_STR();  
                     todo = SprintCString(&ss->sprinter, rval);  
                 } else {  
                     /*  
                      * Don't explicitly parenthesize -- just fix the top  
                      * opcode so that the auto-parens magic in PopOff can do  
                      * its thing.  
                      */  
                     LOCAL_ASSERT(ss->top != 0);  
                     ss->opcodes[ss->top-1] = saveop = lastop;  
                     todo = -2;  
                 }  
                 break;  
   
2215                case JSOP_PUSH:                case JSOP_PUSH:
2216  #if JS_HAS_DESTRUCTURING  #if JS_HAS_DESTRUCTURING
2217                  sn = js_GetSrcNote(jp->script, pc);                  sn = js_GetSrcNote(jp->script, pc);
# Line 2254  Line 2272 
2272    
2273                case JSOP_POPN:                case JSOP_POPN:
2274                {                {
2275                  uintN newtop, oldtop, i;                  uintN newtop, oldtop;
2276    
2277                  /*                  /*
2278                   * The compiler models operand stack depth and fixes the stack                   * The compiler models operand stack depth and fixes the stack
# Line 2276  Line 2294 
2294                                    VarPrefix(sn));                                    VarPrefix(sn));
2295                      if (todo < 0)                      if (todo < 0)
2296                          return NULL;                          return NULL;
2297                      for (i = newtop; i < oldtop; i++) {                      for (uintN i = newtop; i < oldtop; i++) {
2298                          rval = OFF2STR(&ss->sprinter, ss->offsets[i]);                          rval = OFF2STR(&ss->sprinter, ss->offsets[i]);
2299                          if (Sprint(&ss->sprinter, ss_format,                          if (Sprint(&ss->sprinter, ss_format,
2300                                     (i == newtop) ? "" : ", ",                                     (i == newtop) ? "" : ", ",
# Line 2289  Line 2307 
2307                          return NULL;                          return NULL;
2308    
2309                      /*                      /*
2310                       * Kill newtop before the end_groupassignment: label by                       * If this is an empty group assignment, we have no stack
2311                       * retracting/popping early.  Control will either jump to                       * budget into which we can push our result string. Adjust
2312                       * do_forloop: or do_letheadbody: or else break from our                       * ss->sprinter.offset so that our consumer can find the
2313                       * case JSOP_POPN: after the switch (*pc2) below.                       * empty group assignment decompilation.
2314                       */                       */
2315                      if (newtop < oldtop) {                      if (newtop == oldtop) {
2316                            ss->sprinter.offset = todo;
2317                        } else {
2318                            /*
2319                             * Kill newtop before the end_groupassignment: label by
2320                             * retracting/popping early.  Control will either jump
2321                             * to do_forloop: or do_letheadbody: or else break from
2322                             * our case JSOP_POPN: after the switch (*pc2) below.
2323                             */
2324                            LOCAL_ASSERT(newtop < oldtop);
2325                          ss->sprinter.offset = GetOff(ss, newtop);                          ss->sprinter.offset = GetOff(ss, newtop);
2326                          ss->top = newtop;                          ss->top = newtop;
2327                      }                      }
2328    
2329                    end_groupassignment:                    end_groupassignment:
2330                        LOCAL_ASSERT(*pc == JSOP_POPN);
2331    
2332                      /*                      /*
2333                       * Thread directly to the next opcode if we can, to handle                       * Thread directly to the next opcode if we can, to handle
2334                       * the special cases of a group assignment in the first or                       * the special cases of a group assignment in the first or
# Line 2314  Line 2343 
2343                      rval = OFF2STR(&ss->sprinter, todo);                      rval = OFF2STR(&ss->sprinter, todo);
2344                      todo = -2;                      todo = -2;
2345                      pc2 = pc + oplen;                      pc2 = pc + oplen;
2346                      switch (*pc2) {                      if (*pc2 == JSOP_NOP) {
                       case JSOP_NOP:  
                         /* First part of for(;;) or let block/expr head. */  
2347                          sn = js_GetSrcNote(jp->script, pc2);                          sn = js_GetSrcNote(jp->script, pc2);
2348                          if (sn) {                          if (sn) {
2349                              if (SN_TYPE(sn) == SRC_FOR) {                              if (SN_TYPE(sn) == SRC_FOR) {
2350                                    op = JSOP_NOP;
2351                                  pc = pc2;                                  pc = pc2;
2352                                  goto do_forloop;                                  goto do_forloop;
2353                              }                              }
2354    
2355                              if (SN_TYPE(sn) == SRC_DECL) {                              if (SN_TYPE(sn) == SRC_DECL) {
2356                                  if (ss->top == StackDepth(jp->script)) {                                  if (ss->top == StackDepth(jp->script)) {
2357                                      /*                                      /*
# Line 2330  Line 2359 
2359                                       * in the head of a let whose body block                                       * in the head of a let whose body block
2360                                       * is also empty.                                       * is also empty.
2361                                       */                                       */
2362                                      pc = pc2 + 1;                                      pc = pc2 + JSOP_NOP_LENGTH;
2363                                      len = js_GetSrcNoteOffset(sn, 0);                                      len = js_GetSrcNoteOffset(sn, 0);
2364                                      LOCAL_ASSERT(pc[len] == JSOP_LEAVEBLOCK);                                      LOCAL_ASSERT(pc[len] == JSOP_LEAVEBLOCK);
2365                                      js_printf(jp, "\tlet (%s) {\n", rval);                                      js_printf(jp, "\tlet (%s) {\n", rval);
2366                                      js_printf(jp, "\t}\n");                                      js_printf(jp, "\t}\n");
2367                                      goto end_popn;                                      break;
2368                                  }                                  }
2369                                  todo = SprintCString(&ss->sprinter, rval);                                  todo = SprintCString(&ss->sprinter, rval);
2370                                  if (todo < 0 || !PushOff(ss, todo, JSOP_NOP))                                  if (todo < 0 || !PushOff(ss, todo, JSOP_NOP))
2371                                      return NULL;                                      return NULL;
2372                                  op = JSOP_POP;                                  op = JSOP_POP;
2373                                  pc = pc2 + 1;                                  pc = pc2 + JSOP_NOP_LENGTH;
2374                                  goto do_letheadbody;                                  goto do_letheadbody;
2375                              }                              }
2376                          }                          } else {
2377                          break;                              /*
2378                                 * An unnannotated NOP following a POPN must be the
2379                        case JSOP_GOTO:                               * third part of for(;;) loop head. If the POPN's
2380                        case JSOP_GOTOX:                               * immediate operand is 0, then we may have no slot
2381                          /* Third part of for(;;) loop head. */                               * on the sprint-stack in which to push our result
2382                          cond = GetJumpOffset(pc2, pc2);                               * string. In this case the result can be recovered
2383                          sn = js_GetSrcNote(jp->script, pc2 + cond - 1);                               * at ss->sprinter.base + ss->sprinter.offset.
2384                          if (sn && SN_TYPE(sn) == SRC_FOR) {                               */
2385                                if (GET_UINT16(pc) == 0)
2386                                    break;
2387                              todo = SprintCString(&ss->sprinter, rval);                              todo = SprintCString(&ss->sprinter, rval);
2388                              saveop = JSOP_NOP;                              saveop = JSOP_NOP;
2389                          }                          }
                         break;  
2390                      }                      }
2391    
2392                      /*                      /*
# Line 2365  Line 2395 
2395                       */                       */
2396                      if (todo == -2)                      if (todo == -2)
2397                          js_printf(jp, "\t%s;\n", rval);                          js_printf(jp, "\t%s;\n", rval);
                   end_popn:  
2398                      break;                      break;
2399                  }                  }
2400  #endif  #endif
# Line 2452  Line 2481 
2481                      } else {                      } else {
2482                          LOCAL_ASSERT(pc[len] == JSOP_LEAVEBLOCKEXPR);                          LOCAL_ASSERT(pc[len] == JSOP_LEAVEBLOCKEXPR);
2483    
2484                          lval = JS_strdup(cx, POP_STR());                          lval = JS_strdup(cx, PopStr(ss, JSOP_NOP));
2485                          if (!lval)                          if (!lval)
2486                              return NULL;                              return NULL;
2487    
# Line 2462  Line 2491 
2491                              JS_free(cx, (char *)lval);                              JS_free(cx, (char *)lval);
2492                              return NULL;                              return NULL;
2493                          }                          }
2494                          rval = POP_STR();                          rval = PopStr(ss, JSOP_SETNAME);
2495                          todo = Sprint(&ss->sprinter,                          todo = Sprint(&ss->sprinter,
2496                                        (*rval == '{')                                        (*rval == '{')
2497                                        ? "let (%s) (%s)"                                        ? "let (%s) (%s)"
# Line 2503  Line 2532 
2532                  sn = NULL;                  sn = NULL;
2533                  break;                  break;
2534    
               case JSOP_ENDITER:  
                 sn = js_GetSrcNote(jp->script, pc);  
                 todo = -2;  
                 if (sn && SN_TYPE(sn) == SRC_HIDDEN)  
                     break;  
                 (void) PopOff(ss, op);  
                 break;  
   
2535                case JSOP_ENTERWITH:                case JSOP_ENTERWITH:
2536                  LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc));                  LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc));
2537                  rval = POP_STR();                  rval = POP_STR();
# Line 2724  Line 2745 
2745    
2746                case JSOP_CALLUPVAR:                case JSOP_CALLUPVAR:
2747                case JSOP_GETUPVAR:                case JSOP_GETUPVAR:
2748    
2749                    if (!jp->fun)
2750                        JS_GET_SCRIPT_FUNCTION(jp->script, 0, jp->fun);
2751    
2752                    if (!jp->localNames)
2753                        jp->localNames = js_GetLocalNameArray(cx, jp->fun, &jp->pool);
2754    
2755                  i = JS_UPVAR_LOCAL_NAME_START(jp->fun) + GET_UINT16(pc);                  i = JS_UPVAR_LOCAL_NAME_START(jp->fun) + GET_UINT16(pc);
2756                  if (i >= JS_GET_LOCAL_NAME_COUNT(jp->fun)) {                  if (i >= JS_GET_LOCAL_NAME_COUNT(jp->fun)) {
                     JSStackFrame *fp;  
2757                      JSUpvarArray *uva;                      JSUpvarArray *uva;
2758    #ifdef DEBUG
2759                      /*                      /*
2760                       * We must be in an eval called from jp->fun, where                       * We must be in an eval called from jp->fun, where
2761                       * jp->script is the eval-compiled script.                       * jp->script is the eval-compiled script.
# Line 2738  Line 2765 
2765                       * object that's not a constructor, causing us to be                       * object that's not a constructor, causing us to be
2766                       * called with an intervening frame on the stack.                       * called with an intervening frame on the stack.
2767                       */                       */
2768                      fp = cx->fp;                      JSStackFrame *fp = cx->fp;
2769                      while (!(fp->flags & JSFRAME_EVAL))                      if (fp) {
2770                          fp = fp->down;                          while (!(fp->flags & JSFRAME_EVAL))
2771                      JS_ASSERT(fp->script == jp->script);                              fp = fp->down;
2772                      JS_ASSERT(fp->down->fun == jp->fun);                          JS_ASSERT(fp->script == jp->script);
2773                      JS_ASSERT(FUN_INTERPRETED(jp->fun));                          JS_ASSERT(fp->down->fun == jp->fun);
2774                      JS_ASSERT(jp->script != jp->fun->u.i.script);                          JS_ASSERT(FUN_INTERPRETED(jp->fun));
2775                      JS_ASSERT(jp->script->upvarsOffset != 0);                          JS_ASSERT(jp->script != jp->fun->u.i.script);
2776                            JS_ASSERT(jp->script->upvarsOffset != 0);
2777                        }
2778    #endif
2779                      uva = JS_SCRIPT_UPVARS(jp->script);                      uva = JS_SCRIPT_UPVARS(jp->script);
2780                      i = GET_UINT16(pc);                      i = GET_UINT16(pc);
                     JS_ASSERT(UPVAR_FRAME_SKIP(uva->vector[i]) == 1);  
2781                      i = UPVAR_FRAME_SLOT(uva->vector[i]);                      i = UPVAR_FRAME_SLOT(uva->vector[i]);
2782                  }                  }
2783                  atom = GetArgOrVarAtom(jp, i);                  atom = GetArgOrVarAtom(jp, i);
# Line 2787  Line 2815 
2815                      LOCAL_ASSERT(atom);                      LOCAL_ASSERT(atom);
2816                      goto do_setname;                      goto do_setname;
2817                  }                  }
2818                  lval = GetStr(ss, i);                  lval = GetLocal(ss, i);
2819                  rval = POP_STR();                  rval = POP_STR();
2820                  goto do_setlval;                  goto do_setlval;
2821    
# Line 2819  Line 2847 
2847                  LOCAL_ASSERT(jp->fun);                  LOCAL_ASSERT(jp->fun);
2848                  fun = jp->fun;                  fun = jp->fun;
2849                  if (fun->flags & JSFUN_EXPR_CLOSURE) {                  if (fun->flags & JSFUN_EXPR_CLOSURE) {
2850                        /* Turn on parens around comma-expression here. */
2851                        op = JSOP_SETNAME;
2852                      rval = POP_STR();                      rval = POP_STR();
2853                      js_printf(jp, (*rval == '{') ? "(%s)%s" : ss_format,                      js_printf(jp, (*rval == '{') ? "(%s)%s" : ss_format,
2854                                rval,                                rval,
# Line 2875  Line 2905 
2905                  rval = POP_STR();                  rval = POP_STR();
2906    
2907                  /*                  /*
2908                   * Skip down over iterables left stacked by JSOP_FOR* until                   * Skip the for loop head stacked by JSOP_FORLOCAL until we hit
2909                   * we hit a block-local or the new Array initialiser (empty                   * a block local slot (note empty destructuring patterns result
2910                   * destructuring patterns yield zero-count blocks).                   * in unit-count blocks).
2911                   */                   */
2912                  pos = ss->top;                  pos = ss->top;
2913                  while ((op = (JSOp) ss->opcodes[--pos]) != JSOP_ENTERBLOCK &&                  while (pos != 0) {
2914                         op != JSOP_NEWINIT) {                      op = (JSOp) ss->opcodes[--pos];
2915                      if (pos == 0)                      if (op == JSOP_ENTERBLOCK)
2916                          break;                          break;
2917                  }                  }
2918                    JS_ASSERT(op == JSOP_ENTERBLOCK);
2919    
2920                  /*                  /*
2921                   * Make forpos index the space before the left-most |for| in                   * Here, forpos must index the space before the left-most |for|
2922                   * the single string of accumulated |for| heads and optional                   * in the single string of accumulated |for| heads and optional
2923                   * final |if (condition)|.                   * final |if (condition)|.
2924                   */                   */
2925                  forpos = pos + (op == JSOP_ENTERBLOCK || op == JSOP_NEWINIT);                  forpos = pos + 2;
2926                  LOCAL_ASSERT(forpos < ss->top);                  LOCAL_ASSERT(forpos < ss->top);
2927    
2928                  /*                  /*
2929                   * Now skip down over the block's local slots, if any. There                   * Now move pos downward over the block's local slots. Even an
2930                   * may be no locals for an empty destructuring pattern.                   * empty destructuring pattern has one (dummy) local.
2931                   */                   */
2932                  while (ss->opcodes[pos] == JSOP_ENTERBLOCK) {                  while (ss->opcodes[pos] == JSOP_ENTERBLOCK) {
2933                      if (pos == 0)                      if (pos == 0)
2934                          break;                          break;
2935                      --pos;                      --pos;
2936                  }                  }
2937                    JS_ASSERT_IF(saveop == JSOP_ARRAYPUSH,
2938                                 jp->script->nfixed + pos == GET_UINT16(pc));
2939    
2940  #if JS_HAS_GENERATOR_EXPRS  #if JS_HAS_GENERATOR_EXPRS
2941                  if (saveop == JSOP_YIELD) {                  if (saveop == JSOP_YIELD) {
# Line 2939  Line 2972 
2972                  lval = OFF2STR(&ss->sprinter, start);                  lval = OFF2STR(&ss->sprinter, start);
2973                  RETRACT(&ss->sprinter, lval);                  RETRACT(&ss->sprinter, lval);
2974    
2975                  todo = Sprint(&ss->sprinter, "%s%s%.*s",                  todo = Sprint(&ss->sprinter, sss_format, lval, rval, xval);
                               lval, rval, rval - xval, xval);  
2976                  if (todo < 0)                  if (todo < 0)
2977                      return NULL;                      return NULL;
2978                  ss->offsets[pos] = todo;                  ss->offsets[pos] = todo;
# Line 2962  Line 2994 
2994                  js_printf(jp, "\t%s %s;\n", js_throw_str, rval);                  js_printf(jp, "\t%s %s;\n", js_throw_str, rval);
2995                  break;                  break;
2996    
2997                  case JSOP_ITER:
2998                    foreach = (pc[1] & (JSITER_FOREACH | JSITER_KEYVALUE)) ==
2999                              JSITER_FOREACH;
3000                    todo = SprintCString(&ss->sprinter, iter_cookie);
3001                    break;
3002    
3003                  case JSOP_NEXTITER:
3004                    JS_NOT_REACHED("JSOP_NEXTITER");
3005                    break;
3006    
3007                  case JSOP_ENDITER:
3008                    sn = js_GetSrcNote(jp->script, pc);
3009                    todo = -2;
3010                    if (sn && SN_TYPE(sn) == SRC_HIDDEN)
3011                        break;
3012                    (void) PopOff(ss, op);
3013                    (void) PopOff(ss, op);
3014                    break;
3015    
3016                case JSOP_GOTO:                case JSOP_GOTO:
3017                case JSOP_GOTOX:                case JSOP_GOTOX:
3018                  sn = js_GetSrcNote(jp->script, pc);                  sn = js_GetSrcNote(jp->script, pc);
3019                  switch (sn ? SN_TYPE(sn) : SRC_NULL) {                  switch (sn ? SN_TYPE(sn) : SRC_NULL) {
3020                      case SRC_FOR_IN:
3021                        /*
3022                         * The loop back-edge carries +1 stack balance, for the
3023                         * flag processed by JSOP_IFNE. We do not decompile the
3024                         * JSOP_IFNE, and instead push the left-hand side of 'in'
3025                         * after the loop edge in this stack slot (the JSOP_FOR*
3026                         * opcodes' decompilers do this pushing).
3027                         */
3028                        cond = GetJumpOffset(pc, pc);
3029                        next = js_GetSrcNoteOffset(sn, 0);
3030                        tail = js_GetSrcNoteOffset(sn, 1);
3031                        JS_ASSERT(pc[cond] == JSOP_NEXTITER);
3032                        DECOMPILE_CODE(pc + oplen, next - oplen);
3033                        lval = POP_STR();
3034                        if (ss->inArrayInit || ss->inGenExp) {
3035                            (void) PopOff(ss, JSOP_NOP);
3036                            rval = TOP_STR();
3037                            LOCAL_ASSERT(ss->top >= 2);
3038                            if (ss->opcodes[ss->top - 2] == JSOP_FORLOCAL) {
3039                                ss->sprinter.offset = ss->offsets[ss->top - 1] - PAREN_SLOP;
3040                                if (Sprint(&ss->sprinter, " %s (%s in %s)",
3041                                           foreach ? js_for_each_str : js_for_str,
3042                                           lval, rval) < 0) {
3043                                    return NULL;
3044                                }
3045                                
3046                                /*
3047                                 * Do not AddParentSlop here, as we will push the
3048                                 * top-most offset again, which will add paren slop
3049                                 * for us. We must push to balance the stack budget
3050                                 * when nesting for heads in a comprehension.
3051                                 */
3052                                todo = ss->offsets[ss->top - 1];
3053                            } else {
3054                                LOCAL_ASSERT(ss->opcodes[ss->top - 2] == JSOP_ENTERBLOCK);
3055                                todo = Sprint(&ss->sprinter, " %s (%s in %s)",
3056                                              foreach ? js_for_each_str : js_for_str,
3057                                              lval, rval);
3058                            }
3059                            if (todo < 0 || !PushOff(ss, todo, JSOP_FORLOCAL))
3060                                return NULL;
3061                            DECOMPILE_CODE(pc + next, cond - next);
3062                        } else {
3063                            /*
3064                             * As above, rval or an extension of it must remain
3065                             * stacked during loop body decompilation.
3066                             */
3067                            rval = GetStr(ss, ss->top - 2);
3068                            js_printf(jp, "\t%s (%s in %s) {\n",
3069                                      foreach ? js_for_each_str : js_for_str,
3070                                      lval, rval);
3071                            jp->indent += 4;
3072                            DECOMPILE_CODE(pc + next, cond - next);
3073                            jp->indent -= 4;
3074                            js_printf(jp, "\t}\n");
3075                        }
3076                        pc += tail;
3077                        LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX);
3078                        len = js_CodeSpec[*pc].length;
3079                        break;
3080    
3081                    case SRC_WHILE:                    case SRC_WHILE:
3082                      cond = GetJumpOffset(pc, pc);                      cond = GetJumpOffset(pc, pc);
3083                      tail = js_GetSrcNoteOffset(sn, 0);                      tail = js_GetSrcNoteOffset(sn, 0);
3084                      DECOMPILE_CODE(pc + cond, tail - cond);                      DECOMPILE_CODE(pc + cond, tail - cond);
3085                      rval = POP_STR();                      js_printf(jp, "\twhile (%s) {\n", POP_COND_STR());
                     js_printf(jp, "\twhile (%s) {\n", rval);  
3086                      jp->indent += 4;                      jp->indent += 4;
3087                      DECOMPILE_CODE(pc + oplen, cond - oplen);                      DECOMPILE_CODE(pc + oplen, cond - oplen);
3088                      jp->indent -= 4;                      jp->indent -= 4;
# Line 3026  Line 3137 
3137                  switch (sn ? SN_TYPE(sn) : SRC_NULL) {                  switch (sn ? SN_TYPE(sn) : SRC_NULL) {
3138                    case SRC_IF:                    case SRC_IF:
3139                    case SRC_IF_ELSE:                    case SRC_IF_ELSE:
3140                      op = JSOP_NOP;              /* turn off parens */                      rval = POP_COND_STR();
                     rval = POP_STR();  
3141                      if (ss->inArrayInit || ss->inGenExp) {                      if (ss->inArrayInit || ss->inGenExp) {
3142                          LOCAL_ASSERT(SN_TYPE(sn) == SRC_IF);                          LOCAL_ASSERT(SN_TYPE(sn) == SRC_IF);
3143                          ss->sprinter.offset -= PAREN_SLOP;                          ss->sprinter.offset -= PAREN_SLOP;
# Line 3158  Line 3268 
3268                  goto do_logical_connective;                  goto do_logical_connective;
3269    
3270                case JSOP_FORARG:                case JSOP_FORARG:
3271                  atom = GetArgOrVarAtom(jp, GET_ARGNO(pc));                  sn = NULL;
3272                  LOCAL_ASSERT(atom);                  i = GET_ARGNO(pc);
3273                  goto do_fornameinloop;                  goto do_forvarslot;
3274    
               case JSOP_FORCONST:  
3275                case JSOP_FORLOCAL:                case JSOP_FORLOCAL:
3276                  if (IsVarSlot(jp, pc, &i)) {                  sn = js_GetSrcNote(jp->script, pc);
3277                      atom = GetArgOrVarAtom(jp, i);                  if (!IsVarSlot(jp, pc, &i)) {
3278                      LOCAL_ASSERT(atom);                      JS_ASSERT(op == JSOP_FORLOCAL);
3279                      goto do_fornameinloop;                      todo = Sprint(&ss->sprinter, ss_format, VarPrefix(sn), GetStr(ss, i));
3280                        break;
3281                  }                  }
3282                  JS_ASSERT(op == JSOP_FORLOCAL);  
3283                  lval = GetStr(ss, i);                do_forvarslot:
3284                  atom = NULL;                  atom = GetArgOrVarAtom(jp, i);
3285                  goto do_forlvalinloop;                  LOCAL_ASSERT(atom);
3286                    todo = SprintCString(&ss->sprinter, VarPrefix(sn));
3287                    if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0))
3288                        return NULL;
3289                    break;
3290    
3291                case JSOP_FORNAME:                case JSOP_FORNAME:
3292                  LOAD_ATOM(0);                  LOAD_ATOM(0);
   
               do_fornameinloop:  
                 lval = "";  
               do_forlvalinloop:  
3293                  sn = js_GetSrcNote(jp->script, pc);                  sn = js_GetSrcNote(jp->script, pc);
3294                  xval = NULL;                  todo = SprintCString(&ss->sprinter, VarPrefix(sn));
3295                  goto do_forinloop;                  if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0))
3296                        return NULL;
3297                    break;
3298    
3299                case JSOP_FORPROP:                case JSOP_FORPROP:
3300                  xval = NULL;                  xval = NULL;
# Line 3192  Line 3304 
3304                                         (jschar)'\'');                                         (jschar)'\'');
3305                      if (!xval)                      if (!xval)
3306                          return NULL;                          return NULL;
                     atom = NULL;  
3307                  }                  }
3308                  lval = POP_STR();                  lval = POP_STR();
3309                  sn = NULL;                  if (xval) {
3310                        JS_ASSERT(*lval);
3311                do_forinloop:                      todo = Sprint(&ss->sprinter, index_format, lval, xval);
3312                  pc += oplen;                  } else {
3313                  LOCAL_ASSERT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX);                      todo = Sprint(&ss->sprinter, ss_format, lval, *lval ? "." : "");
                 oplen = js_CodeSpec[*pc].length;  
                 len = GetJumpOffset(pc, pc);  
                 sn2 = js_GetSrcNote(jp->script, pc);  
                 tail = js_GetSrcNoteOffset(sn2, 0);  
   
               do_forinhead:  
                 if (!atom && xval) {  
                     /*  
                      * If xval is not a dummy empty string, we have to strdup  
                      * it to save it from being clobbered by the first Sprint  
                      * below.  Standard dumb decompiler operating procedure!  
                      */  
                     if (*xval == '\0') {  
                         xval = NULL;  
                     } else {  
                         xval = JS_strdup(cx, xval);  
                         if (!xval)  
                             return NULL;  
                     }  
                 }  
   
 #if JS_HAS_XML_SUPPORT  
                 if (foreach) {  
                     foreach = JS_FALSE;  
                     todo = Sprint(&ss->sprinter, "for %s (%s%s",  
                                   js_each_str, VarPrefix(sn), lval);  
                 } else  
 #endif  
                 {  
                     todo = Sprint(&ss->sprinter, "for (%s%s",  
                                   VarPrefix(sn), lval);  
                 }  
                 if (atom) {  
                     if (*lval && SprintPut(&ss->sprinter, ".", 1) < 0)  
                         return NULL;  
                     xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);  
                     if (!xval)  
                         return NULL;  
                 } else if (xval) {  
                     LOCAL_ASSERT(*xval != '\0');  
                     ok = (Sprint(&ss->sprinter,  
                                  (JOF_OPMODE(lastop) == JOF_XMLNAME)  
                                  ? ".%s"  
                                  : "[%s]",  
                                  xval)  
                           >= 0);  
                     JS_free(cx, (char *)xval);  
                     if (!ok)  
                         return NULL;  
                 }  
                 if (todo < 0)  
                     return NULL;  
   
                 lval = OFF2STR(&ss->sprinter, todo);  
                 rval = GetStr(ss, ss->top-1);  
                 RETRACT(&ss->sprinter, rval);  
                 if (ss->inArrayInit || ss->inGenExp) {  
                     if (ss->top > 1 &&  
                         (js_CodeSpec[ss->opcodes[ss->top-2]].format &  
                          JOF_FOR)) {  
                         ss->sprinter.offset -= PAREN_SLOP;  
                     }  
                     todo = Sprint(&ss->sprinter, " %s in %s)", lval, rval);  
3314                      if (todo < 0)                      if (todo < 0)
3315                          return NULL;                          return NULL;
3316                      ss->offsets[ss->top-1] = todo;                      if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0))
3317                      ss->opcodes[ss->top-1] = op;                          return NULL;
                     AddParenSlop(ss);  
                     DECOMPILE_CODE(pc + oplen, tail - oplen);  
                 } else {  
                     js_printf(jp, "\t%s in %s) {\n", lval, rval);  
                     jp->indent += 4;  
                     DECOMPILE_CODE(pc + oplen, tail - oplen);  
                     jp->indent -= 4;  
                     js_printf(jp, "\t}\n");  
3318                  }                  }
                 todo = -2;  
3319                  break;                  break;
3320    
3321                case JSOP_FORELEM:                case JSOP_FORELEM:
                 pc++;  
                 LOCAL_ASSERT(*pc == JSOP_IFEQ || *pc == JSOP_IFEQX);  
                 len = js_CodeSpec[*pc].length;  
   
                 /*  
                  * Arrange for the JSOP_ENUMELEM case to set tail for use by  
                  * do_forinhead: code that uses on it to find the loop-closing  
                  * jump (whatever its format, normal or extended), in order to  
                  * bound the recursively decompiled loop body.  
                  */  
                 sn = js_GetSrcNote(jp->script, pc);  
                 LOCAL_ASSERT(!forelem_tail);  
                 forelem_tail = pc + js_GetSrcNoteOffset(sn, 0);  
   
                 /*  
                  * 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.  
                  *  
                  * Since a for..in loop can't nest in the head of another for  
                  * loop, we can use forelem_{tail,done} singletons to remember  
                  * state from JSOP_FORELEM to JSOP_ENUMELEM, thence (via goto)  
                  * to label do_forinhead.  
                  */  
                 LOCAL_ASSERT(!forelem_done);  
                 forelem_done = pc + GetJumpOffset(pc, pc);  
   
                 /* Our net stack balance after forelem;ifeq is +1. */  
3322                  todo = SprintCString(&ss->sprinter, forelem_cookie);                  todo = SprintCString(&ss->sprinter, forelem_cookie);
3323                  break;                  break;
3324    
# Line 3330  Line 3339 
3339                  op = saveop;                  op = saveop;
3340                  rval = POP_STR();                  rval = POP_STR();
3341                  LOCAL_ASSERT(strcmp(rval, forelem_cookie) == 0);                  LOCAL_ASSERT(strcmp(rval, forelem_cookie) == 0);
3342                  LOCAL_ASSERT(forelem_tail > pc);                  if (*xval == '\0') {
3343                  tail = forelem_tail - pc;                      todo = SprintCString(&ss->sprinter, lval);
3344                  forelem_tail = NULL;                  } else {
3345                  LOCAL_ASSERT(forelem_done > pc);                      todo = Sprint(&ss->sprinter,
3346                  len = forelem_done - pc;                                    (JOF_OPMODE(lastop) == JOF_XMLNAME)
3347                  forelem_done = NULL;                                    ? dot_format
3348                  goto do_forinhead;                                    : index_format,
3349                                      lval, xval);
3350                    }
3351                    break;
3352    
3353  #if JS_HAS_GETTER_SETTER  #if JS_HAS_GETTER_SETTER
3354                case JSOP_GETTER:                case JSOP_GETTER:
# Line 3368  Line 3380 
3380                      rval = POP_STR();                      rval = POP_STR();
3381    
3382                      if (strcmp(rval, forelem_cookie) == 0) {                      if (strcmp(rval, forelem_cookie) == 0) {
3383                          LOCAL_ASSERT(forelem_tail > pc);                          todo = Sprint(&ss->sprinter, ss_format,
3384                          tail = forelem_tail - pc;                                        VarPrefix(sn), lval);
                         forelem_tail = NULL;  
                         LOCAL_ASSERT(forelem_done > pc);  
                         len = forelem_done - pc;  
                         forelem_done = NULL;  
                         xval = NULL;  
                         atom = NULL;  
3385    
3386                          /*                          // Skip POP so the SRC_FOR_IN code can pop for itself.
3387                           * Null sn if this is a 'for (var [k, v] = i in o)'                          if (*pc == JSOP_POP)
3388                           * loop, because 'var [k, v = i;' has already been                              len = JSOP_POP_LENGTH;
3389                           * hoisted.                      } else {
3390                           */                          todo = Sprint(&ss->sprinter, "%s%s = %s",
3391                          if (js_GetSrcNoteOffset(sn, 0) == SRC_DECL_VAR)                                        VarPrefix(sn), lval, rval);
                             sn = NULL;  
                         goto do_forinhead;  
3392                      }                      }
   
                     todo = Sprint(&ss->sprinter, "%s%s = %s",  
                                   VarPrefix(sn), lval, rval);  
3393                      break;                      break;
3394                  }                  }
3395  #endif  #endif
# Line 3445  Line 3446 
3446                case JSOP_NEW:                case JSOP_NEW:
3447                case JSOP_CALL:                case JSOP_CALL:
3448                case JSOP_EVAL:                case JSOP_EVAL:
3449                  case JSOP_APPLY:
3450  #if JS_HAS_LVALUE_RETURN  #if JS_HAS_LVALUE_RETURN
3451                case JSOP_SETCALL:                case JSOP_SETCALL:
3452  #endif  #endif
# Line 3470  Line 3472 
3472                  /*                  /*
3473                   * Special case: new (x(y)(z)) must be parenthesized like so.                   * Special case: new (x(y)(z)) must be parenthesized like so.
3474                   * Same for new (x(y).z) -- contrast with new x(y).z.                   * Same for new (x(y).z) -- contrast with new x(y).z.
3475                     * See PROPAGATE_CALLNESS.
3476                   */                   */
3477                  op = (JSOp) ss->opcodes[ss->top-1];                  op = (JSOp) ss->opcodes[ss->top-1];
3478                  lval = PopStr(ss,                  lval = PopStr(ss,
3479                                (saveop == JSOP_NEW &&                                (saveop == JSOP_NEW &&
3480                                 (op == JSOP_CALL || op == JSOP_EVAL ||                                 (op == JSOP_CALL ||
3481                                    op == JSOP_EVAL ||
3482                                    op == JSOP_APPLY ||
3483                                  (js_CodeSpec[op].format & JOF_CALLOP)))                                  (js_CodeSpec[op].format & JOF_CALLOP)))
3484                                ? JSOP_NAME                                ? JSOP_NAME
3485                                : saveop);                                : saveop);
# Line 3522  Line 3527 
3527                      todo = Sprint(&ss->sprinter, "");                      todo = Sprint(&ss->sprinter, "");
3528                  }                  }
3529  #endif  #endif
                 LOCAL_ASSERT(pc[len] == JSOP_RESUME);  
                 len += JSOP_RESUME_LENGTH;  
3530                  break;                  break;
3531    
3532                case JSOP_DELNAME:                case JSOP_DELNAME:
# Line 3538  Line 3541 
3541    
3542                case JSOP_DELPROP:                case JSOP_DELPROP:
3543                  GET_ATOM_QUOTE_AND_FMT("%s %s[%s]", "%s %s.%s", rval);                  GET_ATOM_QUOTE_AND_FMT("%s %s[%s]", "%s %s.%s", rval);
3544                    op = JSOP_GETPROP;
3545                  lval = POP_STR();                  lval = POP_STR();
3546                  todo = Sprint(&ss->sprinter, fmt, js_delete_str, lval, rval);                  todo = Sprint(&ss->sprinter, fmt, js_delete_str, lval, rval);
3547                  break;                  break;
# Line 3545  Line 3549 
3549                case JSOP_DELELEM:                case JSOP_DELELEM:
3550                  op = JSOP_NOP;          /* turn off parens */                  op = JSOP_NOP;          /* turn off parens */
3551                  xval = POP_STR();                  xval = POP_STR();
3552                  op = saveop;                  op = JSOP_GETPROP;
3553                  lval = POP_STR();                  lval = POP_STR();
3554                  if (*xval == '\0')                  if (*xval == '\0')
3555                      goto do_delete_lval;                      goto do_delete_lval;
# Line 3559  Line 3563 
3563  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
3564                case JSOP_DELDESC:                case JSOP_DELDESC:
3565                  xval = POP_STR();                  xval = POP_STR();
3566                    op = JSOP_GETPROP;
3567                  lval = POP_STR();                  lval = POP_STR();
3568                  todo = Sprint(&ss->sprinter, "%s %s..%s",                  todo = Sprint(&ss->sprinter, "%s %s..%s",
3569                                js_delete_str, lval, xval);                                js_delete_str, lval, xval);
# Line 3703  Line 3708 
3708                do_getprop:                do_getprop:
3709                  GET_QUOTE_AND_FMT(index_format, dot_format, rval);                  GET_QUOTE_AND_FMT(index_format, dot_format, rval);
3710                do_getprop_lval:                do_getprop_lval:
3711                    PROPAGATE_CALLNESS();
3712                  lval = POP_STR();                  lval = POP_STR();
3713                  todo = Sprint(&ss->sprinter, fmt, lval, rval);                  todo = Sprint(&ss->sprinter, fmt, lval, rval);
3714                  break;                  break;
# Line 3776  Line 3782 
3782                  op = JSOP_NOP;          /* turn off parens */                  op = JSOP_NOP;          /* turn off parens */
3783                  xval = POP_STR();                  xval = POP_STR();
3784                  op = saveop;                  op = saveop;
3785                    PROPAGATE_CALLNESS();
3786                  lval = POP_STR();                  lval = POP_STR();
3787                  if (*xval == '\0') {                  if (*xval == '\0') {
3788                      todo = Sprint(&ss->sprinter, "%s", lval);                      todo = Sprint(&ss->sprinter, "%s", lval);
# Line 3855  Line 3862 
3862                  if (!rval)                  if (!rval)
3863                      return NULL;                      return NULL;
3864                  RETRACT(&ss->sprinter, rval);                  RETRACT(&ss->sprinter, rval);
3865                  todo = Sprint(&ss->sprinter, "%s%s%s",                  todo = Sprint(&ss->sprinter, sss_format,
3866                                VarPrefix(sn), lval, rval);                                VarPrefix(sn), lval, rval);
3867                  break;                  break;
3868    
# Line 3925  Line 3932 
3932                      outer = jp->script;                      outer = jp->script;
3933                      LOCAL_ASSERT(JS_UPTRDIFF(pc, outer->code) <= outer->length);                      LOCAL_ASSERT(JS_UPTRDIFF(pc, outer->code) <= outer->length);
3934                      jp->script = inner;                      jp->script = inner;
3935                      if (!Decompile(&ss2, inner->code, inner->length,                      if (!Decompile(&ss2, inner->code, inner->length, JSOP_NOP)) {
                                    JSOP_NOP)) {  
3936                          JS_ARENA_RELEASE(&cx->tempPool, mark);                          JS_ARENA_RELEASE(&cx->tempPool, mark);
3937                          return NULL;                          return NULL;
3938                      }                      }
# Line 4242  Line 4248 
4248                  break;                  break;
4249                }                }
4250    
               case JSOP_STRICTEQ:  
               case JSOP_STRICTNE:  
                 rval = POP_STR();  
                 lval = POP_STR();  
                 todo = Sprint(&ss->sprinter, "%s %c== %s",  
                               lval, (op == JSOP_STRICTEQ) ? '=' : '!', rval);  
                 break;  
   
4251                case JSOP_DEFFUN:                case JSOP_DEFFUN:
4252                  LOAD_FUNCTION(0);                  LOAD_FUNCTION(0);
4253                  todo = -2;                  todo = -2;
# Line 4373  Line 4371 
4371                  const char *maybeComma;                  const char *maybeComma;
4372    
4373                case JSOP_INITELEM:                case JSOP_INITELEM:
                 /* Turn off most parens (all if there's only one initialiser). */  
                 LOCAL_ASSERT(pc + len < endpc);  
4374                  isFirst = (ss->opcodes[ss->top - 3] == JSOP_NEWINIT);                  isFirst = (ss->opcodes[ss->top - 3] == JSOP_NEWINIT);
4375                  op = (isFirst &&  
4376                        GetStr(ss, ss->top - 2)[0] == '0' &&                  /* Turn off most parens. */
4377                        (JSOp) pc[len] == JSOP_ENDINIT)                  op = JSOP_SETNAME;
                      ? JSOP_NOP  
                      : JSOP_SETNAME;  
4378                  rval = POP_STR();                  rval = POP_STR();
4379    
4380                  /* Turn off all parens for xval and lval, which we control. */                  /* Turn off all parens for xval and lval, which we control. */
# Line 4394  Line 4388 
4388                      goto do_initprop;                      goto do_initprop;
4389                  }                  }
4390                  maybeComma = isFirst ? "" : ", ";                  maybeComma = isFirst ? "" : ", ";
4391                  todo = Sprint(&ss->sprinter, "%s%s%s",                  todo = Sprint(&ss->sprinter, sss_format,
4392                                lval,                                lval,
4393                                maybeComma,                                maybeComma,
4394                                rval);                                rval);
# Line 4589  Line 4583 
4583                  inXML = JS_FALSE;                  inXML = JS_FALSE;
4584                  break;                  break;
4585    
               case JSOP_ITER:  
                 foreach = (pc[1] & (JSITER_FOREACH | JSITER_KEYVALUE)) ==  
                           JSITER_FOREACH;  
                 todo = -2;  
                 break;  
   
4586                case JSOP_TOXML:                case JSOP_TOXML:
4587                case JSOP_CALLXMLNAME:                case JSOP_CALLXMLNAME:
4588                case JSOP_XMLNAME:                case JSOP_XMLNAME:
# Line 4606  Line 4594 
4594    
4595                case JSOP_ENDFILTER:                case JSOP_ENDFILTER:
4596                  rval = POP_STR();                  rval = POP_STR();
4597                    PROPAGATE_CALLNESS();
4598                  lval = POP_STR();                  lval = POP_STR();
4599                  todo = Sprint(&ss->sprinter, "%s.(%s)", lval, rval);                  todo = Sprint(&ss->sprinter, "%s.(%s)", lval, rval);
4600                  break;                  break;
4601    
4602                case JSOP_DESCENDANTS:                case JSOP_DESCENDANTS:
4603                  rval = POP_STR();                  rval = POP_STR();
4604                    PROPAGATE_CALLNESS();
4605                  lval = POP_STR();                  lval = POP_STR();
4606                  todo = Sprint(&ss->sprinter, "%s..%s", lval, rval);                  todo = Sprint(&ss->sprinter, "%s..%s", lval, rval);
4607                  break;                  break;
# Line 4690  Line 4680 
4680  #undef inXML  #undef inXML
4681  #undef DECOMPILE_CODE  #undef DECOMPILE_CODE
4682  #undef NEXT_OP  #undef NEXT_OP
4683    #undef TOP_STR
4684  #undef POP_STR  #undef POP_STR
4685    #undef POP_STR_PREC
4686  #undef LOCAL_ASSERT  #undef LOCAL_ASSERT
4687  #undef ATOM_IS_IDENTIFIER  #undef ATOM_IS_IDENTIFIER
4688  #undef GET_QUOTE_AND_FMT  #undef GET_QUOTE_AND_FMT
# Line 4961  Line 4953 
4953    
4954      script = fp->script;      script = fp->script;
4955      regs = fp->regs;      regs = fp->regs;
4956      pc = regs->pc;      pc = fp->imacpc ? fp->imacpc : regs->pc;
4957      if (pc < script->main || script->code + script->length <= pc) {      if (pc < script->main || script->code + script->length <= pc) {
4958          JS_NOT_REACHED("bug");          JS_NOT_REACHED("bug");
4959          goto do_fallback;          goto do_fallback;
# Line 4978  Line 4970 
4970                    JS_malloc(cx, StackDepth(script) * sizeof *pcstack);                    JS_malloc(cx, StackDepth(script) * sizeof *pcstack);
4971          if (!pcstack)          if (!pcstack)
4972              return NULL;              return NULL;
4973          pcdepth = ReconstructPCStack(cx, script, regs->pc, pcstack);          pcdepth = ReconstructPCStack(cx, script, pc, pcstack);
4974          if (pcdepth < 0)          if (pcdepth < 0)
4975              goto release_pcstack;              goto release_pcstack;
4976    
# Line 4995  Line 4987 
4987               * it that caused exception, see bug 328664.               * it that caused exception, see bug 328664.
4988               */               */
4989              stackBase = StackBase(fp);              stackBase = StackBase(fp);
             JS_ASSERT((size_t) (regs->sp - stackBase) <= StackDepth(script));  
4990              sp = regs->sp;              sp = regs->sp;
4991              do {              do {
4992                  if (sp == stackBase) {                  if (sp == stackBase) {
# Line 5006  Line 4997 
4997    
4998              if (sp >= stackBase + pcdepth) {              if (sp >= stackBase + pcdepth) {
4999                  /*                  /*
5000                   * This happens when the value comes from a temporary slot                   * The value comes from a temporary slot that the interpreter
5001                   * that the interpreter uses for GC roots. Assume that it is                   * uses for GC roots or when JSOP_APPLY extended the stack to
5002                   * fp->pc that caused the exception.                   * fit the argument array elements. Assume that it is the
5003                     * current PC that caused the exception.
5004                   */                   */
5005                  pc = regs->pc;                  pc = fp->imacpc ? fp->imacpc : regs->pc;
5006              } else {              } else {
5007                  pc = pcstack[sp - stackBase];                  pc = pcstack[sp - stackBase];
5008              }              }
# Line 5022  Line 5014 
5014              goto do_fallback;              goto do_fallback;
5015      }      }
5016    
5017      name = DecompileExpression(cx, script, fp->fun, pc);      {
5018            jsbytecode* savepc = regs->pc;
5019            jsbytecode* imacpc = fp->imacpc;
5020            if (imacpc) {
5021                regs->pc = imacpc;
5022                fp->imacpc = NULL;
5023            }
5024            name = DecompileExpression(cx, script, fp->fun, pc);
5025            if (imacpc) {
5026                regs->pc = savepc;
5027                fp->imacpc = imacpc;
5028            }
5029        }
5030      if (name != FAILED_EXPRESSION_DECOMPILER)      if (name != FAILED_EXPRESSION_DECOMPILER)
5031          return name;          return name;
5032    

Legend:
Removed from v.332  
changed lines
  Added in v.399

  ViewVC Help
Powered by ViewVC 1.1.24