/[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 459 by siliconforks, Tue Dec 9 03:37:47 2008 UTC revision 460 by siliconforks, Sat Sep 26 23:15:22 2009 UTC
# Line 1  Line 1 
1  /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-  /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2   * vim: set sw=4 ts=8 et tw=99:   * vim: set sw=4 ts=8 et tw=99:
3   *   *
4   * ***** BEGIN LICENSE BLOCK *****   * ***** BEGIN LICENSE BLOCK *****
# Line 76  Line 76 
76    
77  #include "jsautooplen.h"  #include "jsautooplen.h"
78    
79    /*
80     * Index limit must stay within 32 bits.
81     */
82    JS_STATIC_ASSERT(sizeof(uint32) * JS_BITS_PER_BYTE >= INDEX_LIMIT_LOG2 + 1);
83    
84  /* Verify JSOP_XXX_LENGTH constant definitions. */  /* Verify JSOP_XXX_LENGTH constant definitions. */
85  #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)               \  #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format)               \
86      JS_STATIC_ASSERT(op##_LENGTH == length);      JS_STATIC_ASSERT(op##_LENGTH == length);
# Line 138  Line 143 
143      JSOp op;      JSOp op;
144      uintN span, base;      uintN span, base;
145    
146      op = (JSOp)*pc;      op = js_GetOpcode(cx, script, pc);
     if (op == JSOP_TRAP)  
         op = JS_GetTrapOpcode(cx, script, pc);  
147      JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN);      JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN);
148    
149      /*      /*
# Line 199  Line 202 
202  }  }
203    
204  uintN  uintN
205  js_GetVariableStackUseLength(JSOp op, jsbytecode *pc)  js_GetVariableStackUses(JSOp op, jsbytecode *pc)
206  {  {
207      JS_ASSERT(*pc == op || *pc == JSOP_TRAP);      JS_ASSERT(*pc == op || *pc == JSOP_TRAP);
208      JS_ASSERT(js_CodeSpec[op].nuses == -1);      JS_ASSERT(js_CodeSpec[op].nuses == -1);
# Line 211  Line 214 
214        case JSOP_LEAVEBLOCKEXPR:        case JSOP_LEAVEBLOCKEXPR:
215          return GET_UINT16(pc) + 1;          return GET_UINT16(pc) + 1;
216        case JSOP_NEWARRAY:        case JSOP_NEWARRAY:
217          return GET_UINT24(pc);          return GET_UINT16(pc);
218        default:        default:
219          /* stack: fun, this, [argc arguments] */          /* stack: fun, this, [argc arguments] */
220          JS_ASSERT(op == JSOP_NEW || op == JSOP_CALL ||          JS_ASSERT(op == JSOP_NEW || op == JSOP_CALL ||
# Line 221  Line 224 
224      }      }
225  }  }
226    
227    uintN
228    js_GetEnterBlockStackDefs(JSContext *cx, JSScript *script, jsbytecode *pc)
229    {
230        JSObject *obj;
231    
232        JS_ASSERT(*pc == JSOP_ENTERBLOCK || *pc == JSOP_TRAP);
233        GET_OBJECT_FROM_BYTECODE(script, pc, 0, obj);
234        return OBJ_BLOCK_COUNT(cx, obj);
235    }
236    
237  #ifdef DEBUG  #ifdef DEBUG
238    
239  JS_FRIEND_API(JSBool)  JS_FRIEND_API(JSBool)
# Line 247  Line 260 
260  const char *  const char *
261  ToDisassemblySource(JSContext *cx, jsval v)  ToDisassemblySource(JSContext *cx, jsval v)
262  {  {
     JSObject *obj;  
     JSScopeProperty *sprop;  
     char *source;  
     const char *bytes;  
     JSString *str;  
   
263      if (!JSVAL_IS_PRIMITIVE(v)) {      if (!JSVAL_IS_PRIMITIVE(v)) {
264          obj = JSVAL_TO_OBJECT(v);          JSObject *obj = JSVAL_TO_OBJECT(v);
265          if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {          JSClass *clasp = OBJ_GET_CLASS(cx, obj);
266              source = JS_sprintf_append(NULL, "depth %d {",  
267                                         OBJ_BLOCK_DEPTH(cx, obj));          if (clasp == &js_BlockClass) {
268              for (sprop = OBJ_SCOPE(obj)->lastProp; sprop;              char *source = JS_sprintf_append(NULL, "depth %d {", OBJ_BLOCK_DEPTH(cx, obj));
269                for (JSScopeProperty *sprop = OBJ_SCOPE(obj)->lastProp;
270                     sprop;
271                   sprop = sprop->parent) {                   sprop = sprop->parent) {
272                  bytes = js_AtomToPrintableString(cx, JSID_TO_ATOM(sprop->id));                  const char *bytes = js_AtomToPrintableString(cx, JSID_TO_ATOM(sprop->id));
273                  if (!bytes)                  if (!bytes)
274                      return NULL;                      return NULL;
275                  source = JS_sprintf_append(source, "%s: %d%s",                  source = JS_sprintf_append(source, "%s: %d%s",
276                                             bytes, sprop->shortid,                                             bytes, sprop->shortid,
277                                             sprop->parent ? ", " : "");                                             sprop->parent ? ", " : "");
278              }              }
279    
280              source = JS_sprintf_append(source, "}");              source = JS_sprintf_append(source, "}");
281              if (!source)              if (!source)
282                  return NULL;                  return NULL;
283              str = JS_NewString(cx, source, strlen(source));  
284                JSString *str = JS_NewString(cx, source, strlen(source));
285                if (!str)
286                    return NULL;
287                return js_GetStringBytes(cx, str);
288            }
289    
290            if (clasp == &js_FunctionClass) {
291                JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
292                JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
293              if (!str)              if (!str)
294                  return NULL;                  return NULL;
295              return js_GetStringBytes(cx, str);              return js_GetStringBytes(cx, str);
296          }          }
297    
298            if (clasp == &js_RegExpClass) {
299                JSAutoTempValueRooter tvr(cx);
300                if (!js_regexp_toString(cx, obj, tvr.addr()))
301                    return NULL;
302                return js_GetStringBytes(cx, JSVAL_TO_STRING(tvr.value()));
303            }
304      }      }
305    
306      return js_ValueToPrintableSource(cx, v);      return js_ValueToPrintableSource(cx, v);
307  }  }
308    
# Line 717  Line 744 
744      jp->pcstack = NULL;      jp->pcstack = NULL;
745      jp->fun = fun;      jp->fun = fun;
746      jp->localNames = NULL;      jp->localNames = NULL;
747      if (fun && FUN_INTERPRETED(fun) && JS_GET_LOCAL_NAME_COUNT(fun)) {      if (fun && FUN_INTERPRETED(fun) && fun->hasLocalNames()) {
748          jp->localNames = js_GetLocalNameArray(cx, fun, &jp->pool);          jp->localNames = js_GetLocalNameArray(cx, fun, &jp->pool);
749          if (!jp->localNames) {          if (!jp->localNames) {
750              js_DestroyPrinter(jp);              js_DestroyPrinter(jp);
# Line 885  Line 912 
912    
913      JS_ASSERT(off <= -2);      JS_ASSERT(off <= -2);
914      JS_ASSERT(ss->printer->pcstack);      JS_ASSERT(ss->printer->pcstack);
915      if (off < -2 && ss->printer->pcstack) {      if (off <= -2 && ss->printer->pcstack) {
916          pc = ss->printer->pcstack[-2 - off];          pc = ss->printer->pcstack[-2 - off];
917          bytes = DecompileExpression(ss->sprinter.context, ss->printer->script,          bytes = DecompileExpression(ss->sprinter.context, ss->printer->script,
918                                      ss->printer->fun, pc);                                      ss->printer->fun, pc);
# Line 932  Line 959 
959   * JSOP_SETPROP, and JSOP_SETELEM, respectively.  They are never stored in   * JSOP_SETPROP, and JSOP_SETELEM, respectively.  They are never stored in
960   * bytecode, so they don't preempt valid opcodes.   * bytecode, so they don't preempt valid opcodes.
961   */   */
962  #define JSOP_GETPROP2   256  #define JSOP_GETPROP2   JSOP_LIMIT
963  #define JSOP_GETELEM2   257  #define JSOP_GETELEM2   JSOP_LIMIT + 1
964    JS_STATIC_ASSERT(JSOP_GETELEM2 <= 255);
965    
966  static void  static void
967  AddParenSlop(SprintStack *ss)  AddParenSlop(SprintStack *ss)
# Line 960  Line 988 
988    
989      /* The opcodes stack must contain real bytecodes that index js_CodeSpec. */      /* The opcodes stack must contain real bytecodes that index js_CodeSpec. */
990      ss->offsets[top] = off;      ss->offsets[top] = off;
991      ss->opcodes[top] = (op == JSOP_GETPROP2) ? JSOP_GETPROP      ss->opcodes[top] = jsbytecode((op == JSOP_GETPROP2) ? JSOP_GETPROP
992                       : (op == JSOP_GETELEM2) ? JSOP_GETELEM                                  : (op == JSOP_GETELEM2) ? JSOP_GETELEM
993                       : (jsbytecode) op;                                  : op);
994      ss->top = ++top;      ss->top = ++top;
995      AddParenSlop(ss);      AddParenSlop(ss);
996      return JS_TRUE;      return JS_TRUE;
# Line 1219  Line 1247 
1247      JSAtom *name;      JSAtom *name;
1248    
1249      LOCAL_ASSERT_RV(jp->fun, NULL);      LOCAL_ASSERT_RV(jp->fun, NULL);
1250      LOCAL_ASSERT_RV(slot < (uintN) JS_GET_LOCAL_NAME_COUNT(jp->fun), NULL);      LOCAL_ASSERT_RV(slot < jp->fun->countLocalNames(), NULL);
1251      name = JS_LOCAL_NAME_TO_ATOM(jp->localNames[slot]);      name = JS_LOCAL_NAME_TO_ATOM(jp->localNames[slot]);
1252  #if !JS_HAS_DESTRUCTURING  #if !JS_HAS_DESTRUCTURING
1253      LOCAL_ASSERT_RV(name, NULL);      LOCAL_ASSERT_RV(name, NULL);
# Line 1250  Line 1278 
1278       * We must be called from js_DecompileValueGenerator (via Decompile) when       * We must be called from js_DecompileValueGenerator (via Decompile) when
1279       * dereferencing a local that's undefined or null. Search script->objects       * dereferencing a local that's undefined or null. Search script->objects
1280       * for the block containing this local by its stack index, i.       * for the block containing this local by its stack index, i.
1281         *
1282         * In case of destructuring's use of JSOP_GETLOCAL, however, there may be
1283         * no such local. This could mean no blocks (no script objects at all, or
1284         * none of the script's object literals are blocks), or the stack slot i is
1285         * not in a block. In either case, return GetStr(ss, i).
1286       */       */
1287      cx = ss->sprinter.context;      cx = ss->sprinter.context;
1288      script = ss->printer->script;      script = ss->printer->script;
1289      LOCAL_ASSERT(script->objectsOffset != 0);      if (script->objectsOffset == 0)
1290            return GetStr(ss, i);
1291      for (j = 0, n = JS_SCRIPT_OBJECTS(script)->length; ; j++) {      for (j = 0, n = JS_SCRIPT_OBJECTS(script)->length; ; j++) {
1292          LOCAL_ASSERT(j < n);          if (j == n)
1293                return GetStr(ss, i);
1294          JS_GET_SCRIPT_OBJECT(script, j, obj);          JS_GET_SCRIPT_OBJECT(script, j, obj);
1295          if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {          if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {
1296              depth = OBJ_BLOCK_DEPTH(cx, obj);              depth = OBJ_BLOCK_DEPTH(cx, obj);
# Line 1597  Line 1632 
1632              break;              break;
1633    
1634          /*          /*
1635           * Check for SRC_DESTRUCT on this JSOP_DUP, which would mean another           * We should stop if JSOP_DUP is either without notes or its note is
1636           * destructuring initialiser abuts this one, and we should stop.  This           * not SRC_CONTINUE. The former happens when JSOP_DUP duplicates the
1637           * happens with source of the form '[a] = [b] = c'.           * last destructuring reference implementing an op= assignment like in
1638             * '([t] = z).y += x'. In the latter case the note is SRC_DESTRUCT and
1639             * means another destructuring initialiser abuts this one like in
1640             * '[a] = [b] = c'.
1641           */           */
1642          sn = js_GetSrcNote(jp->script, pc);          sn = js_GetSrcNote(jp->script, pc);
1643          if (sn && SN_TYPE(sn) == SRC_DESTRUCT)          if (!sn)
1644              break;              break;
1645            if (SN_TYPE(sn) != SRC_CONTINUE) {
1646                LOCAL_ASSERT(SN_TYPE(sn) == SRC_DESTRUCT);
1647                break;
1648            }
1649    
1650          if (!hole && SprintPut(&ss->sprinter, ", ", 2) < 0)          if (!hole && SprintPut(&ss->sprinter, ", ", 2) < 0)
1651              return NULL;              return NULL;
# Line 1727  Line 1769 
1769      const JSCodeSpec *cs;      const JSCodeSpec *cs;
1770      jssrcnote *sn, *sn2;      jssrcnote *sn, *sn2;
1771      const char *lval, *rval, *xval, *fmt, *token;      const char *lval, *rval, *xval, *fmt, *token;
1772        uintN nuses;
1773      jsint i, argc;      jsint i, argc;
1774      char **argv;      char **argv;
1775      JSAtom *atom;      JSAtom *atom;
# Line 1769  Line 1812 
1812  #define POP_STR_PREC(prec)    PopStrPrec(ss, prec)  #define POP_STR_PREC(prec)    PopStrPrec(ss, prec)
1813    
1814  /*  /*
1815   * Pop a condition expression for if/for/while. JSOP_IFEQ's precedence forces   * Pop a condition expression for if/while. JSOP_IFEQ's precedence forces
1816   * extra parens around assignment, which avoids a strict-mode warning.   * extra parens around assignment, which avoids a strict-mode warning.
1817   */   */
1818  #define POP_COND_STR()                                                        \  #define POP_COND_STR()                                                        \
# Line 1894  Line 1937 
1937          }          }
1938          saveop = op;          saveop = op;
1939          len = oplen = cs->length;          len = oplen = cs->length;
1940            nuses = js_GetStackUses(cs, op, pc);
1941    
1942          if (nb < 0 && -(nb + 1) == (intN)ss->top - cs->nuses + cs->ndefs)          /*
1943              return pc;           * Here it is possible that nuses > ss->top when the op has a hidden
1944             * source note. But when nb < 0 we assume that the caller knows that
1945             * Decompile would never meet such opcodes.
1946             */
1947            if (nb < 0) {
1948                LOCAL_ASSERT(ss->top >= nuses);
1949                uintN ndefs = js_GetStackDefs(cx, cs, op, jp->script, pc);
1950                if ((uintN) -(nb + 1) == ss->top - nuses + ndefs)
1951                    return pc;
1952            }
1953    
1954          /*          /*
1955           * Save source literal associated with JS now before the following           * Save source literal associated with JS now before the following
# Line 1913  Line 1966 
1966               * the bytecode at pc, so we don't decompile more than the error               * the bytecode at pc, so we don't decompile more than the error
1967               * expression.               * expression.
1968               */               */
1969              for (fp = cx->fp; fp && !fp->script; fp = fp->down)              fp = js_GetScriptedCaller(cx, NULL);
                 continue;  
1970              format = cs->format;              format = cs->format;
1971              if (((fp && fp->regs && pc == fp->regs->pc) ||              if (((fp && fp->regs && pc == fp->regs->pc) ||
1972                   (pc == startpc && cs->nuses != 0)) &&                   (pc == startpc && nuses != 0)) &&
1973                  format & (JOF_SET|JOF_DEL|JOF_INCDEC|JOF_FOR|JOF_VARPROP)) {                  format & (JOF_SET|JOF_DEL|JOF_INCDEC|JOF_FOR|JOF_VARPROP)) {
1974                  mode = JOF_MODE(format);                  mode = JOF_MODE(format);
1975                  if (mode == JOF_NAME) {                  if (mode == JOF_NAME) {
# Line 1934  Line 1986 
1986                           ? JSOP_GETLOCAL                           ? JSOP_GETLOCAL
1987                           : JSOP_NAME;                           : JSOP_NAME;
1988    
1989                      i = cs->nuses - js_CodeSpec[op].nuses;                      JS_ASSERT(js_CodeSpec[op].nuses >= 0);
1990                        i = nuses - js_CodeSpec[op].nuses;
1991                      while (--i >= 0)                      while (--i >= 0)
1992                          PopOff(ss, JSOP_NOP);                          PopOff(ss, JSOP_NOP);
1993                  } else {                  } else {
# Line 2018  Line 2071 
2071          }          }
2072    
2073          if (token) {          if (token) {
2074              switch (cs->nuses) {              switch (nuses) {
2075                case 2:                case 2:
2076                  sn = js_GetSrcNote(jp->script, pc);                  sn = js_GetSrcNote(jp->script, pc);
2077                  if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) {                  if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) {
# Line 2743  Line 2796 
2796                  break;                  break;
2797                }                }
2798    
               case JSOP_CALLUPVAR:  
2799                case JSOP_GETUPVAR:                case JSOP_GETUPVAR:
2800                  case JSOP_CALLUPVAR:
2801                  if (!jp->fun)                case JSOP_GETUPVAR_DBG:
2802                  case JSOP_CALLUPVAR_DBG:
2803                  case JSOP_GETDSLOT:
2804                  case JSOP_CALLDSLOT:
2805                  {
2806                    if (!jp->fun) {
2807                        JS_ASSERT(jp->script->flags & JSSF_SAVED_CALLER_FUN);
2808                      JS_GET_SCRIPT_FUNCTION(jp->script, 0, jp->fun);                      JS_GET_SCRIPT_FUNCTION(jp->script, 0, jp->fun);
2809                    }
2810    
2811                  if (!jp->localNames)                  if (!jp->localNames)
2812                      jp->localNames = js_GetLocalNameArray(cx, jp->fun, &jp->pool);                      jp->localNames = js_GetLocalNameArray(cx, jp->fun, &jp->pool);
2813    
2814                  i = JS_UPVAR_LOCAL_NAME_START(jp->fun) + GET_UINT16(pc);                  uintN index = GET_UINT16(pc);
2815                  if (i >= JS_GET_LOCAL_NAME_COUNT(jp->fun)) {                  if (index < jp->fun->u.i.nupvars) {
2816                        index += jp->fun->countArgsAndVars();
2817                    } else {
2818                      JSUpvarArray *uva;                      JSUpvarArray *uva;
2819  #ifdef DEBUG  #ifdef DEBUG
2820                      /*                      /*
# Line 2765  Line 2826 
2826                       * object that's not a constructor, causing us to be                       * object that's not a constructor, causing us to be
2827                       * called with an intervening frame on the stack.                       * called with an intervening frame on the stack.
2828                       */                       */
2829                      JSStackFrame *fp = cx->fp;                      JSStackFrame *fp = js_GetTopStackFrame(cx);
2830                      if (fp) {                      if (fp) {
2831                          while (!(fp->flags & JSFRAME_EVAL))                          while (!(fp->flags & JSFRAME_EVAL))
2832                              fp = fp->down;                              fp = fp->down;
# Line 2777  Line 2838 
2838                      }                      }
2839  #endif  #endif
2840                      uva = JS_SCRIPT_UPVARS(jp->script);                      uva = JS_SCRIPT_UPVARS(jp->script);
2841                      i = GET_UINT16(pc);                      index = UPVAR_FRAME_SLOT(uva->vector[index]);
                     i = UPVAR_FRAME_SLOT(uva->vector[i]);  
2842                  }                  }
2843                  atom = GetArgOrVarAtom(jp, i);                  atom = GetArgOrVarAtom(jp, index);
2844                  goto do_name;                  goto do_name;
2845                  }
2846    
2847                case JSOP_CALLLOCAL:                case JSOP_CALLLOCAL:
2848                case JSOP_GETLOCAL:                case JSOP_GETLOCAL:
# Line 2795  Line 2856 
2856    
2857  #if JS_HAS_DESTRUCTURING  #if JS_HAS_DESTRUCTURING
2858                  if (sn && SN_TYPE(sn) == SRC_GROUPASSIGN) {                  if (sn && SN_TYPE(sn) == SRC_GROUPASSIGN) {
2859                      pc = DecompileGroupAssignment(ss, pc, endpc, sn, &todo);                      /*
2860                      if (!pc)                       * Distinguish a js_DecompileValueGenerator call that
2861                          return NULL;                       * targets op alone, from decompilation of a full group
2862                      LOCAL_ASSERT(*pc == JSOP_POPN);                       * assignment sequence, triggered by SRC_GROUPASSIGN
2863                      len = oplen = JSOP_POPN_LENGTH;                       * annotating the first JSOP_GETLOCAL in the sequence.
2864                      goto end_groupassignment;                       */
2865                        if (endpc - pc > JSOP_GETLOCAL_LENGTH || pc > startpc) {
2866                            pc = DecompileGroupAssignment(ss, pc, endpc, sn, &todo);
2867                            if (!pc)
2868                                return NULL;
2869                            LOCAL_ASSERT(*pc == JSOP_POPN);
2870                            len = oplen = JSOP_POPN_LENGTH;
2871                            goto end_groupassignment;
2872                        }
2873    
2874                        /* Null sn to prevent bogus VarPrefix'ing below. */
2875                        sn = NULL;
2876                  }                  }
2877  #endif  #endif
2878    
# Line 2888  Line 2960 
2960                             : SprintCString(&ss->sprinter, js_yield_str);                             : SprintCString(&ss->sprinter, js_yield_str);
2961                      break;                      break;
2962                  }                  }
2963    
2964  #if JS_HAS_GENERATOR_EXPRS  #if JS_HAS_GENERATOR_EXPRS
2965                  LOCAL_ASSERT(SN_TYPE(sn) == SRC_HIDDEN);                  LOCAL_ASSERT(SN_TYPE(sn) == SRC_HIDDEN);
2966                  /* FALL THROUGH */                  /* FALL THROUGH */
# Line 2934  Line 3007 
3007                          break;                          break;
3008                      --pos;                      --pos;
3009                  }                  }
                 JS_ASSERT_IF(saveop == JSOP_ARRAYPUSH,  
                              jp->script->nfixed + pos == GET_UINT16(pc));  
3010    
3011  #if JS_HAS_GENERATOR_EXPRS  #if JS_HAS_GENERATOR_EXPRS
3012                  if (saveop == JSOP_YIELD) {                  if (saveop == JSOP_YIELD) {
# Line 2963  Line 3034 
3034                   * Array comprehension: retract the sprinter to the beginning                   * Array comprehension: retract the sprinter to the beginning
3035                   * of the array initialiser and decompile "[<rval> for ...]".                   * of the array initialiser and decompile "[<rval> for ...]".
3036                   */                   */
3037                    JS_ASSERT(jp->script->nfixed + pos == GET_UINT16(pc));
3038                  LOCAL_ASSERT(ss->opcodes[pos] == JSOP_NEWINIT);                  LOCAL_ASSERT(ss->opcodes[pos] == JSOP_NEWINIT);
3039    
3040                  start = ss->offsets[pos];                  start = ss->offsets[pos];
3041                  LOCAL_ASSERT(ss->sprinter.base[start] == '[' ||                  LOCAL_ASSERT(ss->sprinter.base[start] == '[' ||
3042                               ss->sprinter.base[start] == '#');                               ss->sprinter.base[start] == '#');
# Line 2979  Line 3052 
3052                  todo = -2;                  todo = -2;
3053                  break;                  break;
3054                }                }
3055  #endif  #endif /* JS_HAS_GENERATORS */
3056    
3057                case JSOP_THROWING:                case JSOP_THROWING:
3058                  todo = -2;                  todo = -2;
# Line 3031  Line 3104 
3104                      JS_ASSERT(pc[cond] == JSOP_NEXTITER);                      JS_ASSERT(pc[cond] == JSOP_NEXTITER);
3105                      DECOMPILE_CODE(pc + oplen, next - oplen);                      DECOMPILE_CODE(pc + oplen, next - oplen);
3106                      lval = POP_STR();                      lval = POP_STR();
3107                        LOCAL_ASSERT(ss->top >= 2);
3108    
3109                      if (ss->inArrayInit || ss->inGenExp) {                      if (ss->inArrayInit || ss->inGenExp) {
3110                          (void) PopOff(ss, JSOP_NOP);                          (void) PopOff(ss, JSOP_NOP);
3111                          rval = TOP_STR();                          rval = TOP_STR();
3112                          LOCAL_ASSERT(ss->top >= 2);                          if (ss->top >= 2 && ss->opcodes[ss->top - 2] == JSOP_FORLOCAL) {
                         if (ss->opcodes[ss->top - 2] == JSOP_FORLOCAL) {  
3113                              ss->sprinter.offset = ss->offsets[ss->top - 1] - PAREN_SLOP;                              ss->sprinter.offset = ss->offsets[ss->top - 1] - PAREN_SLOP;
3114                              if (Sprint(&ss->sprinter, " %s (%s in %s)",                              if (Sprint(&ss->sprinter, " %s (%s in %s)",
3115                                         foreach ? js_for_each_str : js_for_str,                                         foreach ? js_for_each_str : js_for_str,
3116                                         lval, rval) < 0) {                                         lval, rval) < 0) {
3117                                  return NULL;                                  return NULL;
3118                              }                              }
3119                                
3120                              /*                              /*
3121                               * Do not AddParentSlop here, as we will push the                               * Do not AddParentSlop here, as we will push the
3122                               * top-most offset again, which will add paren slop                               * top-most offset again, which will add paren slop
# Line 3051  Line 3125 
3125                               */                               */
3126                              todo = ss->offsets[ss->top - 1];                              todo = ss->offsets[ss->top - 1];
3127                          } else {                          } else {
                             LOCAL_ASSERT(ss->opcodes[ss->top - 2] == JSOP_ENTERBLOCK);  
3128                              todo = Sprint(&ss->sprinter, " %s (%s in %s)",                              todo = Sprint(&ss->sprinter, " %s (%s in %s)",
3129                                            foreach ? js_for_each_str : js_for_str,                                            foreach ? js_for_each_str : js_for_str,
3130                                            lval, rval);                                            lval, rval);
# Line 3073  Line 3146 
3146                          jp->indent -= 4;                          jp->indent -= 4;
3147                          js_printf(jp, "\t}\n");                          js_printf(jp, "\t}\n");
3148                      }                      }
3149    
3150                      pc += tail;                      pc += tail;
3151                      LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX);                      LOCAL_ASSERT(*pc == JSOP_IFNE || *pc == JSOP_IFNEX);
3152                      len = js_CodeSpec[*pc].length;                      len = js_CodeSpec[*pc].length;
# Line 3450  Line 3524 
3524  #if JS_HAS_LVALUE_RETURN  #if JS_HAS_LVALUE_RETURN
3525                case JSOP_SETCALL:                case JSOP_SETCALL:
3526  #endif  #endif
                 /* Turn off most parens (all if there's only one argument). */  
3527                  argc = GET_ARGC(pc);                  argc = GET_ARGC(pc);
                 op = (argc == 1) ? JSOP_NOP : JSOP_SETNAME;  
3528                  argv = (char **)                  argv = (char **)
3529                      JS_malloc(cx, (size_t)(argc + 1) * sizeof *argv);                      JS_malloc(cx, (size_t)(argc + 1) * sizeof *argv);
3530                  if (!argv)                  if (!argv)
3531                      return NULL;                      return NULL;
3532    
3533                    op = JSOP_SETNAME;
3534                  ok = JS_TRUE;                  ok = JS_TRUE;
3535                  for (i = argc; i > 0; i--) {                  for (i = argc; i > 0; i--)
3536                      argv[i] = JS_strdup(cx, POP_STR());                      argv[i] = JS_strdup(cx, POP_STR());
                     if (!argv[i])  
                         ok = JS_FALSE;  
                 }  
3537    
3538                  /* Skip the JSOP_PUSHOBJ-created empty string. */                  /* Skip the JSOP_PUSHOBJ-created empty string. */
3539                  LOCAL_ASSERT(ss->top >= 2);                  LOCAL_ASSERT(ss->top >= 2);
# Line 3474  Line 3544 
3544                   * Same for new (x(y).z) -- contrast with new x(y).z.                   * Same for new (x(y).z) -- contrast with new x(y).z.
3545                   * See PROPAGATE_CALLNESS.                   * See PROPAGATE_CALLNESS.
3546                   */                   */
3547                  op = (JSOp) ss->opcodes[ss->top-1];                  op = (JSOp) ss->opcodes[ss->top - 1];
3548                  lval = PopStr(ss,                  lval = PopStr(ss,
3549                                (saveop == JSOP_NEW &&                                (saveop == JSOP_NEW &&
3550                                 (op == JSOP_CALL ||                                 (op == JSOP_CALL ||
3551                                  op == JSOP_EVAL ||                                  op == JSOP_EVAL ||
3552                                  op == JSOP_APPLY ||                                  op == JSOP_APPLY ||
3553                                  (js_CodeSpec[op].format & JOF_CALLOP)))                                  (js_CodeSpec[op].format & JOF_CALLOP)))
# Line 3486  Line 3556 
3556                  op = saveop;                  op = saveop;
3557    
3558                  argv[0] = JS_strdup(cx, lval);                  argv[0] = JS_strdup(cx, lval);
3559                  if (!argv[i])                  if (!argv[0])
3560                      ok = JS_FALSE;                      ok = JS_FALSE;
3561    
3562                  lval = "(", rval = ")";                  lval = "(", rval = ")";
# Line 3513  Line 3583 
3583                  if (Sprint(&ss->sprinter, rval) < 0)                  if (Sprint(&ss->sprinter, rval) < 0)
3584                      ok = JS_FALSE;                      ok = JS_FALSE;
3585    
3586                  for (i = 0; i <= argc; i++) {                  for (i = 0; i <= argc; i++)
3587                      if (argv[i])                      JS_free(cx, argv[i]);
                         JS_free(cx, argv[i]);  
                 }  
3588                  JS_free(cx, argv);                  JS_free(cx, argv);
3589                  if (!ok)                  if (!ok)
3590                      return NULL;                      return NULL;
# Line 3900  Line 3968 
3968                  todo = STR2OFF(&ss->sprinter, rval);                  todo = STR2OFF(&ss->sprinter, rval);
3969                  break;                  break;
3970    
3971                case JSOP_ANONFUNOBJ:                case JSOP_LAMBDA:
3972                  case JSOP_LAMBDA_FC:
3973                  case JSOP_LAMBDA_DBGFC:
3974  #if JS_HAS_GENERATOR_EXPRS  #if JS_HAS_GENERATOR_EXPRS
3975                  sn = js_GetSrcNote(jp->script, pc);                  sn = js_GetSrcNote(jp->script, pc);
3976                  if (sn && SN_TYPE(sn) == SRC_GENEXP) {                  if (sn && SN_TYPE(sn) == SRC_GENEXP) {
                     JSScript *inner, *outer;  
3977                      void *mark;                      void *mark;
3978                        jsuword *innerLocalNames, *outerLocalNames;
3979                        JSScript *inner, *outer;
3980                      SprintStack ss2;                      SprintStack ss2;
3981                        JSFunction *outerfun;
3982    
3983                      LOAD_FUNCTION(0);                      LOAD_FUNCTION(0);
                     inner = fun->u.i.script;  
3984    
3985                      /*                      /*
3986                       * All allocation when decompiling is LIFO, using malloc                       * All allocation when decompiling is LIFO, using malloc
3987                       * or, more commonly, arena-alloocating from cx->tempPool.                       * or, more commonly, arena-allocating from cx->tempPool.
3988                       * After InitSprintStack succeeds, we must release to mark                       * Therefore after InitSprintStack succeeds, we must
3989                       * before returning.                       * release to mark before returning.
3990                       */                       */
3991                      mark = JS_ARENA_MARK(&cx->tempPool);                      mark = JS_ARENA_MARK(&cx->tempPool);
3992                      if (!InitSprintStack(cx, &ss2, jp, StackDepth(inner)))                      if (!fun->hasLocalNames()) {
3993                            innerLocalNames = NULL;
3994                        } else {
3995                            innerLocalNames = js_GetLocalNameArray(cx, fun, &cx->tempPool);
3996                            if (!innerLocalNames)
3997                                return NULL;
3998                        }
3999                        inner = fun->u.i.script;
4000                        if (!InitSprintStack(cx, &ss2, jp, StackDepth(inner))) {
4001                            JS_ARENA_RELEASE(&cx->tempPool, mark);
4002                          return NULL;                          return NULL;
4003                        }
4004                      ss2.inGenExp = JS_TRUE;                      ss2.inGenExp = JS_TRUE;
4005    
4006                      /*                      /*
# Line 3930  Line 4011 
4011                       * string pushed on ss2.                       * string pushed on ss2.
4012                       */                       */
4013                      outer = jp->script;                      outer = jp->script;
4014                        outerfun = jp->fun;
4015                        outerLocalNames = jp->localNames;
4016                      LOCAL_ASSERT(JS_UPTRDIFF(pc, outer->code) <= outer->length);                      LOCAL_ASSERT(JS_UPTRDIFF(pc, outer->code) <= outer->length);
4017                      jp->script = inner;                      jp->script = inner;
4018                      if (!Decompile(&ss2, inner->code, inner->length, JSOP_NOP)) {                      jp->fun = fun;
4019                        jp->localNames = innerLocalNames;
4020                        ok = Decompile(&ss2, inner->code, inner->length, JSOP_NOP) != NULL;
4021                        jp->script = outer;
4022                        jp->fun = outerfun;
4023                        jp->localNames = outerLocalNames;
4024                        if (!ok) {
4025                          JS_ARENA_RELEASE(&cx->tempPool, mark);                          JS_ARENA_RELEASE(&cx->tempPool, mark);
4026                          return NULL;                          return NULL;
4027                      }                      }
                     jp->script = outer;  
4028    
4029                      /*                      /*
4030                       * Advance over this op and its global |this| push, and                       * Advance over this op and its global |this| push, and
4031                       * arrange to advance over the call to this lambda.                       * arrange to advance over the call to this lambda.
4032                       */                       */
4033                      pc += len;                      pc += len;
4034                      LOCAL_ASSERT(*pc == JSOP_NULL || *pc == JSOP_NULLTHIS);                      LOCAL_ASSERT(*pc == JSOP_NULL);
4035                      pc += JSOP_NULL_LENGTH;                      pc += JSOP_NULL_LENGTH;
4036                      LOCAL_ASSERT(*pc == JSOP_CALL);                      LOCAL_ASSERT(*pc == JSOP_CALL);
4037                      LOCAL_ASSERT(GET_ARGC(pc) == 0);                      LOCAL_ASSERT(GET_ARGC(pc) == 0);
# Line 3955  Line 4043 
4043                       *  1. It is the complete expression consumed by a control                       *  1. It is the complete expression consumed by a control
4044                       *     flow bytecode such as JSOP_TABLESWITCH whose syntax                       *     flow bytecode such as JSOP_TABLESWITCH whose syntax
4045                       *     always parenthesizes the controlling expression.                       *     always parenthesizes the controlling expression.
4046                       *  2. It is the condition of a loop other than a for (;;).                       *  2. It is the sole argument to a function call.
4047                       *  3. It is the sole argument to a function call.                       *
4048                       *  4. It is the condition of an if statement and not of a                       * But if this genexp runs up against endpc, parenthesize
4049                       *     ?: expression.                       * regardless.  (This can happen if we are called from
4050                         * DecompileExpression or recursively from case
4051                         * JSOP_{NOP,AND,OR}.)
4052                       *                       *
4053                       * But (first, before anything else) always parenthesize                       * There's no special case for |if (genexp)| because the
4054                       * if this genexp runs up against endpc and the next op is                       * compiler optimizes that to |if (true)|.
                      * not a loop condition (JSOP_IFNE*) opcode. In such cases,  
                      * this Decompile activation has been recursively called by  
                      * a comma operator, &&, or || bytecode.  
4055                       */                       */
4056                      pc2 = pc + len;                      pc2 = pc + len;
4057                      LOCAL_ASSERT(pc2 < endpc ||                      LOCAL_ASSERT(pc2 < endpc ||
4058                                   endpc < outer->code + outer->length);                                   endpc < outer->code + outer->length);
4059                      LOCAL_ASSERT(ss2.top == 1);                      LOCAL_ASSERT(ss2.top == 1);
4060                      ss2.opcodes[0] = JSOP_POP;                      ss2.opcodes[0] = JSOP_POP;
4061                      if (pc2 == endpc &&                      if (pc2 == endpc) {
                         (JSOp) *endpc != JSOP_IFNE &&  
                         (JSOp) *endpc != JSOP_IFNEX) {  
4062                          op = JSOP_SETNAME;                          op = JSOP_SETNAME;
4063                      } else {                      } else {
4064                          op = (JSOp) *pc2;                          op = (JSOp) *pc2;
4065                          op = ((js_CodeSpec[op].format & JOF_PARENHEAD) ||                          op = ((js_CodeSpec[op].format & JOF_PARENHEAD) ||
4066                                ((js_CodeSpec[op].format & JOF_INVOKE) &&                                ((js_CodeSpec[op].format & JOF_INVOKE) && GET_ARGC(pc2) == 1))
                                GET_ARGC(pc2) == 1) ||  
                               ((op == JSOP_IFEQ || op == JSOP_IFEQX) &&  
                                (sn2 = js_GetSrcNote(outer, pc2)) &&  
                                SN_TYPE(sn2) != SRC_COND))  
4067                               ? JSOP_POP                               ? JSOP_POP
4068                               : JSOP_SETNAME;                               : JSOP_SETNAME;
4069    
# Line 3991  Line 4072 
4072                           * anonymous function, so it doesn't get decompiled as                           * anonymous function, so it doesn't get decompiled as
4073                           * a generator function in a getter or setter context.                           * a generator function in a getter or setter context.
4074                           * The precedence level is the same for JSOP_NAME and                           * The precedence level is the same for JSOP_NAME and
4075                           * JSOP_ANONFUNOBJ.                           * JSOP_LAMBDA.
4076                           */                           */
4077                          LOCAL_ASSERT(js_CodeSpec[JSOP_NAME].prec ==                          LOCAL_ASSERT(js_CodeSpec[JSOP_NAME].prec ==
4078                                       js_CodeSpec[saveop].prec);                                       js_CodeSpec[saveop].prec);
# Line 4014  Line 4095 
4095  #endif /* JS_HAS_GENERATOR_EXPRS */  #endif /* JS_HAS_GENERATOR_EXPRS */
4096                  /* FALL THROUGH */                  /* FALL THROUGH */
4097    
               case JSOP_NAMEDFUNOBJ:  
4098                  LOAD_FUNCTION(0);                  LOAD_FUNCTION(0);
4099                  {                  {
4100                      uintN indent = JS_DONT_PRETTY_PRINT;                      uintN indent = JS_DONT_PRETTY_PRINT;
# Line 4023  Line 4103 
4103                       * Always parenthesize expression closures. We can't force                       * Always parenthesize expression closures. We can't force
4104                       * saveop to a low-precedence op to arrange for auto-magic                       * saveop to a low-precedence op to arrange for auto-magic
4105                       * parenthesization without confusing getter/setter code                       * parenthesization without confusing getter/setter code
4106                       * that checks for JSOP_ANONFUNOBJ and JSOP_NAMEDFUNOBJ.                       * that checks for JSOP_LAMBDA.
4107                       */                       */
4108                      if (!(fun->flags & JSFUN_EXPR_CLOSURE))                      if (!(fun->flags & JSFUN_EXPR_CLOSURE))
4109                          indent |= JS_IN_GROUP_CONTEXT;                          indent |= JS_IN_GROUP_CONTEXT;
# Line 4035  Line 4115 
4115                  todo = SprintString(&ss->sprinter, str);                  todo = SprintString(&ss->sprinter, str);
4116                  break;                  break;
4117    
4118                  case JSOP_CALLEE:
4119                    JS_ASSERT(jp->fun && jp->fun->atom);
4120                    todo = SprintString(&ss->sprinter, ATOM_TO_STRING(jp->fun->atom));
4121                    break;
4122    
4123                case JSOP_OBJECT:                case JSOP_OBJECT:
4124                  LOAD_OBJECT(0);                  LOAD_OBJECT(0);
4125                  LOCAL_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);                  LOCAL_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
# Line 4097  Line 4182 
4182                      tmp = (TableEntry *)                      tmp = (TableEntry *)
4183                            JS_malloc(cx, (size_t)j * sizeof *table);                            JS_malloc(cx, (size_t)j * sizeof *table);
4184                      if (tmp) {                      if (tmp) {
4185                            VOUCH_DOES_NOT_REQUIRE_STACK();
4186                          ok = js_MergeSort(table, (size_t)j, sizeof(TableEntry),                          ok = js_MergeSort(table, (size_t)j, sizeof(TableEntry),
4187                                            CompareOffsets, NULL, tmp);                                            CompareOffsets, NULL, tmp);
4188                          JS_free(cx, tmp);                          JS_free(cx, tmp);
# Line 4249  Line 4335 
4335                }                }
4336    
4337                case JSOP_DEFFUN:                case JSOP_DEFFUN:
4338                  case JSOP_DEFFUN_FC:
4339                  case JSOP_DEFFUN_DBGFC:
4340                  LOAD_FUNCTION(0);                  LOAD_FUNCTION(0);
4341                  todo = -2;                  todo = -2;
4342                  goto do_function;                  goto do_function;
# Line 4269  Line 4357 
4357                  break;                  break;
4358    
4359                case JSOP_NEWARRAY:                case JSOP_NEWARRAY:
4360                {                  argc = GET_UINT16(pc);
                 ptrdiff_t off;  
                 char *base, *from, *to;  
   
                 /*  
                  * All operands are stacked and ready for in-place formatting.  
                  * We know that PAREN_SLOP is 3 here, and take advantage of it  
                  * to avoid strdup'ing.  
                  */  
                 argc = GET_UINT24(pc);  
4361                  LOCAL_ASSERT(ss->top >= (uintN) argc);                  LOCAL_ASSERT(ss->top >= (uintN) argc);
                 sn = js_GetSrcNote(jp->script, pc);  
4362                  if (argc == 0) {                  if (argc == 0) {
4363                      todo = Sprint(&ss->sprinter, "[%s]",                      todo = SprintCString(&ss->sprinter, "[]");
4364                                    (sn && SN_TYPE(sn) == SRC_CONTINUE)                      break;
4365                                    ? ", "                  }
4366                                    : "");  
4367                  } else {                  argv = (char **) JS_malloc(cx, size_t(argc) * sizeof *argv);
4368                      ss->top -= argc;                  if (!argv)
4369                      off = GetOff(ss, ss->top);                      return NULL;
4370                      LOCAL_ASSERT(off >= PAREN_SLOP);  
4371                      base = OFF2STR(&ss->sprinter, off);                  op = JSOP_SETNAME;
4372                      to = base + 1;                  ok = JS_TRUE;
4373                      i = 0;                  i = argc;
4374                      for (;;) {                  while (i > 0)
4375                          /* Move to the next string that had been stacked. */                      argv[--i] = JS_strdup(cx, POP_STR());
4376                          from = OFF2STR(&ss->sprinter, off);  
4377                          todo = strlen(from);                  todo = SprintCString(&ss->sprinter, "[");
4378                          memmove(to, from, todo);                  if (todo < 0)
4379                          to += todo;                      break;
4380                          if (++i == argc &&  
4381                              !(sn && SN_TYPE(sn) == SRC_CONTINUE)) {                  for (i = 0; i < argc; i++) {
4382                              break;                      if (!argv[i] ||
4383                          }                          Sprint(&ss->sprinter, ss_format,
4384                          *to++ = ',';                                 argv[i], (i < argc - 1) ? ", " : "") < 0) {
4385                          *to++ = ' ';                          ok = JS_FALSE;
4386                          off = GetOff(ss, ss->top + i);                          break;
4387                      }                      }
                     LOCAL_ASSERT(to - base < ss->sprinter.offset - PAREN_SLOP);  
                     *base = '[';  
                     *to++ = ']';  
                     *to = '\0';  
                     ss->sprinter.offset = STR2OFF(&ss->sprinter, to);  
                     todo = STR2OFF(&ss->sprinter, base);  
4388                  }                  }
4389    
4390                    for (i = 0; i < argc; i++)
4391                        JS_free(cx, argv[i]);
4392                    JS_free(cx, argv);
4393                    if (!ok)
4394                        return NULL;
4395    
4396                    sn = js_GetSrcNote(jp->script, pc);
4397                    if (sn && SN_TYPE(sn) == SRC_CONTINUE && SprintCString(&ss->sprinter, ", ") < 0)
4398                        return NULL;
4399                    if (SprintCString(&ss->sprinter, "]") < 0)
4400                        return NULL;
4401                  break;                  break;
               }  
4402    
4403                case JSOP_NEWINIT:                case JSOP_NEWINIT:
4404                {                {
# Line 4425  Line 4508 
4508                          !ATOM_IS_STRING(atom) ||                          !ATOM_IS_STRING(atom) ||
4509                          !ATOM_IS_IDENTIFIER(atom) ||                          !ATOM_IS_IDENTIFIER(atom) ||
4510                          ATOM_IS_KEYWORD(atom) ||                          ATOM_IS_KEYWORD(atom) ||
4511                          (ss->opcodes[ss->top+1] != JSOP_ANONFUNOBJ &&                          (ss->opcodes[ss->top+1] != JSOP_LAMBDA &&
4512                           ss->opcodes[ss->top+1] != JSOP_NAMEDFUNOBJ)) {                           ss->opcodes[ss->top+1] != JSOP_LAMBDA_FC)) {
4513                          todo = Sprint(&ss->sprinter, "%s%s%s %s: %s",                          todo = Sprint(&ss->sprinter, "%s%s%s %s: %s",
4514                                        lval,                                        lval,
4515                                        maybeComma,                                        maybeComma,
# Line 4946  Line 5029 
5029                spindex == JSDVG_IGNORE_STACK ||                spindex == JSDVG_IGNORE_STACK ||
5030                spindex == JSDVG_SEARCH_STACK);                spindex == JSDVG_SEARCH_STACK);
5031    
5032      for (fp = cx->fp; fp && !fp->script; fp = fp->down)      fp = js_GetScriptedCaller(cx, NULL);
5033          continue;      if (!fp || !fp->regs || !fp->regs->sp)
     if (!fp || !fp->regs)  
5034          goto do_fallback;          goto do_fallback;
5035    
5036      script = fp->script;      script = fp->script;
# Line 4995  Line 5077 
5077                  }                  }
5078              } while (*--sp != v);              } while (*--sp != v);
5079    
5080              if (sp >= stackBase + pcdepth) {              /*
5081                  /*               * The value may have come from beyond stackBase + pcdepth,
5082                   * The value comes from a temporary slot that the interpreter               * meaning that it came from a temporary slot that the
5083                   * uses for GC roots or when JSOP_APPLY extended the stack to               * interpreter uses for GC roots or when JSOP_APPLY extended
5084                   * fit the argument array elements. Assume that it is the               * the stack to fit the argument array elements. Only update pc
5085                   * current PC that caused the exception.               * if beneath stackBase + pcdepth; otherwise blame existing
5086                   */               * (current) PC.
5087                  pc = fp->imacpc ? fp->imacpc : regs->pc;               */
5088              } else {              if (sp < stackBase + pcdepth)
5089                  pc = pcstack[sp - stackBase];                  pc = pcstack[sp - stackBase];
             }  
5090          }          }
5091    
5092        release_pcstack:        release_pcstack:
# Line 5021  Line 5102 
5102              regs->pc = imacpc;              regs->pc = imacpc;
5103              fp->imacpc = NULL;              fp->imacpc = NULL;
5104          }          }
5105          name = DecompileExpression(cx, script, fp->fun, pc);  
5106            /*
5107             * FIXME: bug 489843. Stack reconstruction may have returned a pc
5108             * value *inside* an imacro; this would confuse the decompiler.
5109             */
5110            if (imacpc && size_t(pc - script->code) >= script->length)
5111                name = FAILED_EXPRESSION_DECOMPILER;
5112            else
5113                name = DecompileExpression(cx, script, fp->fun, pc);
5114    
5115          if (imacpc) {          if (imacpc) {
5116              regs->pc = savepc;              regs->pc = savepc;
5117              fp->imacpc = imacpc;              fp->imacpc = imacpc;
# Line 5075  Line 5165 
5165      JS_ASSERT(op != JSOP_CASE && op != JSOP_CASEX &&      JS_ASSERT(op != JSOP_CASE && op != JSOP_CASEX &&
5166                op != JSOP_DUP && op != JSOP_DUP2);                op != JSOP_DUP && op != JSOP_DUP2);
5167    
5168        /* JSOP_PUSH is used to generate undefined for group assignment holes. */
5169        if (op == JSOP_PUSH) {
5170            name = JS_strdup(cx, js_undefined_str);
5171            goto out;
5172        }
5173    
5174      /*      /*
5175       * |this| could convert to a very long object initialiser, so cite it by       * |this| could convert to a very long object initialiser, so cite it by
5176       * its keyword name instead.       * its keyword name instead.
# Line 5173  Line 5269 
5269      return ReconstructPCStack(cx, script, pc, NULL);      return ReconstructPCStack(cx, script, pc, NULL);
5270  }  }
5271    
5272    #define LOCAL_ASSERT(expr)      LOCAL_ASSERT_RV(expr, -1);
5273    
5274  static intN  static intN
5275  ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,  SimulateOp(JSContext *cx, JSScript *script, JSOp op, const JSCodeSpec *cs,
5276                     jsbytecode **pcstack)             jsbytecode *pc, jsbytecode **pcstack, uintN &pcdepth)
5277  {  {
5278      intN pcdepth, nuses, ndefs;      uintN nuses = js_GetStackUses(cs, op, pc);
5279      jsbytecode *pc;      uintN ndefs = js_GetStackDefs(cx, cs, op, script, pc);
5280      JSOp op;      LOCAL_ASSERT(pcdepth >= nuses);
5281      const JSCodeSpec *cs;      pcdepth -= nuses;
5282        LOCAL_ASSERT(pcdepth + ndefs <= StackDepth(script));
5283    
5284        /*
5285         * Fill the slots that the opcode defines withs its pc unless it just
5286         * reshuffles the stack. In the latter case we want to preserve the
5287         * opcode that generated the original value.
5288         */
5289        switch (op) {
5290          default:
5291            if (pcstack) {
5292                for (uintN i = 0; i != ndefs; ++i)
5293                    pcstack[pcdepth + i] = pc;
5294            }
5295            break;
5296    
5297          case JSOP_CASE:
5298          case JSOP_CASEX:
5299            /* Keep the switch value. */
5300            JS_ASSERT(ndefs == 1);
5301            break;
5302    
5303          case JSOP_DUP:
5304            JS_ASSERT(ndefs == 2);
5305            if (pcstack)
5306                pcstack[pcdepth + 1] = pcstack[pcdepth];
5307            break;
5308    
5309          case JSOP_DUP2:
5310            JS_ASSERT(ndefs == 4);
5311            if (pcstack) {
5312                pcstack[pcdepth + 2] = pcstack[pcdepth];
5313                pcstack[pcdepth + 3] = pcstack[pcdepth + 1];
5314            }
5315            break;
5316    
5317          case JSOP_SWAP:
5318            JS_ASSERT(ndefs == 2);
5319            if (pcstack) {
5320                jsbytecode *tmp = pcstack[pcdepth + 1];
5321                pcstack[pcdepth + 1] = pcstack[pcdepth];
5322                pcstack[pcdepth] = tmp;
5323            }
5324            break;
5325        }
5326        pcdepth += ndefs;
5327        return pcdepth;
5328    }
5329    
5330    #ifdef JS_TRACER
5331    static intN
5332    SimulateImacroCFG(JSContext *cx, JSScript *script,
5333                      uintN pcdepth, jsbytecode *pc, jsbytecode *target,
5334                      jsbytecode **pcstack)
5335    {
5336        size_t nbytes = StackDepth(script) * sizeof *pcstack;
5337        jsbytecode** tmp_pcstack = (jsbytecode **) JS_malloc(cx, nbytes);
5338        if (!tmp_pcstack)
5339            return -1;
5340        memcpy(tmp_pcstack, pcstack, nbytes);
5341    
5342      ptrdiff_t oplen;      ptrdiff_t oplen;
5343      jssrcnote *sn;      for (; pc < target; pc += oplen) {
5344      intN i;          JSOp op = js_GetOpcode(cx, script, pc);
5345            const JSCodeSpec *cs = &js_CodeSpec[op];
5346            oplen = cs->length;
5347            if (oplen < 0)
5348                oplen = js_GetVariableBytecodeLength(pc);
5349    
5350  #define LOCAL_ASSERT(expr)      LOCAL_ASSERT_RV(expr, -1);          if (SimulateOp(cx, script, op, cs, pc, tmp_pcstack, pcdepth) < 0)
5351                goto failure;
5352    
5353            uint32 type = cs->format & JOF_TYPEMASK;
5354            if (type == JOF_JUMP || type == JOF_JUMPX) {
5355                ptrdiff_t jmpoff = (type == JOF_JUMP) ? GET_JUMP_OFFSET(pc)
5356                                                      : GET_JUMPX_OFFSET(pc);
5357                LOCAL_ASSERT(jmpoff >= 0);
5358                uintN tmp_pcdepth = SimulateImacroCFG(cx, script, pcdepth, pc + jmpoff,
5359                                                      target, tmp_pcstack);
5360                if (tmp_pcdepth >= 0) {
5361                    pcdepth = tmp_pcdepth;
5362                    goto success;
5363                }
5364    
5365                if (op == JSOP_GOTO || op == JSOP_GOTOX)
5366                    goto failure;
5367            }
5368        }
5369    
5370        if (pc > target)
5371            goto failure;
5372    
5373        LOCAL_ASSERT(pc == target);
5374    
5375      success:
5376        LOCAL_ASSERT(pcdepth >= 0);
5377        memcpy(pcstack, tmp_pcstack, nbytes);
5378        JS_free(cx, tmp_pcstack);
5379        return pcdepth;
5380    
5381      failure:
5382        JS_free(cx, tmp_pcstack);
5383        return -1;
5384    }
5385    
5386    static intN
5387    ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,
5388                       jsbytecode **pcstack);
5389    
5390    static intN
5391    ReconstructImacroPCStack(JSContext *cx, JSScript *script,
5392                             jsbytecode *imacstart, jsbytecode *target,
5393                             jsbytecode **pcstack)
5394    {
5395        /*
5396         * Begin with a recursive call back to ReconstructPCStack to pick up
5397         * the state-of-the-world at the *start* of the imacro.
5398         */
5399        JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
5400        JS_ASSERT(fp->imacpc);
5401        uintN pcdepth = ReconstructPCStack(cx, script, fp->imacpc, pcstack);
5402        if (pcdepth < 0)
5403            return pcdepth;
5404        return SimulateImacroCFG(cx, script, pcdepth, imacstart, target, pcstack);
5405    }
5406    
5407    extern jsbytecode* js_GetImacroStart(jsbytecode* pc);
5408    #endif
5409    
5410    static intN
5411    ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,
5412                       jsbytecode **pcstack)
5413    {
5414      /*      /*
5415       * Walk forward from script->main and compute the stack depth and stack of       * Walk forward from script->main and compute the stack depth and stack of
5416       * operand-generating opcode PCs in pcstack.       * operand-generating opcode PCs in pcstack.
# Line 5194  Line 5418 
5418       * FIXME: Code to compute oplen copied from js_Disassemble1 and reduced.       * FIXME: Code to compute oplen copied from js_Disassemble1 and reduced.
5419       * FIXME: Optimize to use last empty-stack sequence point.       * FIXME: Optimize to use last empty-stack sequence point.
5420       */       */
5421    #ifdef JS_TRACER
5422        jsbytecode *imacstart = js_GetImacroStart(target);
5423    
5424        if (imacstart)
5425            return ReconstructImacroPCStack(cx, script, imacstart, target, pcstack);
5426    #endif
5427    
5428      LOCAL_ASSERT(script->main <= target && target < script->code + script->length);      LOCAL_ASSERT(script->main <= target && target < script->code + script->length);
5429      pcdepth = 0;      jsbytecode *pc = script->main;
5430      for (pc = script->main; pc < target; pc += oplen) {      uintN pcdepth = 0;
5431          op = (JSOp) *pc;      ptrdiff_t oplen;
5432          if (op == JSOP_TRAP)      for (; pc < target; pc += oplen) {
5433              op = JS_GetTrapOpcode(cx, script, pc);          JSOp op = js_GetOpcode(cx, script, pc);
5434          cs = &js_CodeSpec[op];          const JSCodeSpec *cs = &js_CodeSpec[op];
5435          oplen = cs->length;          oplen = cs->length;
5436          if (oplen < 0)          if (oplen < 0)
5437              oplen = js_GetVariableBytecodeLength(pc);              oplen = js_GetVariableBytecodeLength(pc);
# Line 5212  Line 5443 
5443           * tests condition C.  We know that the stack depth can't change from           * tests condition C.  We know that the stack depth can't change from
5444           * what it was with C on top of stack.           * what it was with C on top of stack.
5445           */           */
5446          sn = js_GetSrcNote(script, pc);          jssrcnote *sn = js_GetSrcNote(script, pc);
5447          if (sn && SN_TYPE(sn) == SRC_COND) {          if (sn && SN_TYPE(sn) == SRC_COND) {
5448              ptrdiff_t jmpoff, jmplen;              ptrdiff_t jmpoff = js_GetSrcNoteOffset(sn, 0);
   
             jmpoff = js_GetSrcNoteOffset(sn, 0);  
5449              if (pc + jmpoff < target) {              if (pc + jmpoff < target) {
5450                  pc += jmpoff;                  pc += jmpoff;
5451                  op = (JSOp) *pc;                  op = js_GetOpcode(cx, script, pc);
5452                  JS_ASSERT(op == JSOP_GOTO || op == JSOP_GOTOX);                  JS_ASSERT(op == JSOP_GOTO || op == JSOP_GOTOX);
5453                  cs = &js_CodeSpec[op];                  cs = &js_CodeSpec[op];
5454                  oplen = cs->length;                  oplen = cs->length;
5455                  JS_ASSERT(oplen > 0);                  JS_ASSERT(oplen > 0);
5456                  jmplen = GetJumpOffset(pc, pc);                  ptrdiff_t jmplen = GetJumpOffset(pc, pc);
5457                  if (pc + jmplen < target) {                  if (pc + jmplen < target) {
5458                      oplen = (uintN) jmplen;                      oplen = (uintN) jmplen;
5459                      continue;                      continue;
# Line 5234  Line 5463 
5463                   * Ok, target lies in E. Manually pop C off the model stack,                   * Ok, target lies in E. Manually pop C off the model stack,
5464                   * since we have moved beyond the IFEQ now.                   * since we have moved beyond the IFEQ now.
5465                   */                   */
5466                    LOCAL_ASSERT(pcdepth != 0);
5467                  --pcdepth;                  --pcdepth;
                 LOCAL_ASSERT(pcdepth >= 0);  
5468              }              }
5469          }          }
5470    
5471          if (sn && SN_TYPE(sn) == SRC_HIDDEN)          if (sn && SN_TYPE(sn) == SRC_HIDDEN)
5472              continue;              continue;
5473    
5474          nuses = cs->nuses;          if (SimulateOp(cx, script, op, cs, pc, pcstack, pcdepth) < 0)
5475          if (nuses < 0)              return -1;
             nuses = js_GetVariableStackUseLength(op, pc);  
   
         ndefs = cs->ndefs;  
         if (ndefs < 0) {  
             JSObject *obj;  
   
             JS_ASSERT(op == JSOP_ENTERBLOCK);  
             GET_OBJECT_FROM_BYTECODE(script, pc, 0, obj);  
             JS_ASSERT(OBJ_BLOCK_DEPTH(cx, obj) == pcdepth);  
             ndefs = OBJ_BLOCK_COUNT(cx, obj);  
         }  
   
         pcdepth -= nuses;  
         LOCAL_ASSERT(pcdepth >= 0);  
         LOCAL_ASSERT((uintN)(pcdepth + ndefs) <= StackDepth(script));  
   
         /*  
          * Fill the slots that the opcode defines withs its pc unless it just  
          * reshuffle the stack. In the latter case we want to preserve the  
          * opcode that generated the original value.  
          */  
         switch (op) {  
           default:  
             if (pcstack) {  
                 for (i = 0; i != ndefs; ++i)  
                     pcstack[pcdepth + i] = pc;  
             }  
             break;  
   
           case JSOP_CASE:  
           case JSOP_CASEX:  
             /* Keep the switch value. */  
             JS_ASSERT(ndefs == 1);  
             break;  
   
           case JSOP_DUP:  
             JS_ASSERT(ndefs == 2);  
             if (pcstack)  
                 pcstack[pcdepth + 1] = pcstack[pcdepth];  
             break;  
5476    
           case JSOP_DUP2:  
             JS_ASSERT(ndefs == 4);  
             if (pcstack) {  
                 pcstack[pcdepth + 2] = pcstack[pcdepth];  
                 pcstack[pcdepth + 3] = pcstack[pcdepth + 1];  
             }  
             break;  
         }  
         pcdepth += ndefs;  
5477      }      }
5478      LOCAL_ASSERT(pc == target);      LOCAL_ASSERT(pc == target);
5479      return pcdepth;      return pcdepth;

Legend:
Removed from v.459  
changed lines
  Added in v.460

  ViewVC Help
Powered by ViewVC 1.1.24