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

Diff of /trunk/js/jsemit.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 460 by siliconforks, Sat Sep 26 23:15:22 2009 UTC
# Line 45  Line 45 
45  #ifdef HAVE_MEMORY_H  #ifdef HAVE_MEMORY_H
46  #include <memory.h>  #include <memory.h>
47  #endif  #endif
48    #include <new>
49  #include <string.h>  #include <string.h>
50  #include "jstypes.h"  #include "jstypes.h"
51  #include "jsarena.h" /* Added by JSIFY */  #include "jsarena.h" /* Added by JSIFY */
# Line 82  Line 83 
83  NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind,  NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind,
84             uintN stackDepth, size_t start, size_t end);             uintN stackDepth, size_t start, size_t end);
85    
86  JS_FRIEND_API(void)  JSCodeGenerator::JSCodeGenerator(JSCompiler *jsc,
87  js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc,                                   JSArenaPool *cpool, JSArenaPool *npool,
88                       JSArenaPool *codePool, JSArenaPool *notePool,                                   uintN lineno)
89                       uintN lineno)    : JSTreeContext(jsc),
90  {      codePool(cpool), notePool(npool),
91      memset(cg, 0, sizeof *cg);      codeMark(JS_ARENA_MARK(cpool)), noteMark(JS_ARENA_MARK(npool)),
92      TREE_CONTEXT_INIT(&cg->treeContext, pc);      stackDepth(0), maxStackDepth(0),
93      cg->codePool = codePool;      ntrynotes(0), lastTryNode(NULL),
94      cg->notePool = notePool;      spanDeps(NULL), jumpTargets(NULL), jtFreeList(NULL),
95      cg->codeMark = JS_ARENA_MARK(codePool);      numSpanDeps(0), numJumpTargets(0), spanDepTodo(0),
96      cg->noteMark = JS_ARENA_MARK(notePool);      arrayCompDepth(0),
97      cg->current = &cg->main;      emitLevel(0)
98      cg->firstLine = cg->prolog.currentLine = cg->main.currentLine = lineno;  {
99      ATOM_LIST_INIT(&cg->atomList);      flags = TCF_COMPILING;
100      cg->prolog.noteMask = cg->main.noteMask = SRCNOTE_CHUNK - 1;      memset(&prolog, 0, sizeof prolog);
101      ATOM_LIST_INIT(&cg->constList);      memset(&main, 0, sizeof main);
102      ATOM_LIST_INIT(&cg->upvarList);      current = &main;
103  }      firstLine = prolog.currentLine = main.currentLine = lineno;
104        prolog.noteMask = main.noteMask = SRCNOTE_CHUNK - 1;
105  JS_FRIEND_API(void)      memset(&upvarMap, 0, sizeof upvarMap);
106  js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg)  }
107  {  
108      TREE_CONTEXT_FINISH(cx, &cg->treeContext);  JSCodeGenerator::~JSCodeGenerator()
109      JS_ARENA_RELEASE(cg->codePool, cg->codeMark);  {
110      JS_ARENA_RELEASE(cg->notePool, cg->noteMark);      JS_ARENA_RELEASE(codePool, codeMark);
111        JS_ARENA_RELEASE(notePool, noteMark);
112    
113      /* NB: non-null only after OOM. */      /* NB: non-null only after OOM. */
114      if (cg->spanDeps)      if (spanDeps)
115          JS_free(cx, cg->spanDeps);          JS_free(compiler->context, spanDeps);
116    
117      if (cg->upvarMap.vector)      if (upvarMap.vector)
118          JS_free(cx, cg->upvarMap.vector);          JS_free(compiler->context, upvarMap.vector);
119  }  }
120    
121  static ptrdiff_t  static ptrdiff_t
# Line 157  Line 159 
159      jsbytecode *pc;      jsbytecode *pc;
160      JSOp op;      JSOp op;
161      const JSCodeSpec *cs;      const JSCodeSpec *cs;
162      uintN depth;      uintN extra, depth, nuses;
163      intN nuses, ndefs;      intN ndefs;
164    
165      pc = CG_CODE(cg, target);      pc = CG_CODE(cg, target);
166      op = (JSOp) *pc;      op = (JSOp) *pc;
167      cs = &js_CodeSpec[op];      cs = &js_CodeSpec[op];
168      if (cs->format & JOF_TMPSLOT_MASK) {  #ifdef JS_TRACER
169        extern uint8 js_opcode2extra[];
170        extra = js_opcode2extra[op];
171    #else
172        extra = 0;
173    #endif
174        if ((cs->format & JOF_TMPSLOT_MASK) || extra) {
175          depth = (uintN) cg->stackDepth +          depth = (uintN) cg->stackDepth +
176                  ((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT);                  ((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT) +
177                    extra;
178          if (depth > cg->maxStackDepth)          if (depth > cg->maxStackDepth)
179              cg->maxStackDepth = depth;              cg->maxStackDepth = depth;
180      }      }
181      nuses = cs->nuses;  
182      if (nuses < 0)      nuses = js_GetStackUses(cs, op, pc);
         nuses = js_GetVariableStackUseLength(op, pc);  
183      cg->stackDepth -= nuses;      cg->stackDepth -= nuses;
184      JS_ASSERT(cg->stackDepth >= 0);      JS_ASSERT(cg->stackDepth >= 0);
185      if (cg->stackDepth < 0) {      if (cg->stackDepth < 0) {
# Line 179  Line 187 
187          JSTokenStream *ts;          JSTokenStream *ts;
188    
189          JS_snprintf(numBuf, sizeof numBuf, "%d", target);          JS_snprintf(numBuf, sizeof numBuf, "%d", target);
190          ts = &cg->treeContext.parseContext->tokenStream;          ts = &cg->compiler->tokenStream;
191          JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING,          JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING,
192                                       js_GetErrorMessage, NULL,                                       js_GetErrorMessage, NULL,
193                                       JSMSG_STACK_UNDERFLOW,                                       JSMSG_STACK_UNDERFLOW,
# Line 193  Line 201 
201          /* We just executed IndexParsedObject */          /* We just executed IndexParsedObject */
202          JS_ASSERT(op == JSOP_ENTERBLOCK);          JS_ASSERT(op == JSOP_ENTERBLOCK);
203          JS_ASSERT(nuses == 0);          JS_ASSERT(nuses == 0);
204          blockObj = cg->objectList.lastPob->object;          blockObj = cg->objectList.lastbox->object;
205          JS_ASSERT(STOBJ_GET_CLASS(blockObj) == &js_BlockClass);          JS_ASSERT(STOBJ_GET_CLASS(blockObj) == &js_BlockClass);
206          JS_ASSERT(JSVAL_IS_VOID(blockObj->fslots[JSSLOT_BLOCK_DEPTH]));          JS_ASSERT(JSVAL_IS_VOID(blockObj->fslots[JSSLOT_BLOCK_DEPTH]));
207    
# Line 299  Line 307 
307  static const char *  static const char *
308  StatementName(JSCodeGenerator *cg)  StatementName(JSCodeGenerator *cg)
309  {  {
310      if (!cg->treeContext.topStmt)      if (!cg->topStmt)
311          return js_script_str;          return js_script_str;
312      return statementName[cg->treeContext.topStmt->type];      return statementName[cg->topStmt->type];
313  }  }
314    
315  static void  static void
# Line 885  Line 893 
893    
894      if (growth) {      if (growth) {
895  #ifdef DEBUG_brendan  #ifdef DEBUG_brendan
896          JSTokenStream *ts = &cg->treeContext.parseContext->tokenStream;          JSTokenStream *ts = &cg->compiler->tokenStream;
897    
898          printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n",          printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n",
899                 ts->filename ? ts->filename : "stdin", cg->firstLine,                 ts->filename ? ts->filename : "stdin", cg->firstLine,
# Line 1225  Line 1233 
1233      return SetSpanDepTarget(cx, cg, GetSpanDep(cg, pc), off);      return SetSpanDepTarget(cx, cg, GetSpanDep(cg, pc), off);
1234  }  }
1235    
1236  JSBool  bool
1237  js_InStatement(JSTreeContext *tc, JSStmtType type)  JSTreeContext::inStatement(JSStmtType type)
1238  {  {
1239      JSStmtInfo *stmt;      for (JSStmtInfo *stmt = topStmt; stmt; stmt = stmt->down) {
   
     for (stmt = tc->topStmt; stmt; stmt = stmt->down) {  
1240          if (stmt->type == type)          if (stmt->type == type)
1241              return JS_TRUE;              return true;
1242      }      }
1243      return JS_FALSE;      return false;
1244  }  }
1245    
1246  void  void
# Line 1243  Line 1249 
1249  {  {
1250      stmt->type = type;      stmt->type = type;
1251      stmt->flags = 0;      stmt->flags = 0;
1252        stmt->blockid = tc->blockid();
1253      SET_STATEMENT_TOP(stmt, top);      SET_STATEMENT_TOP(stmt, top);
1254      stmt->u.label = NULL;      stmt->label = NULL;
1255      JS_ASSERT(!stmt->u.blockObj);      JS_ASSERT(!stmt->blockObj);
1256      stmt->down = tc->topStmt;      stmt->down = tc->topStmt;
1257      tc->topStmt = stmt;      tc->topStmt = stmt;
1258      if (STMT_LINKS_SCOPE(stmt)) {      if (STMT_LINKS_SCOPE(stmt)) {
# Line 1260  Line 1267 
1267  js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj,  js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj,
1268                    ptrdiff_t top)                    ptrdiff_t top)
1269  {  {
   
1270      js_PushStatement(tc, stmt, STMT_BLOCK, top);      js_PushStatement(tc, stmt, STMT_BLOCK, top);
1271      stmt->flags |= SIF_SCOPE;      stmt->flags |= SIF_SCOPE;
1272      STOBJ_SET_PARENT(blockObj, tc->blockChain);      STOBJ_SET_PARENT(blockObj, tc->blockChain);
1273      stmt->downScope = tc->topScopeStmt;      stmt->downScope = tc->topScopeStmt;
1274      tc->topScopeStmt = stmt;      tc->topScopeStmt = stmt;
1275      tc->blockChain = blockObj;      tc->blockChain = blockObj;
1276      stmt->u.blockObj = blockObj;      stmt->blockObj = blockObj;
1277  }  }
1278    
1279  /*  /*
# Line 1329  Line 1335 
1335    
1336  #define FLUSH_POPS() if (npops && !FlushPops(cx, cg, &npops)) return JS_FALSE  #define FLUSH_POPS() if (npops && !FlushPops(cx, cg, &npops)) return JS_FALSE
1337    
1338      for (stmt = cg->treeContext.topStmt; stmt != toStmt; stmt = stmt->down) {      for (stmt = cg->topStmt; stmt != toStmt; stmt = stmt->down) {
1339          switch (stmt->type) {          switch (stmt->type) {
1340            case STMT_FINALLY:            case STMT_FINALLY:
1341              FLUSH_POPS();              FLUSH_POPS();
# Line 1377  Line 1383 
1383              FLUSH_POPS();              FLUSH_POPS();
1384              if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)              if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
1385                  return JS_FALSE;                  return JS_FALSE;
1386              i = OBJ_BLOCK_COUNT(cx, stmt->u.blockObj);              i = OBJ_BLOCK_COUNT(cx, stmt->blockObj);
1387              EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, i);              EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, i);
1388          }          }
1389      }      }
# Line 1445  Line 1451 
1451      if (STMT_LINKS_SCOPE(stmt)) {      if (STMT_LINKS_SCOPE(stmt)) {
1452          tc->topScopeStmt = stmt->downScope;          tc->topScopeStmt = stmt->downScope;
1453          if (stmt->flags & SIF_SCOPE) {          if (stmt->flags & SIF_SCOPE) {
1454              tc->blockChain = STOBJ_GET_PARENT(stmt->u.blockObj);              tc->blockChain = STOBJ_GET_PARENT(stmt->blockObj);
1455              JS_SCOPE_DEPTH_METERING(--tc->scopeDepth);              JS_SCOPE_DEPTH_METERING(--tc->scopeDepth);
1456          }          }
1457      }      }
# Line 1456  Line 1462 
1462  {  {
1463      JSStmtInfo *stmt;      JSStmtInfo *stmt;
1464    
1465      stmt = cg->treeContext.topStmt;      stmt = cg->topStmt;
1466      if (!STMT_IS_TRYING(stmt) &&      if (!STMT_IS_TRYING(stmt) &&
1467          (!BackPatch(cx, cg, stmt->breaks, CG_NEXT(cg), JSOP_GOTO) ||          (!BackPatch(cx, cg, stmt->breaks, CG_NEXT(cg), JSOP_GOTO) ||
1468           !BackPatch(cx, cg, stmt->continues, CG_CODE(cg, stmt->update),           !BackPatch(cx, cg, stmt->continues, CG_CODE(cg, stmt->update),
1469                      JSOP_GOTO))) {                      JSOP_GOTO))) {
1470          return JS_FALSE;          return JS_FALSE;
1471      }      }
1472      js_PopStatement(&cg->treeContext);      js_PopStatement(cg);
1473      return JS_TRUE;      return JS_TRUE;
1474  }  }
1475    
# Line 1493  Line 1499 
1499                  return JS_FALSE;                  return JS_FALSE;
1500              v = ATOM_KEY(valueAtom);              v = ATOM_KEY(valueAtom);
1501          }          }
1502          ale = js_IndexAtom(cx, atom, &cg->constList);          ale = cg->constList.add(cg->compiler, atom);
1503          if (!ale)          if (!ale)
1504              return JS_FALSE;              return JS_FALSE;
1505          ALE_SET_VALUE(ale, v);          ALE_SET_VALUE(ale, v);
# Line 1502  Line 1508 
1508  }  }
1509    
1510  JSStmtInfo *  JSStmtInfo *
1511  js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp)  js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt)
1512  {  {
     JSStmtInfo *stmt;  
1513      JSObject *obj;      JSObject *obj;
1514      JSScope *scope;      JSScope *scope;
1515      JSScopeProperty *sprop;      JSScopeProperty *sprop;
1516    
1517      for (stmt = tc->topScopeStmt; stmt; stmt = stmt->downScope) {      if (!stmt)
1518            stmt = tc->topScopeStmt;
1519        for (; stmt; stmt = stmt->downScope) {
1520          if (stmt->type == STMT_WITH)          if (stmt->type == STMT_WITH)
1521              break;              break;
1522    
# Line 1517  Line 1524 
1524          if (!(stmt->flags & SIF_SCOPE))          if (!(stmt->flags & SIF_SCOPE))
1525              continue;              continue;
1526    
1527          obj = stmt->u.blockObj;          obj = stmt->blockObj;
1528          JS_ASSERT(LOCKED_OBJ_GET_CLASS(obj) == &js_BlockClass);          JS_ASSERT(LOCKED_OBJ_GET_CLASS(obj) == &js_BlockClass);
1529          scope = OBJ_SCOPE(obj);          scope = OBJ_SCOPE(obj);
1530          sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));          sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
# Line 1557  Line 1564 
1564      JSBool ok;      JSBool ok;
1565      JSStmtInfo *stmt;      JSStmtInfo *stmt;
1566      JSAtomListElement *ale;      JSAtomListElement *ale;
1567      JSObject *obj, *pobj;      JSObject *obj, *objbox;
1568      JSProperty *prop;      JSProperty *prop;
1569      uintN attrs;      uintN attrs;
1570    
# Line 1568  Line 1575 
1575       */       */
1576      *vp = JSVAL_HOLE;      *vp = JSVAL_HOLE;
1577      do {      do {
1578          if (cg->treeContext.flags & (TCF_IN_FUNCTION | TCF_COMPILE_N_GO)) {          if (cg->flags & (TCF_IN_FUNCTION | TCF_COMPILE_N_GO)) {
1579              /* XXX this will need revising when 'let const' is added. */              /* XXX this will need revising if 'const' becomes block-scoped. */
1580              stmt = js_LexicalLookup(&cg->treeContext, atom, NULL);              stmt = js_LexicalLookup(cg, atom, NULL);
1581              if (stmt)              if (stmt)
1582                  return JS_TRUE;                  return JS_TRUE;
1583    
1584              ATOM_LIST_SEARCH(ale, &cg->constList, atom);              ale = cg->constList.lookup(atom);
1585              if (ale) {              if (ale) {
1586                  JS_ASSERT(ALE_VALUE(ale) != JSVAL_HOLE);                  JS_ASSERT(ALE_VALUE(ale) != JSVAL_HOLE);
1587                  *vp = ALE_VALUE(ale);                  *vp = ALE_VALUE(ale);
# Line 1588  Line 1595 
1595               * with object or catch variable; nor can prop's value be changed,               * with object or catch variable; nor can prop's value be changed,
1596               * nor can prop be deleted.               * nor can prop be deleted.
1597               */               */
1598              if (cg->treeContext.flags & TCF_IN_FUNCTION) {              if (cg->flags & TCF_IN_FUNCTION) {
1599                  if (js_LookupLocal(cx, cg->treeContext.u.fun, atom, NULL) !=                  if (js_LookupLocal(cx, cg->fun, atom, NULL) != JSLOCAL_NONE)
                     JSLOCAL_NONE) {  
1600                      break;                      break;
                 }  
1601              } else {              } else {
1602                  JS_ASSERT(cg->treeContext.flags & TCF_COMPILE_N_GO);                  JS_ASSERT(cg->flags & TCF_COMPILE_N_GO);
1603                  obj = cg->treeContext.u.scopeChain;                  obj = cg->scopeChain;
1604                  ok = OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &pobj,                  ok = OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &objbox,
1605                                           &prop);                                           &prop);
1606                  if (!ok)                  if (!ok)
1607                      return JS_FALSE;                      return JS_FALSE;
1608                  if (pobj == obj) {                  if (objbox == obj) {
1609                      /*                      /*
1610                       * We're compiling code that will be executed immediately,                       * We're compiling code that will be executed immediately,
1611                       * not re-executed against a different scope chain and/or                       * not re-executed against a different scope chain and/or
# Line 1615  Line 1620 
1620                      }                      }
1621                  }                  }
1622                  if (prop)                  if (prop)
1623                      OBJ_DROP_PROPERTY(cx, pobj, prop);                      OBJ_DROP_PROPERTY(cx, objbox, prop);
1624                  if (!ok)                  if (!ok)
1625                      return JS_FALSE;                      return JS_FALSE;
1626                  if (prop)                  if (prop)
1627                      break;                      break;
1628              }              }
1629          }          }
1630      } while ((cg = cg->parent) != NULL);      } while ((cg = (JSCodeGenerator *) cg->parent) != NULL);
1631      return JS_TRUE;      return JS_TRUE;
1632  }  }
1633    
# Line 1697  Line 1702 
1702              return JS_FALSE;                                                  \              return JS_FALSE;                                                  \
1703      JS_END_MACRO      JS_END_MACRO
1704    
   
1705  static JSBool  static JSBool
1706  EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)  EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
1707  {  {
# Line 1708  Line 1712 
1712          pn->pn_atom == cx->runtime->atomState.lengthAtom) {          pn->pn_atom == cx->runtime->atomState.lengthAtom) {
1713          return js_Emit1(cx, cg, JSOP_LENGTH) >= 0;          return js_Emit1(cx, cg, JSOP_LENGTH) >= 0;
1714      }      }
1715      ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);      ale = cg->atomList.add(cg->compiler, pn->pn_atom);
1716      if (!ale)      if (!ale)
1717          return JS_FALSE;          return JS_FALSE;
1718      return EmitIndexOp(cx, op, ALE_INDEX(ale), cg);      return EmitIndexOp(cx, op, ALE_INDEX(ale), cg);
1719  }  }
1720    
 static uintN  
 IndexParsedObject(JSParsedObjectBox *pob, JSEmittedObjectList *list);  
   
1721  static JSBool  static JSBool
1722  EmitObjectOp(JSContext *cx, JSParsedObjectBox *pob, JSOp op,  EmitObjectOp(JSContext *cx, JSObjectBox *objbox, JSOp op,
1723               JSCodeGenerator *cg)               JSCodeGenerator *cg)
1724  {  {
1725      JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);      JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
1726      return EmitIndexOp(cx, op, IndexParsedObject(pob, &cg->objectList), cg);      return EmitIndexOp(cx, op, cg->objectList.index(objbox), cg);
1727  }  }
1728    
1729  /*  /*
# Line 1737  Line 1738 
1738    
1739  static JSBool  static JSBool
1740  EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index,  EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index,
1741                   JSCodeGenerator *cg)                  JSCodeGenerator *cg)
1742  {  {
1743      JSOp bigSuffix;      JSOp bigSuffix;
1744      ptrdiff_t off;      ptrdiff_t off;
# Line 1764  Line 1765 
1765   * Adjust the slot for a block local to account for the number of variables   * Adjust the slot for a block local to account for the number of variables
1766   * that share the same index space with locals. Due to the incremental code   * that share the same index space with locals. Due to the incremental code
1767   * generation for top-level script, we do the adjustment via code patching in   * generation for top-level script, we do the adjustment via code patching in
1768   * js_CompileScript; see comments there.   * JSCompiler::compileScript; see comments there.
1769   *   *
1770   * The function returns -1 on failures.   * The function returns -1 on failures.
1771   */   */
# Line 1772  Line 1773 
1773  AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot)  AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot)
1774  {  {
1775      JS_ASSERT((jsuint) slot < cg->maxStackDepth);      JS_ASSERT((jsuint) slot < cg->maxStackDepth);
1776      if (cg->treeContext.flags & TCF_IN_FUNCTION) {      if (cg->flags & TCF_IN_FUNCTION) {
1777          slot += cg->treeContext.u.fun->u.i.nvars;          slot += cg->fun->u.i.nvars;
1778          if ((uintN) slot >= SLOTNO_LIMIT) {          if ((uintN) slot >= SLOTNO_LIMIT) {
1779              js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL,              js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL,
1780                                          JSREPORT_ERROR,                                          JSREPORT_ERROR,
# Line 1784  Line 1785 
1785      return slot;      return slot;
1786  }  }
1787    
1788    static bool
1789    EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
1790    {
1791        JS_ASSERT(PN_TYPE(pn) == TOK_LEXICALSCOPE);
1792        if (!EmitObjectOp(cx, pn->pn_objbox, JSOP_ENTERBLOCK, cg))
1793            return false;
1794    
1795        JSObject *blockObj = pn->pn_objbox->object;
1796        jsint depth = AdjustBlockSlot(cx, cg, OBJ_BLOCK_DEPTH(cx, blockObj));
1797        if (depth < 0)
1798            return false;
1799    
1800        for (uintN slot = JSSLOT_FREE(&js_BlockClass),
1801                   limit = slot + OBJ_BLOCK_COUNT(cx, blockObj);
1802             slot < limit; slot++) {
1803            jsval v = STOBJ_GET_SLOT(blockObj, slot);
1804    
1805            /* Beware the empty destructuring dummy. */
1806            if (JSVAL_IS_VOID(v)) {
1807                JS_ASSERT(slot + 1 <= limit);
1808                continue;
1809            }
1810    
1811            JSDefinition *dn = (JSDefinition *) JSVAL_TO_PRIVATE(v);
1812            JS_ASSERT(dn->pn_defn);
1813            JS_ASSERT(uintN(dn->frameSlot() + depth) < JS_BIT(16));
1814            dn->pn_cookie += depth;
1815    #ifdef DEBUG
1816            for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
1817                JS_ASSERT(pnu->pn_lexdef == dn);
1818                JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
1819                JS_ASSERT(pnu->pn_cookie == FREE_UPVAR_COOKIE);
1820            }
1821    #endif
1822        }
1823    
1824        OBJ_SCOPE(blockObj)->freeslot = JSSLOT_FREE(&js_BlockClass);
1825        js_ReallocSlots(cx, blockObj, JSSLOT_FREE(&js_BlockClass), JS_TRUE);
1826        return true;
1827    }
1828    
1829    /*
1830     * When eval is called from a function, the eval code or function code it
1831     * compiles may reference upvars that live in the eval-calling function. The
1832     * eval-invoked compiler does not have explicit definitions for these upvars
1833     * and we do not attempt to create them a-priori (by inspecting the function's
1834     * args and vars) -- we could, but we'd take an avoidable penalty for each
1835     * function local not referenced by any upvar. Instead, we map such upvars
1836     * lazily, growing upvarMap.vector by powers of two.
1837     *
1838     * This function knows that it is called with pn pointing to a PN_NAME-arity
1839     * node, and cg->compiler->callerFrame having a non-null fun member, and the
1840     * static level of cg at least one greater than the eval-calling function's
1841     * static level.
1842     */
1843    static bool
1844    MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg)
1845    {
1846        JSContext *cx = cg->compiler->context;
1847        JSFunction *fun = cg->compiler->callerFrame->fun;
1848        uintN upvarLevel = fun->u.i.script->staticLevel;
1849    
1850        JSFunctionBox *funbox = cg->funbox;
1851        if (funbox) {
1852            /*
1853             * Treat top-level function definitions as escaping (i.e., as funargs),
1854             * required since we compile each such top level function or statement
1855             * and throw away the AST, so we can't yet see all funarg uses of this
1856             * function being compiled (cg->funbox->object). See bug 493177.
1857             */
1858            if (funbox->level == fun->u.i.script->staticLevel + 1U &&
1859                !(((JSFunction *) funbox->object)->flags & JSFUN_LAMBDA)) {
1860                JS_ASSERT_IF(cx->options & JSOPTION_ANONFUNFIX,
1861                             ((JSFunction *) funbox->object)->atom);
1862                return true;
1863            }
1864    
1865            while (funbox->level >= upvarLevel) {
1866                if (funbox->node->pn_dflags & PND_FUNARG)
1867                    return true;
1868                funbox = funbox->parent;
1869                if (!funbox)
1870                    break;
1871            }
1872        }
1873    
1874        JSAtom *atom = pn->pn_atom;
1875    
1876        uintN index;
1877        JSLocalKind localKind = js_LookupLocal(cx, fun, atom, &index);
1878        if (localKind == JSLOCAL_NONE)
1879            return true;
1880    
1881        JS_ASSERT(cg->staticLevel > upvarLevel);
1882        if (cg->staticLevel >= JS_DISPLAY_SIZE || upvarLevel >= JS_DISPLAY_SIZE)
1883            return true;
1884    
1885        JSAtomListElement *ale = cg->upvarList.lookup(atom);
1886        if (!ale) {
1887            if ((cg->flags & TCF_IN_FUNCTION) &&
1888                !js_AddLocal(cx, cg->fun, atom, JSLOCAL_UPVAR)) {
1889                return false;
1890            }
1891    
1892            ale = cg->upvarList.add(cg->compiler, atom);
1893            if (!ale)
1894                return false;
1895            JS_ASSERT(ALE_INDEX(ale) == cg->upvarList.count - 1);
1896    
1897            uint32 *vector = cg->upvarMap.vector;
1898            uint32 length = cg->upvarMap.length;
1899    
1900            JS_ASSERT(ALE_INDEX(ale) <= length);
1901            if (ALE_INDEX(ale) == length) {
1902                length = 2 * JS_MAX(2, length);
1903                vector = (uint32 *) JS_realloc(cx, vector, length * sizeof *vector);
1904                if (!vector)
1905                    return false;
1906                cg->upvarMap.vector = vector;
1907                cg->upvarMap.length = length;
1908            }
1909    
1910            if (localKind != JSLOCAL_ARG)
1911                index += fun->nargs;
1912            JS_ASSERT(index < JS_BIT(16));
1913    
1914            uintN skip = cg->staticLevel - upvarLevel;
1915            vector[ALE_INDEX(ale)] = MAKE_UPVAR_COOKIE(skip, index);
1916        }
1917    
1918        pn->pn_op = JSOP_GETUPVAR;
1919        pn->pn_cookie = MAKE_UPVAR_COOKIE(cg->staticLevel, ALE_INDEX(ale));
1920        pn->pn_dflags |= PND_BOUND;
1921        return true;
1922    }
1923    
1924  /*  /*
1925   * This routine tries to optimize name gets and sets to stack slot loads and   * BindNameToSlot attempts to optimize name gets and sets to stack slot loads
1926   * stores, given the variables object and scope chain in cx's top frame, the   * and stores, given the compile-time information in cg and a TOK_NAME node pn.
1927   * compile-time context in tc, and a TOK_NAME node pn.  It returns false on   * It returns false on error, true on success.
  * error, true on success.  
1928   *   *
1929   * The caller can inspect pn->pn_slot for a non-negative slot number to tell   * The caller can inspect pn->pn_cookie for FREE_UPVAR_COOKIE to tell whether
1930   * whether optimization occurred, in which case BindNameToSlot also updated   * optimization occurred, in which case BindNameToSlot also updated pn->pn_op.
1931   * pn->pn_op.  If pn->pn_slot is still -1 on return, pn->pn_op nevertheless   * If pn->pn_cookie is still FREE_UPVAR_COOKIE on return, pn->pn_op still may
1932   * may have been optimized, e.g., from JSOP_NAME to JSOP_ARGUMENTS.  Whether   * have been optimized, e.g., from JSOP_NAME to JSOP_CALLEE.  Whether or not
1933   * or not pn->pn_op was modified, if this function finds an argument or local   * pn->pn_op was modified, if this function finds an argument or local variable
1934   * variable name, pn->pn_const will be true for const properties after a   * name, PND_CONST will be set in pn_dflags for read-only properties after a
1935   * successful return.   * successful return.
1936   *   *
1937   * NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget   * NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget
# Line 1805  Line 1941 
1941  static JSBool  static JSBool
1942  BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)  BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
1943  {  {
1944      JSTreeContext *tc;      JSDefinition *dn;
     JSAtom *atom;  
     JSStmtInfo *stmt;  
     jsint slot;  
1945      JSOp op;      JSOp op;
1946      JSLocalKind localKind;      JSAtom *atom;
1947      uintN index;      uint32 cookie;
1948        JSDefinition::Kind dn_kind;
1949      JSAtomListElement *ale;      JSAtomListElement *ale;
1950      JSBool constOp;      uintN index;
1951    
1952      JS_ASSERT(pn->pn_type == TOK_NAME);      JS_ASSERT(pn->pn_type == TOK_NAME);
     if (pn->pn_slot >= 0 || pn->pn_op == JSOP_ARGUMENTS)  
         return JS_TRUE;  
1953    
1954      /* QNAME references can never be optimized to use arg/var storage. */      /* Idempotency tests come first, since we may be called more than once. */
1955      if (pn->pn_op == JSOP_QNAMEPART)      if (pn->pn_dflags & PND_BOUND)
1956          return JS_TRUE;          return JS_TRUE;
1957    
1958        /* No cookie initialized for these two, they're pre-bound by definition. */
1959        JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE);
1960    
1961      /*      /*
1962       * We can't optimize if we are compiling a with statement and its body,       * The parser linked all uses (including forward references) to their
1963       * or we're in a catch block whose exception variable has the same name       * definitions, unless a with statement or direct eval intervened.
      * as this node.  FIXME: we should be able to optimize catch vars to be  
      * block-locals.  
1964       */       */
1965      tc = &cg->treeContext;      if (pn->pn_used) {
1966      atom = pn->pn_atom;          JS_ASSERT(pn->pn_cookie == FREE_UPVAR_COOKIE);
1967      stmt = js_LexicalLookup(tc, atom, &slot);          dn = pn->pn_lexdef;
1968      if (stmt) {          JS_ASSERT(dn->pn_defn);
1969          if (stmt->type == STMT_WITH)          pn->pn_dflags |= (dn->pn_dflags & PND_CONST);
1970        } else {
1971            if (!pn->pn_defn)
1972              return JS_TRUE;              return JS_TRUE;
1973            dn = (JSDefinition *) pn;
1974        }
1975    
1976          JS_ASSERT(stmt->flags & SIF_SCOPE);      op = PN_OP(pn);
1977          JS_ASSERT(slot >= 0);      if (op == JSOP_NOP)
         op = PN_OP(pn);  
         switch (op) {  
           case JSOP_NAME:     op = JSOP_GETLOCAL; break;  
           case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;  
           case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;  
           case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;  
           case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;  
           case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;  
           case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;  
           case JSOP_DELNAME:  op = JSOP_FALSE; break;  
           default: JS_ASSERT(0);  
         }  
         if (op != pn->pn_op) {  
             slot = AdjustBlockSlot(cx, cg, slot);  
             if (slot < 0)  
                 return JS_FALSE;  
             pn->pn_op = op;  
             pn->pn_slot = slot;  
         }  
1978          return JS_TRUE;          return JS_TRUE;
1979      }  
1980        JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
1981        atom = pn->pn_atom;
1982        cookie = dn->pn_cookie;
1983        dn_kind = dn->kind();
1984    
1985      /*      /*
1986       * We can't optimize if var and closure (a local function not in a larger       * Turn attempts to mutate const-declared bindings into get ops (for
1987       * expression and not at top-level within another's body) collide.       * pre-increment and pre-decrement ops, our caller will have to emit
1988       * XXX suboptimal: keep track of colliding names and deoptimize only those       * JSOP_POS, JSOP_ONE, and JSOP_ADD as well).
1989         *
1990         * Turn JSOP_DELNAME into JSOP_FALSE if dn is known, as all declared
1991         * bindings visible to the compiler are permanent in JS unless the
1992         * declaration originates in eval code. We detect eval code by testing
1993         * cg->compiler->callerFrame, which is set only by eval or a debugger
1994         * equivalent.
1995         *
1996         * Note that this callerFrame non-null test must be qualified by testing
1997         * !cg->funbox to exclude function code nested in eval code, which is not
1998         * subject to the deletable binding exception.
1999       */       */
2000      if (tc->flags & TCF_FUN_CLOSURE_VS_VAR)      switch (op) {
2001          return JS_TRUE;        case JSOP_NAME:
2002          case JSOP_SETCONST:
2003      if (!(tc->flags & TCF_IN_FUNCTION)) {          break;
2004          JSStackFrame *caller;        case JSOP_DELNAME:
2005            if (dn_kind != JSDefinition::UNKNOWN) {
2006                if (cg->compiler->callerFrame && !cg->funbox)
2007                    JS_ASSERT(cg->flags & TCF_COMPILE_N_GO);
2008                else
2009                    pn->pn_op = JSOP_FALSE;
2010                pn->pn_dflags |= PND_BOUND;
2011                return JS_TRUE;
2012            }
2013            break;
2014          default:
2015            if (pn->isConst())
2016                pn->pn_op = op = JSOP_NAME;
2017        }
2018    
2019          caller = tc->parseContext->callerFrame;      if (cookie == FREE_UPVAR_COOKIE) {
2020            JSStackFrame *caller = cg->compiler->callerFrame;
2021          if (caller) {          if (caller) {
2022              JS_ASSERT(tc->flags & TCF_COMPILE_N_GO);              JS_ASSERT(cg->flags & TCF_COMPILE_N_GO);
2023    
2024                /*
2025                 * Don't generate upvars on the left side of a for loop. See
2026                 * bug 470758.
2027                 */
2028                if (cg->flags & TCF_IN_FOR_INIT)
2029                    return JS_TRUE;
2030    
2031              JS_ASSERT(caller->script);              JS_ASSERT(caller->script);
2032              if (!caller->fun || caller->varobj != tc->u.scopeChain)              if (!caller->fun)
2033                    return JS_TRUE;
2034    
2035                /*
2036                 * Make sure the variable object used by the compiler to initialize
2037                 * parent links matches the caller's varobj. Compile-n-go compiler-
2038                 * created function objects have the top-level cg's scopeChain set
2039                 * as their parent by JSCompiler::newFunction.
2040                 */
2041                JSObject *scopeobj = (cg->flags & TCF_IN_FUNCTION)
2042                                     ? STOBJ_GET_PARENT(FUN_OBJECT(cg->fun))
2043                                     : cg->scopeChain;
2044                if (scopeobj != caller->varobj)
2045                  return JS_TRUE;                  return JS_TRUE;
2046    
2047              /*              /*
2048               * We are compiling eval or debug script inside a function frame               * We are compiling eval or debug script inside a function frame
2049               * and the scope chain matches function's variable object.               * and the scope chain matches the function's variable object.
2050               * Optimize access to function's arguments and variable and the               * Optimize access to function's arguments and variable and the
2051               * arguments object.               * arguments object.
2052               */               */
2053              if (PN_OP(pn) != JSOP_NAME || cg->staticDepth > JS_DISPLAY_SIZE)              if (op != JSOP_NAME)
2054                  goto arguments_check;                  return JS_TRUE;
             localKind = js_LookupLocal(cx, caller->fun, atom, &index);  
             if (localKind == JSLOCAL_NONE)  
                 goto arguments_check;  
   
             ATOM_LIST_SEARCH(ale, &cg->upvarList, atom);  
             if (!ale) {  
                 uint32 cookie, length, *vector;  
   
                 ale = js_IndexAtom(cx, atom, &cg->upvarList);  
                 if (!ale)  
                     return JS_FALSE;  
                 JS_ASSERT(ALE_INDEX(ale) == cg->upvarList.count - 1);  
   
                 length = cg->upvarMap.length;  
                 JS_ASSERT(ALE_INDEX(ale) <= length);  
                 if (ALE_INDEX(ale) == length) {  
                     length = 2 * JS_MAX(2, length);  
                     vector = (uint32 *)  
                              JS_realloc(cx, cg->upvarMap.vector,  
                                         length * sizeof *vector);  
                     if (!vector)  
                         return JS_FALSE;  
                     cg->upvarMap.vector = vector;  
                     cg->upvarMap.length = length;  
                 }  
   
                 if (localKind != JSLOCAL_ARG)  
                     index += caller->fun->nargs;  
                 if (index >= JS_BIT(16)) {  
                     cg->treeContext.flags |= TCF_FUN_USES_NONLOCALS;  
                     return JS_TRUE;  
                 }  
   
                 cookie = MAKE_UPVAR_COOKIE(1, index);  
                 cg->upvarMap.vector[ALE_INDEX(ale)] = cookie;  
             }  
2055    
2056              pn->pn_op = JSOP_GETUPVAR;              return MakeUpvarForEval(pn, cg);
             pn->pn_slot = ALE_INDEX(ale);  
             return JS_TRUE;  
2057          }          }
2058            return JS_TRUE;
2059        }
2060    
2061        if (dn->pn_dflags & PND_GVAR) {
2062          /*          /*
2063           * We are optimizing global variables and there may be no pre-existing           * If this is a global reference from within a function, leave pn_op as
2064           * global property named atom.  If atom was declared via const or var,           * JSOP_NAME, etc. We could emit JSOP_*GVAR ops within function code if
2065           * optimize pn to access fp->vars using the appropriate JSOP_*GVAR op.           * only we could depend on the global frame's slots being valid for all
2066             * calls to the function.
2067           */           */
2068          ATOM_LIST_SEARCH(ale, &tc->decls, atom);          if (cg->flags & TCF_IN_FUNCTION)
         if (!ale) {  
             /* Use precedes declaration, or name is never declared. */  
2069              return JS_TRUE;              return JS_TRUE;
         }  
         constOp = (ALE_JSOP(ale) == JSOP_DEFCONST);  
2070    
2071          /* Index atom so we can map fast global number to name. */          /*
2072          ale = js_IndexAtom(cx, atom, &cg->atomList);           * We are optimizing global variables and there may be no pre-existing
2073          if (!ale)           * global property named atom when this global script runs. If atom was
2074              return JS_FALSE;           * declared via const or var, optimize pn to access fp->vars using the
2075             * appropriate JSOP_*GVAR op.
2076          /* Defend against tc->ngvars 16-bit overflow. */           *
2077          slot = ALE_INDEX(ale);           * FIXME: should be able to optimize global function access too.
2078          if ((slot + 1) >> 16)           */
2079              return JS_TRUE;          JS_ASSERT(dn_kind == JSDefinition::VAR || dn_kind == JSDefinition::CONST);
   
         if ((uint16)(slot + 1) > tc->ngvars)  
             tc->ngvars = (uint16)(slot + 1);  
2080    
         op = PN_OP(pn);  
2081          switch (op) {          switch (op) {
2082            case JSOP_NAME:     op = JSOP_GETGVAR; break;            case JSOP_NAME:     op = JSOP_GETGVAR; break;
2083            case JSOP_SETNAME:  op = JSOP_SETGVAR; break;            case JSOP_SETNAME:  op = JSOP_SETGVAR; break;
# Line 1966  Line 2090 
2090            case JSOP_DELNAME:  /* NB: no change */ break;            case JSOP_DELNAME:  /* NB: no change */ break;
2091            default: JS_NOT_REACHED("gvar");            default: JS_NOT_REACHED("gvar");
2092          }          }
2093          pn->pn_const = constOp;          pn->pn_op = op;
2094          if (op != pn->pn_op) {          pn->pn_cookie = cookie;
2095              pn->pn_op = op;          pn->pn_dflags |= PND_BOUND;
             pn->pn_slot = slot;  
         }  
2096          return JS_TRUE;          return JS_TRUE;
2097      }      }
2098    
2099      if (tc->flags & TCF_IN_FUNCTION) {      uintN level = UPVAR_FRAME_SKIP(cookie);
2100        JS_ASSERT(cg->staticLevel >= level);
2101    
2102        /*
2103         * A JSDefinition witnessed as a declaration by the parser cannot be an
2104         * upvar, unless it is the degenerate kind of upvar selected above (in the
2105         * code before the PND_GVAR test) for the special case of compile-and-go
2106         * code generated from eval called from a function, where the eval code
2107         * uses local vars defined in the function. We detect this upvar-for-eval
2108         * case by checking dn's op.
2109         */
2110        if (PN_OP(dn) == JSOP_GETUPVAR) {
2111            JS_ASSERT(cg->staticLevel >= level);
2112            if (op != JSOP_NAME)
2113                return JS_TRUE;
2114    
2115    #ifdef DEBUG
2116            JSStackFrame *caller = cg->compiler->callerFrame;
2117            JS_ASSERT(caller);
2118    
2119            JSTreeContext *tc = cg;
2120            while (tc->staticLevel != level)
2121                tc = tc->parent;
2122            JS_ASSERT(tc->flags & TCF_COMPILING);
2123    
2124            JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
2125            JS_ASSERT(evalcg->flags & TCF_COMPILE_N_GO);
2126            JS_ASSERT(!(evalcg->flags & TCF_IN_FOR_INIT));
2127            JS_ASSERT(caller->script);
2128            JS_ASSERT(caller->fun && caller->varobj == evalcg->scopeChain);
2129    #endif
2130    
2131            if (cg->staticLevel == level) {
2132                pn->pn_op = JSOP_GETUPVAR;
2133                pn->pn_cookie = cookie;
2134                pn->pn_dflags |= PND_BOUND;
2135                return JS_TRUE;
2136            }
2137    
2138            return MakeUpvarForEval(pn, cg);
2139        }
2140    
2141        uintN skip = cg->staticLevel - level;
2142        if (skip != 0) {
2143            JS_ASSERT(cg->flags & TCF_IN_FUNCTION);
2144            JS_ASSERT(cg->lexdeps.lookup(atom));
2145            JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
2146            JS_ASSERT(cg->fun->u.i.skipmin <= skip);
2147    
2148          /*          /*
2149           * We are compiling a function body and may be able to optimize name           * If op is a mutating opcode, this upvar's static level is too big to
2150           * to stack slot. Look for an argument or variable in the function and           * index into the display, or the function is heavyweight, we fall back
2151           * rewrite pn_op and update pn accordingly.           * on JSOP_*NAME*.
2152           */           */
2153          localKind = js_LookupLocal(cx, tc->u.fun, atom, &index);          if (op != JSOP_NAME)
2154          if (localKind != JSLOCAL_NONE) {              return JS_TRUE;
2155              op = PN_OP(pn);          if (level >= JS_DISPLAY_SIZE)
2156              if (localKind == JSLOCAL_ARG) {              return JS_TRUE;
2157                  switch (op) {          if (cg->flags & TCF_FUN_HEAVYWEIGHT)
2158                    case JSOP_NAME:     op = JSOP_GETARG; break;              return JS_TRUE;
2159                    case JSOP_SETNAME:  op = JSOP_SETARG; break;  
2160                    case JSOP_INCNAME:  op = JSOP_INCARG; break;          if (FUN_FLAT_CLOSURE(cg->fun)) {
2161                    case JSOP_NAMEINC:  op = JSOP_ARGINC; break;              op = JSOP_GETDSLOT;
2162                    case JSOP_DECNAME:  op = JSOP_DECARG; break;          } else {
2163                    case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;              /*
2164                    case JSOP_FORNAME:  op = JSOP_FORARG; break;               * The function we're compiling may not be heavyweight, but if it
2165                    case JSOP_DELNAME:  op = JSOP_FALSE; break;               * escapes as a funarg, we can't use JSOP_GETUPVAR/JSOP_CALLUPVAR.
2166                    default: JS_NOT_REACHED("arg");               * JSCompiler::analyzeFunctions has arranged for this function's
2167                  }               * enclosing functions to be heavyweight, so we can safely stick
2168                  pn->pn_const = JS_FALSE;               * with JSOP_NAME/JSOP_CALLNAME.
2169              } else {               */
2170                  JS_ASSERT(localKind == JSLOCAL_VAR ||              if (cg->funbox->node->pn_dflags & PND_FUNARG)
2171                            localKind == JSLOCAL_CONST);                  return JS_TRUE;
2172                  switch (op) {  
2173                    case JSOP_NAME:     op = JSOP_GETLOCAL; break;              /*
2174                    case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;               * Generator functions may be resumed from any call stack, which
2175                    case JSOP_SETCONST: op = JSOP_SETLOCAL; break;               * defeats the display optimization to static link searching used
2176                    case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;               * by JSOP_{GET,CALL}UPVAR.
2177                    case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;               */
2178                    case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;              if (cg->flags & TCF_FUN_IS_GENERATOR)
2179                    case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;                  return JS_TRUE;
2180                    case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;  
2181                    case JSOP_DELNAME:  op = JSOP_FALSE; break;              op = JSOP_GETUPVAR;
2182                    default: JS_NOT_REACHED("local");          }
2183    
2184            ale = cg->upvarList.lookup(atom);
2185            if (ale) {
2186                index = ALE_INDEX(ale);
2187            } else {
2188                if (!js_AddLocal(cx, cg->fun, atom, JSLOCAL_UPVAR))
2189                    return JS_FALSE;
2190    
2191                ale = cg->upvarList.add(cg->compiler, atom);
2192                if (!ale)
2193                    return JS_FALSE;
2194                index = ALE_INDEX(ale);
2195                JS_ASSERT(index == cg->upvarList.count - 1);
2196    
2197                uint32 *vector = cg->upvarMap.vector;
2198                if (!vector) {
2199                    uint32 length = cg->lexdeps.count;
2200    
2201                    vector = (uint32 *) calloc(length, sizeof *vector);
2202                    if (!vector) {
2203                        JS_ReportOutOfMemory(cx);
2204                        return JS_FALSE;
2205                  }                  }
2206                  pn->pn_const = (localKind == JSLOCAL_CONST);                  cg->upvarMap.vector = vector;
2207                    cg->upvarMap.length = length;
2208              }              }
2209              pn->pn_op = op;  
2210              pn->pn_slot = index;              uintN slot = UPVAR_FRAME_SLOT(cookie);
2211              return JS_TRUE;              if (dn_kind != JSDefinition::ARG) {
2212                    JSTreeContext *tc = cg;
2213                    do {
2214                        tc = tc->parent;
2215                    } while (tc->staticLevel != level);
2216                    if (tc->flags & TCF_IN_FUNCTION)
2217                        slot += tc->fun->nargs;
2218                }
2219    
2220                vector[index] = MAKE_UPVAR_COOKIE(skip, slot);
2221          }          }
2222          tc->flags |= TCF_FUN_USES_NONLOCALS;  
2223            pn->pn_op = op;
2224            pn->pn_cookie = index;
2225            pn->pn_dflags |= PND_BOUND;
2226            return JS_TRUE;
2227      }      }
2228    
   arguments_check:  
2229      /*      /*
2230       * Here we either compiling a function body or an eval or debug script       * We are compiling a function body and may be able to optimize name
2231       * inside a function and couldn't optimize pn, so it's not a global or       * to stack slot. Look for an argument or variable in the function and
2232       * local slot name. We are also outside of any with blocks. Check if we       * rewrite pn_op and update pn accordingly.
      * can optimize the predefined arguments variable.  
2233       */       */
2234      JS_ASSERT((tc->flags & TCF_IN_FUNCTION) ||      switch (dn_kind) {
2235                (tc->parseContext->callerFrame &&        case JSDefinition::UNKNOWN:
                tc->parseContext->callerFrame->fun &&  
                tc->parseContext->callerFrame->varobj == tc->u.scopeChain));  
     if (pn->pn_op == JSOP_NAME &&  
         atom == cx->runtime->atomState.argumentsAtom) {  
         pn->pn_op = JSOP_ARGUMENTS;  
2236          return JS_TRUE;          return JS_TRUE;
2237    
2238          case JSDefinition::LET:
2239            switch (op) {
2240              case JSOP_NAME:     op = JSOP_GETLOCAL; break;
2241              case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
2242              case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
2243              case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
2244              case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
2245              case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
2246              case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;
2247              default: JS_NOT_REACHED("let");
2248            }
2249            break;
2250    
2251          case JSDefinition::ARG:
2252            switch (op) {
2253              case JSOP_NAME:     op = JSOP_GETARG; break;
2254              case JSOP_SETNAME:  op = JSOP_SETARG; break;
2255              case JSOP_INCNAME:  op = JSOP_INCARG; break;
2256              case JSOP_NAMEINC:  op = JSOP_ARGINC; break;
2257              case JSOP_DECNAME:  op = JSOP_DECARG; break;
2258              case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;
2259              case JSOP_FORNAME:  op = JSOP_FORARG; break;
2260              default: JS_NOT_REACHED("arg");
2261            }
2262            JS_ASSERT(!pn->isConst());
2263            break;
2264    
2265          case JSDefinition::VAR:
2266            if (PN_OP(dn) == JSOP_CALLEE) {
2267                JS_ASSERT(op != JSOP_CALLEE);
2268                JS_ASSERT((cg->fun->flags & JSFUN_LAMBDA) && atom == cg->fun->atom);
2269    
2270                switch (op) {
2271                  default:
2272                    /*
2273                     * Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight, as
2274                     * we cannot be sure cg->fun is not something of the form:
2275                     *
2276                     *   var ff = (function f(s) { eval(s); return f; });
2277                     *
2278                     * where a caller invokes ff("var f = 42"). The result returned
2279                     * for such an invocation must be 42, since the callee name is
2280                     * lexically bound in an outer declarative environment from the
2281                     * function's activation. See jsfun.cpp:call_resolve.
2282                     */
2283                    JS_ASSERT(op != JSOP_DELNAME);
2284                    if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) {
2285                        op = JSOP_CALLEE;
2286                        pn->pn_dflags |= PND_CONST;
2287                    }
2288                    break;
2289                }
2290                pn->pn_op = op;
2291                pn->pn_dflags |= PND_BOUND;
2292                return JS_TRUE;
2293            }
2294            /* FALL THROUGH */
2295    
2296          default:
2297            JS_ASSERT_IF(dn_kind != JSDefinition::FUNCTION,
2298                         dn_kind == JSDefinition::VAR ||
2299                         dn_kind == JSDefinition::CONST);
2300            switch (op) {
2301              case JSOP_NAME:     op = JSOP_GETLOCAL; break;
2302              case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
2303              case JSOP_SETCONST: op = JSOP_SETLOCAL; break;
2304              case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
2305              case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
2306              case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
2307              case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
2308              case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;
2309              default: JS_NOT_REACHED("local");
2310            }
2311            JS_ASSERT_IF(dn_kind == JSDefinition::CONST, pn->pn_dflags & PND_CONST);
2312            break;
2313      }      }
2314    
2315        JS_ASSERT(op != PN_OP(pn));
2316        pn->pn_op = op;
2317        pn->pn_cookie = UPVAR_FRAME_SLOT(cookie);
2318        pn->pn_dflags |= PND_BOUND;
2319      return JS_TRUE;      return JS_TRUE;
2320  }  }
2321    
# Line 2056  Line 2336 
2336                   JSBool *answer)                   JSBool *answer)
2337  {  {
2338      JSBool ok;      JSBool ok;
     JSFunction *fun;  
2339      JSParseNode *pn2;      JSParseNode *pn2;
2340    
2341      ok = JS_TRUE;      ok = JS_TRUE;
# Line 2066  Line 2345 
2345      switch (pn->pn_arity) {      switch (pn->pn_arity) {
2346        case PN_FUNC:        case PN_FUNC:
2347          /*          /*
2348           * A named function is presumed useful: we can't yet know that it is           * A named function, contrary to ES3, is no longer useful, because we
2349           * not called.  The side effects are the creation of a scope object           * bind its name lexically (using JSOP_CALLEE) instead of creating an
2350           * to parent this function object, and the binding of the function's           * Object instance and binding a readonly, permanent property in it
2351           * name in that scope object.  See comments at case JSOP_NAMEDFUNOBJ:           * (the object and binding can be detected and hijacked or captured).
2352           * in jsinterp.c.           * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
2353           */           */
2354          fun = (JSFunction *) pn->pn_funpob->object;          *answer = JS_FALSE;
         if (fun->atom)  
             *answer = JS_TRUE;  
2355          break;          break;
2356    
2357        case PN_LIST:        case PN_LIST:
2358          if (pn->pn_type == TOK_NEW ||          if (pn->pn_op == JSOP_NOP ||
2359              pn->pn_type == TOK_LP ||              pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
2360              pn->pn_type == TOK_LB ||              pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
2361              pn->pn_type == TOK_RB ||              /*
2362              pn->pn_type == TOK_RC) {               * Non-operators along with ||, &&, ===, and !== never invoke
2363                 * toString or valueOf.
2364                 */
2365                for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
2366                    ok &= CheckSideEffects(cx, cg, pn2, answer);
2367            } else {
2368              /*              /*
2369               * All invocation operations (construct: TOK_NEW, call: TOK_LP)               * All invocation operations (construct: TOK_NEW, call: TOK_LP)
2370               * are presumed to be useful, because they may have side effects               * are presumed to be useful, because they may have side effects
# Line 2094  Line 2376 
2376               * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,               * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,
2377               * does not apply here: arguments[i][j] might invoke a getter).               * does not apply here: arguments[i][j] might invoke a getter).
2378               *               *
2379               * Array and object initializers (TOK_RB and TOK_RC lists) must be               * Likewise, array and object initialisers may call prototype
2380               * considered useful, because they are sugar for constructor calls               * setters (the __defineSetter__ built-in, and writable __proto__
2381               * (to Array and Object, respectively).               * on Array.prototype create this hazard). Initialiser list nodes
2382                 * have JSOP_NEWINIT in their pn_op.
2383               */               */
2384              *answer = JS_TRUE;              *answer = JS_TRUE;
         } else {  
             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)  
                 ok &= CheckSideEffects(cx, cg, pn2, answer);  
2385          }          }
2386          break;          break;
2387    
# Line 2130  Line 2410 
2410                      return JS_FALSE;                      return JS_FALSE;
2411                  if (!CheckSideEffects(cx, cg, pn->pn_right, answer))                  if (!CheckSideEffects(cx, cg, pn->pn_right, answer))
2412                      return JS_FALSE;                      return JS_FALSE;
2413                  if (!*answer &&                  if (!*answer && (pn->pn_op != JSOP_NOP || !pn2->isConst()))
                     (pn->pn_op != JSOP_NOP ||  
                      pn2->pn_slot < 0 ||  
                      !pn2->pn_const)) {  
2414                      *answer = JS_TRUE;                      *answer = JS_TRUE;
                 }  
2415              }              }
2416          } else {          } else {
2417              /*              if (pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
2418               * We can't easily prove that neither operand ever denotes an                  pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
2419               * object with a toString or valueOf method.                  /*
2420               */                   * ||, &&, ===, and !== do not convert their operands via
2421              *answer = JS_TRUE;                   * toString or valueOf method calls.
2422                     */
2423                    ok = CheckSideEffects(cx, cg, pn->pn_left, answer) &&
2424                         CheckSideEffects(cx, cg, pn->pn_right, answer);
2425                } else {
2426                    /*
2427                     * We can't easily prove that neither operand ever denotes an
2428                     * object with a toString or valueOf method.
2429                     */
2430                    *answer = JS_TRUE;
2431                }
2432          }          }
2433          break;          break;
2434    
# Line 2156  Line 2442 
2442              pn2 = pn->pn_kid;              pn2 = pn->pn_kid;
2443              switch (pn2->pn_type) {              switch (pn2->pn_type) {
2444                case TOK_NAME:                case TOK_NAME:
2445                    if (!BindNameToSlot(cx, cg, pn2))
2446                        return JS_FALSE;
2447                    if (pn2->isConst()) {
2448                        *answer = JS_FALSE;
2449                        break;
2450                    }
2451                    /* FALL THROUGH */
2452                case TOK_DOT:                case TOK_DOT:
2453  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
2454                case TOK_DBLDOT:                case TOK_DBLDOT:
# Line 2173  Line 2466 
2466              }              }
2467              break;              break;
2468    
2469              case TOK_UNARYOP:
2470                if (pn->pn_op == JSOP_NOT) {
2471                    /* ! does not convert its operand via toString or valueOf. */
2472                    ok = CheckSideEffects(cx, cg, pn->pn_kid, answer);
2473                    break;
2474                }
2475                /* FALL THROUGH */
2476    
2477            default:            default:
2478              /*              /*
2479               * All of TOK_INC, TOK_DEC, TOK_THROW, TOK_YIELD, and TOK_DEFSHARP               * All of TOK_INC, TOK_DEC, TOK_THROW, TOK_YIELD, and TOK_DEFSHARP
# Line 2194  Line 2495 
2495          if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) {          if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) {
2496              if (!BindNameToSlot(cx, cg, pn))              if (!BindNameToSlot(cx, cg, pn))
2497                  return JS_FALSE;                  return JS_FALSE;
2498              if (pn->pn_slot < 0 && pn->pn_op != JSOP_ARGUMENTS) {              if (pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE &&
2499                    pn->pn_cookie == FREE_UPVAR_COOKIE) {
2500                  /*                  /*
2501                   * Not an argument or local variable use, so this expression                   * Not an argument or local variable use, and not a use of a
2502                   * could invoke a getter that has side effects.                   * unshadowed named function expression's given name, so this
2503                     * expression could invoke a getter that has side effects.
2504                   */                   */
2505                  *answer = JS_TRUE;                  *answer = JS_TRUE;
2506              }              }
2507          }          }
2508          pn2 = pn->pn_expr;          pn2 = pn->maybeExpr();
2509          if (pn->pn_type == TOK_DOT) {          if (pn->pn_type == TOK_DOT) {
2510              if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2))              if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2))
2511                  return JS_FALSE;                  return JS_FALSE;
# Line 2218  Line 2521 
2521          ok = CheckSideEffects(cx, cg, pn2, answer);          ok = CheckSideEffects(cx, cg, pn2, answer);
2522          break;          break;
2523    
2524          case PN_NAMESET:
2525            ok = CheckSideEffects(cx, cg, pn->pn_tree, answer);
2526            break;
2527    
2528        case PN_NULLARY:        case PN_NULLARY:
2529          if (pn->pn_type == TOK_DEBUGGER)          if (pn->pn_type == TOK_DEBUGGER)
2530              *answer = JS_TRUE;              *answer = JS_TRUE;
# Line 2253  Line 2560 
2560            case JSOP_GETUPVAR:            case JSOP_GETUPVAR:
2561              op = JSOP_CALLUPVAR;              op = JSOP_CALLUPVAR;
2562              break;              break;
2563              case JSOP_GETDSLOT:
2564                op = JSOP_CALLDSLOT;
2565                break;
2566            default:            default:
2567              JS_ASSERT(op == JSOP_ARGUMENTS);              JS_ASSERT(op == JSOP_ARGUMENTS || op == JSOP_CALLEE);
2568              break;              break;
2569          }          }
2570      }      }
2571    
2572      if (op == JSOP_ARGUMENTS) {      if (op == JSOP_ARGUMENTS || op == JSOP_CALLEE) {
2573          if (js_Emit1(cx, cg, op) < 0)          if (js_Emit1(cx, cg, op) < 0)
2574              return JS_FALSE;              return JS_FALSE;
2575          if (callContext && js_Emit1(cx, cg, JSOP_NULL) < 0)          if (callContext && js_Emit1(cx, cg, JSOP_NULL) < 0)
2576              return JS_FALSE;              return JS_FALSE;
2577      } else {      } else {
2578          if (pn->pn_slot >= 0) {          if (pn->pn_cookie != FREE_UPVAR_COOKIE) {
2579              EMIT_UINT16_IMM_OP(op, pn->pn_slot);              EMIT_UINT16_IMM_OP(op, pn->pn_cookie);
2580          } else {          } else {
2581              if (!EmitAtomOp(cx, pn, op, cg))              if (!EmitAtomOp(cx, pn, op, cg))
2582                  return JS_FALSE;                  return JS_FALSE;
# Line 2288  Line 2598 
2598      JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME);      JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME);
2599    
2600      pn2 = pn->pn_kid;      pn2 = pn->pn_kid;
2601      oldflags = cg->treeContext.flags;      oldflags = cg->flags;
2602      cg->treeContext.flags &= ~TCF_IN_FOR_INIT;      cg->flags &= ~TCF_IN_FOR_INIT;
2603      if (!js_EmitTree(cx, cg, pn2))      if (!js_EmitTree(cx, cg, pn2))
2604          return JS_FALSE;          return JS_FALSE;
2605      cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;      cg->flags |= oldflags & TCF_IN_FOR_INIT;
2606      if (js_NewSrcNote2(cx, cg, SRC_PCBASE,      if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
2607                         CG_OFFSET(cg) - pn2->pn_offset) < 0) {                         CG_OFFSET(cg) - pn2->pn_offset) < 0) {
2608          return JS_FALSE;          return JS_FALSE;
# Line 2303  Line 2613 
2613  #endif  #endif
2614    
2615  static JSBool  static JSBool
2616    EmitSpecialPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
2617    {
2618        /*
2619         * Special case for obj.__proto__, obj.__parent__, obj.__count__ to
2620         * deoptimize away from fast paths in the interpreter and trace recorder,
2621         * which skip dense array instances by going up to Array.prototype before
2622         * looking up the property name.
2623         */
2624        JSAtomListElement *ale = cg->atomList.add(cg->compiler, pn->pn_atom);
2625        if (!ale)
2626            return JS_FALSE;
2627        if (!EmitIndexOp(cx, JSOP_QNAMEPART, ALE_INDEX(ale), cg))
2628            return JS_FALSE;
2629        if (js_Emit1(cx, cg, op) < 0)
2630            return JS_FALSE;
2631        return JS_TRUE;
2632    }
2633    
2634    static JSBool
2635  EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,  EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
2636             JSBool callContext)             JSBool callContext)
2637  {  {
2638      JSParseNode *pn2, *pndot, *pnup, *pndown;      JSParseNode *pn2, *pndot, *pnup, *pndown;
2639      ptrdiff_t top;      ptrdiff_t top;
2640    
2641      pn2 = pn->pn_expr;      JS_ASSERT(pn->pn_arity == PN_NAME);
2642        pn2 = pn->maybeExpr();
2643    
2644        /* Special case deoptimization on __proto__, __count__ and __parent__. */
2645        if ((op == JSOP_GETPROP || op == JSOP_CALLPROP) &&
2646            (pn->pn_atom == cx->runtime->atomState.protoAtom ||
2647             pn->pn_atom == cx->runtime->atomState.parentAtom ||
2648             pn->pn_atom == cx->runtime->atomState.countAtom)) {
2649            if (pn2 && !js_EmitTree(cx, cg, pn2))
2650                return JS_FALSE;
2651            return EmitSpecialPropOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, cg);
2652        }
2653    
2654      if (callContext) {      if (callContext) {
2655          JS_ASSERT(pn->pn_type == TOK_DOT);          JS_ASSERT(pn->pn_type == TOK_DOT);
2656          JS_ASSERT(op == JSOP_GETPROP);          JS_ASSERT(op == JSOP_GETPROP);
# Line 2344  Line 2685 
2685                    do_indexconst: {                    do_indexconst: {
2686                          JSAtomListElement *ale;                          JSAtomListElement *ale;
2687                          jsatomid atomIndex;                          jsatomid atomIndex;
2688                            
2689                          ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);                          ale = cg->atomList.add(cg->compiler, pn->pn_atom);
2690                          if (!ale)                          if (!ale)
2691                              return JS_FALSE;                              return JS_FALSE;
2692                          atomIndex = ALE_INDEX(ale);                          atomIndex = ALE_INDEX(ale);
2693                          return EmitSlotIndexOp(cx, op, pn2->pn_slot, atomIndex, cg);                          return EmitSlotIndexOp(cx, op, pn2->pn_cookie, atomIndex, cg);
2694                      }                      }
2695                        
2696                    default:;                    default:;
2697                  }                  }
2698              }              }
# Line 2370  Line 2711 
2711          for (;;) {          for (;;) {
2712              /* Reverse pndot->pn_expr to point up, not down. */              /* Reverse pndot->pn_expr to point up, not down. */
2713              pndot->pn_offset = top;              pndot->pn_offset = top;
2714                JS_ASSERT(!pndot->pn_used);
2715              pndown = pndot->pn_expr;              pndown = pndot->pn_expr;
2716              pndot->pn_expr = pnup;              pndot->pn_expr = pnup;
2717              if (pndown->pn_type != TOK_DOT)              if (pndown->pn_type != TOK_DOT)
# Line 2388  Line 2730 
2730                                 CG_OFFSET(cg) - pndown->pn_offset) < 0) {                                 CG_OFFSET(cg) - pndown->pn_offset) < 0) {
2731                  return JS_FALSE;                  return JS_FALSE;
2732              }              }
2733              if (!EmitAtomOp(cx, pndot, PN_OP(pndot), cg))  
2734                /*
2735                 * Special case deoptimization on __proto__, __count__ and
2736                 * __parent__, as above.
2737                 */
2738                if (pndot->pn_arity == PN_NAME &&
2739                    (pndot->pn_atom == cx->runtime->atomState.protoAtom ||
2740                     pndot->pn_atom == cx->runtime->atomState.parentAtom ||
2741                     pndot->pn_atom == cx->runtime->atomState.countAtom)) {
2742                    if (!EmitSpecialPropOp(cx, pndot, JSOP_GETELEM, cg))
2743                        return JS_FALSE;
2744                } else if (!EmitAtomOp(cx, pndot, PN_OP(pndot), cg)) {
2745                  return JS_FALSE;                  return JS_FALSE;
2746                }
2747    
2748              /* Reverse the pn_expr link again. */              /* Reverse the pn_expr link again. */
2749              pnup = pndot->pn_expr;              pnup = pndot->pn_expr;
# Line 2422  Line 2776 
2776          JS_ASSERT(pn->pn_op == JSOP_GETELEM);          JS_ASSERT(pn->pn_op == JSOP_GETELEM);
2777          JS_ASSERT(pn->pn_count >= 3);          JS_ASSERT(pn->pn_count >= 3);
2778          left = pn->pn_head;          left = pn->pn_head;
2779          right = PN_LAST(pn);          right = pn->last();
2780          next = left->pn_next;          next = left->pn_next;
2781          JS_ASSERT(next != right);          JS_ASSERT(next != right);
2782    
# Line 2478  Line 2832 
2832               * the base expression (pn_expr) of the name may be null, which               * the base expression (pn_expr) of the name may be null, which
2833               * means we have to emit a JSOP_BINDNAME.               * means we have to emit a JSOP_BINDNAME.
2834               */               */
2835              left = pn->pn_expr;              left = pn->maybeExpr();
2836              if (!left) {              if (!left) {
2837                  left = &ltmp;                  left = &ltmp;
2838                  left->pn_type = TOK_STRING;                  left->pn_type = TOK_STRING;
# Line 2572  Line 2926 
2926      if (!atom)      if (!atom)
2927          return JS_FALSE;          return JS_FALSE;
2928    
2929      ale = js_IndexAtom(cx, atom, &cg->atomList);      ale = cg->atomList.add(cg->compiler, atom);
2930      if (!ale)      if (!ale)
2931          return JS_FALSE;          return JS_FALSE;
2932      return EmitIndexOp(cx, JSOP_DOUBLE, ALE_INDEX(ale), cg);      return EmitIndexOp(cx, JSOP_DOUBLE, ALE_INDEX(ale), cg);
# Line 2622  Line 2976 
2976           * the stack so that case-dispatch bytecodes can find the discriminant           * the stack so that case-dispatch bytecodes can find the discriminant
2977           * on top of stack.           * on top of stack.
2978           */           */
2979          count = OBJ_BLOCK_COUNT(cx, pn2->pn_pob->object);          count = OBJ_BLOCK_COUNT(cx, pn2->pn_objbox->object);
2980          js_PushBlockScope(&cg->treeContext, stmtInfo, pn2->pn_pob->object, -1);          js_PushBlockScope(cg, stmtInfo, pn2->pn_objbox->object, -1);
2981          stmtInfo->type = STMT_SWITCH;          stmtInfo->type = STMT_SWITCH;
2982    
2983          /* Emit JSOP_ENTERBLOCK before code to evaluate the discriminant. */          /* Emit JSOP_ENTERBLOCK before code to evaluate the discriminant. */
2984          if (!EmitObjectOp(cx, pn2->pn_pob, JSOP_ENTERBLOCK, cg))          if (!EmitEnterBlock(cx, pn2, cg))
2985              return JS_FALSE;              return JS_FALSE;
2986    
2987          /*          /*
2988           * Pop the switch's statement info around discriminant code-gen.  Note           * Pop the switch's statement info around discriminant code-gen.  Note
2989           * how this leaves cg->treeContext.blockChain referencing the switch's           * how this leaves cg->blockChain referencing the switch's
2990           * block scope object, which is necessary for correct block parenting           * block scope object, which is necessary for correct block parenting
2991           * in the case where the discriminant contains a let expression.           * in the case where the discriminant contains a let expression.
2992           */           */
2993          cg->treeContext.topStmt = stmtInfo->down;          cg->topStmt = stmtInfo->down;
2994          cg->treeContext.topScopeStmt = stmtInfo->downScope;          cg->topScopeStmt = stmtInfo->downScope;
2995      }      }
2996  #ifdef __GNUC__  #ifdef __GNUC__
2997      else {      else {
# Line 2656  Line 3010 
3010      /* Switch bytecodes run from here till end of final case. */      /* Switch bytecodes run from here till end of final case. */
3011      top = CG_OFFSET(cg);      top = CG_OFFSET(cg);
3012  #if !JS_HAS_BLOCK_SCOPE  #if !JS_HAS_BLOCK_SCOPE
3013      js_PushStatement(&cg->treeContext, stmtInfo, STMT_SWITCH, top);      js_PushStatement(cg, stmtInfo, STMT_SWITCH, top);
3014  #else  #else
3015      if (pn2->pn_type == TOK_LC) {      if (pn2->pn_type == TOK_LC) {
3016          js_PushStatement(&cg->treeContext, stmtInfo, STMT_SWITCH, top);          js_PushStatement(cg, stmtInfo, STMT_SWITCH, top);
3017      } else {      } else {
3018          /* Re-push the switch's statement info record. */          /* Re-push the switch's statement info record. */
3019          cg->treeContext.topStmt = cg->treeContext.topScopeStmt = stmtInfo;          cg->topStmt = cg->topScopeStmt = stmtInfo;
3020    
3021          /* Set the statement info record's idea of top. */          /* Set the statement info record's idea of top. */
3022          stmtInfo->update = top;          stmtInfo->update = top;
3023    
3024          /* Advance pn2 to refer to the switch case list. */          /* Advance pn2 to refer to the switch case list. */
3025          pn2 = pn2->pn_expr;          pn2 = pn2->expr();
3026      }      }
3027  #endif  #endif
3028    
# Line 2703  Line 3057 
3057                  continue;                  continue;
3058    
3059              pn4 = pn3->pn_left;              pn4 = pn3->pn_left;
3060                while (pn4->pn_type == TOK_RP)
3061                    pn4 = pn4->pn_kid;
3062              switch (pn4->pn_type) {              switch (pn4->pn_type) {
3063                case TOK_NUMBER:                case TOK_NUMBER:
3064                  d = pn4->pn_dval;                  d = pn4->pn_dval;
# Line 2721  Line 3077 
3077                  pn3->pn_val = ATOM_KEY(pn4->pn_atom);                  pn3->pn_val = ATOM_KEY(pn4->pn_atom);
3078                  break;                  break;
3079                case TOK_NAME:                case TOK_NAME:
3080                  if (!pn4->pn_expr) {                  if (!pn4->maybeExpr()) {
3081                      ok = LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &v);                      ok = LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &v);
3082                      if (!ok)                      if (!ok)
3083                          goto release;                          goto release;
# Line 3005  Line 3361 
3361                          (pn4 = pn3->pn_left) != NULL &&                          (pn4 = pn3->pn_left) != NULL &&
3362                          pn4->pn_type == TOK_NAME) {                          pn4->pn_type == TOK_NAME) {
3363                          /* Note a propagated constant with the const's name. */                          /* Note a propagated constant with the const's name. */
3364                          JS_ASSERT(!pn4->pn_expr);                          JS_ASSERT(!pn4->maybeExpr());
3365                          ale = js_IndexAtom(cx, pn4->pn_atom, &cg->atomList);                          ale = cg->atomList.add(cg->compiler, pn4->pn_atom);
3366                          if (!ale)                          if (!ale)
3367                              goto bad;                              goto bad;
3368                          CG_NEXT(cg) = pc;                          CG_NEXT(cg) = pc;
# Line 3022  Line 3378 
3378                      pn4 = pn3->pn_left;                      pn4 = pn3->pn_left;
3379                      if (pn4 && pn4->pn_type == TOK_NAME) {                      if (pn4 && pn4->pn_type == TOK_NAME) {
3380                          /* Note a propagated constant with the const's name. */                          /* Note a propagated constant with the const's name. */
3381                          JS_ASSERT(!pn4->pn_expr);                          JS_ASSERT(!pn4->maybeExpr());
3382                          ale = js_IndexAtom(cx, pn4->pn_atom, &cg->atomList);                          ale = cg->atomList.add(cg->compiler, pn4->pn_atom);
3383                          if (!ale)                          if (!ale)
3384                              goto bad;                              goto bad;
3385                          CG_NEXT(cg) = pc;                          CG_NEXT(cg) = pc;
# Line 3104  Line 3460 
3460                  continue;                  continue;
3461              if (!js_AtomizePrimitiveValue(cx, pn3->pn_val, &atom))              if (!js_AtomizePrimitiveValue(cx, pn3->pn_val, &atom))
3462                  goto bad;                  goto bad;
3463              ale = js_IndexAtom(cx, atom, &cg->atomList);              ale = cg->atomList.add(cg->compiler, atom);
3464              if (!ale)              if (!ale)
3465                  goto bad;                  goto bad;
3466              SET_INDEX(pc, ALE_INDEX(ale));              SET_INDEX(pc, ALE_INDEX(ale));
# Line 3139  Line 3495 
3495  JSBool  JSBool
3496  js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)  js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
3497  {  {
3498      if (cg->treeContext.flags & TCF_FUN_IS_GENERATOR) {      if (cg->flags & TCF_FUN_IS_GENERATOR) {
3499          /* JSOP_GENERATOR must be the first instruction. */          /* JSOP_GENERATOR must be the first instruction. */
3500          CG_SWITCH_TO_PROLOG(cg);          CG_SWITCH_TO_PROLOG(cg);
3501          JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg));          JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg));
# Line 3154  Line 3510 
3510  }  }
3511    
3512  /* A macro for inlining at the top of js_EmitTree (whence it came). */  /* A macro for inlining at the top of js_EmitTree (whence it came). */
3513  #define UPDATE_LINE_NUMBER_NOTES(cx, cg, pn)                                  \  #define UPDATE_LINE_NUMBER_NOTES(cx, cg, line)                                \
3514      JS_BEGIN_MACRO                                                            \      JS_BEGIN_MACRO                                                            \
3515          uintN line_ = (pn)->pn_pos.begin.lineno;                              \          uintN line_ = (line);                                                 \
3516          uintN delta_ = line_ - CG_CURRENT_LINE(cg);                           \          uintN delta_ = line_ - CG_CURRENT_LINE(cg);                           \
3517          if (delta_ != 0) {                                                    \          if (delta_ != 0) {                                                    \
3518              /*                                                                \              /*                                                                \
# Line 3185  Line 3541 
3541    
3542  /* A function, so that we avoid macro-bloating all the other callsites. */  /* A function, so that we avoid macro-bloating all the other callsites. */
3543  static JSBool  static JSBool
3544  UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)  UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, uintN line)
3545  {  {
3546      UPDATE_LINE_NUMBER_NOTES(cx, cg, pn);      UPDATE_LINE_NUMBER_NOTES(cx, cg, line);
3547      return JS_TRUE;      return JS_TRUE;
3548  }  }
3549    
# Line 3198  Line 3554 
3554      jsatomid atomIndex;      jsatomid atomIndex;
3555      JSAtomListElement *ale;      JSAtomListElement *ale;
3556    
3557      if (pn->pn_slot >= 0) {      if (pn->pn_cookie != FREE_UPVAR_COOKIE) {
3558          atomIndex = (jsatomid) pn->pn_slot;          atomIndex = (jsatomid) UPVAR_FRAME_SLOT(pn->pn_cookie);
3559      } else {      } else {
3560          ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);          ale = cg->atomList.add(cg->compiler, pn->pn_atom);
3561          if (!ale)          if (!ale)
3562              return JS_FALSE;              return JS_FALSE;
3563          atomIndex = ALE_INDEX(ale);          atomIndex = ALE_INDEX(ale);
3564      }      }
3565    
3566      if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM &&      if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM &&
3567          (!(cg->treeContext.flags & TCF_IN_FUNCTION) ||          (!(cg->flags & TCF_IN_FUNCTION) || (cg->flags & TCF_FUN_HEAVYWEIGHT))) {
          (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT))) {  
         /* Emit a prolog bytecode to predefine the variable. */  
3568          CG_SWITCH_TO_PROLOG(cg);          CG_SWITCH_TO_PROLOG(cg);
3569          if (!UpdateLineNumberNotes(cx, cg, pn))          if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno))
3570              return JS_FALSE;              return JS_FALSE;
3571          EMIT_INDEX_OP(prologOp, atomIndex);          EMIT_INDEX_OP(prologOp, atomIndex);
3572          CG_SWITCH_TO_MAIN(cg);          CG_SWITCH_TO_MAIN(cg);
# Line 3237  Line 3591 
3591      if (!BindNameToSlot(cx, cg, pn))      if (!BindNameToSlot(cx, cg, pn))
3592          return JS_FALSE;          return JS_FALSE;
3593    
3594      JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS);      JS_ASSERT(PN_OP(pn) != JSOP_ARGUMENTS && PN_OP(pn) != JSOP_CALLEE);
3595      return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL);      return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL);
3596  }  }
3597    
# Line 3296  Line 3650 
3650          if (js_Emit1(cx, cg, JSOP_POP) < 0)          if (js_Emit1(cx, cg, JSOP_POP) < 0)
3651              return JS_FALSE;              return JS_FALSE;
3652      } else {      } else {
3653          if (pn->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn))          if (pn->pn_type == TOK_NAME) {
3654              return JS_FALSE;              if (!BindNameToSlot(cx, cg, pn))
3655                    return JS_FALSE;
3656                if (pn->isConst() && !pn->isInitialized())
3657                    return js_Emit1(cx, cg, JSOP_POP) >= 0;
3658            }
3659    
3660          switch (pn->pn_op) {          switch (pn->pn_op) {
3661            case JSOP_SETNAME:            case JSOP_SETNAME:
# Line 3316  Line 3674 
3674              break;              break;
3675    
3676            case JSOP_SETLOCAL:            case JSOP_SETLOCAL:
3677              slot = (jsuint) pn->pn_slot;              slot = (jsuint) pn->pn_cookie;
3678              EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);              EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
3679              break;              break;
3680    
3681            case JSOP_SETARG:            case JSOP_SETARG:
3682            case JSOP_SETGVAR:            case JSOP_SETGVAR:
3683              slot = (jsuint) pn->pn_slot;              slot = (jsuint) pn->pn_cookie;
3684              EMIT_UINT16_IMM_OP(PN_OP(pn), slot);              EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
3685              if (js_Emit1(cx, cg, JSOP_POP) < 0)              if (js_Emit1(cx, cg, JSOP_POP) < 0)
3686                  return JS_FALSE;                  return JS_FALSE;
# Line 3382  Line 3740 
3740      for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {      for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
3741          /*          /*
3742           * Duplicate the value being destructured to use as a reference base.           * Duplicate the value being destructured to use as a reference base.
3743             * If dup is not the first one, annotate it for the decompiler.
3744           */           */
3745            if (pn2 != pn->pn_head && js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0)
3746                return JS_FALSE;
3747          if (js_Emit1(cx, cg, JSOP_DUP) < 0)          if (js_Emit1(cx, cg, JSOP_DUP) < 0)
3748              return JS_FALSE;              return JS_FALSE;
3749    
# Line 3466  Line 3827 
3827  }  }
3828    
3829  static JSBool  static JSBool
3830  EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp declOp,  EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
3831                       JSParseNode *pn)                       JSParseNode *pn)
3832  {  {
3833      /*      /*
# Line 3475  Line 3836 
3836       * If the destructuring initialiser is empty, our helper will emit a       * If the destructuring initialiser is empty, our helper will emit a
3837       * JSOP_DUP followed by a JSOP_POP for the decompiler.       * JSOP_DUP followed by a JSOP_POP for the decompiler.
3838       */       */
3839      if (js_NewSrcNote2(cx, cg, SRC_DESTRUCT, OpToDeclType(declOp)) < 0)      if (js_NewSrcNote2(cx, cg, SRC_DESTRUCT, OpToDeclType(prologOp)) < 0)
3840          return JS_FALSE;          return JS_FALSE;
3841    
3842      /*      /*
# Line 3486  Line 3847 
3847  }  }
3848    
3849  static JSBool  static JSBool
3850  EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp declOp,  EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
3851                      JSParseNode *lhs, JSParseNode *rhs)                      JSParseNode *lhs, JSParseNode *rhs)
3852  {  {
3853      jsuint depth, limit, i, nslots;      jsuint depth, limit, i, nslots;
# Line 3500  Line 3861 
3861              return JS_FALSE;              return JS_FALSE;
3862          }          }
3863    
3864          if (pn->pn_type == TOK_COMMA) {          /* MaybeEmitGroupAssignment won't call us if rhs is holey. */
3865              if (js_Emit1(cx, cg, JSOP_PUSH) < 0)          JS_ASSERT(pn->pn_type != TOK_COMMA);
3866                  return JS_FALSE;          if (!js_EmitTree(cx, cg, pn))
3867          } else {              return JS_FALSE;
             JS_ASSERT(pn->pn_type != TOK_DEFSHARP);  
             if (!js_EmitTree(cx, cg, pn))  
                 return JS_FALSE;  
         }  
3868          ++limit;          ++limit;
3869      }      }
3870    
3871      if (js_NewSrcNote2(cx, cg, SRC_GROUPASSIGN, OpToDeclType(declOp)) < 0)      if (js_NewSrcNote2(cx, cg, SRC_GROUPASSIGN, OpToDeclType(prologOp)) < 0)
3872          return JS_FALSE;          return JS_FALSE;
3873    
3874      i = depth;      i = depth;
3875      for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) {      for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) {
3876          if (i < limit) {          /* MaybeEmitGroupAssignment requires lhs->pn_count <= rhs->pn_count. */
3877              jsint slot;          JS_ASSERT(i < limit);
3878            jsint slot = AdjustBlockSlot(cx, cg, i);
3879            if (slot < 0)
3880                return JS_FALSE;
3881            EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot);
3882    
             slot = AdjustBlockSlot(cx, cg, i);  
             if (slot < 0)  
                 return JS_FALSE;  
             EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot);  
         } else {  
             if (js_Emit1(cx, cg, JSOP_PUSH) < 0)  
                 return JS_FALSE;  
         }  
3883          if (pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY) {          if (pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY) {
3884              if (js_Emit1(cx, cg, JSOP_POP) < 0)              if (js_Emit1(cx, cg, JSOP_POP) < 0)
3885                  return JS_FALSE;                  return JS_FALSE;
# Line 3548  Line 3901 
3901   * we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop.   * we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop.
3902   */   */
3903  static JSBool  static JSBool
3904  MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp declOp,  MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
3905                           JSParseNode *pn, JSOp *pop)                           JSParseNode *pn, JSOp *pop)
3906  {  {
3907      JSParseNode *lhs, *rhs;      JSParseNode *lhs, *rhs;
# Line 3558  Line 3911 
3911      lhs = pn->pn_left;      lhs = pn->pn_left;
3912      rhs = pn->pn_right;      rhs = pn->pn_right;
3913      if (lhs->pn_type == TOK_RB && rhs->pn_type == TOK_RB &&      if (lhs->pn_type == TOK_RB && rhs->pn_type == TOK_RB &&
3914          lhs->pn_count <= rhs->pn_count &&          !(rhs->pn_xflags & PNX_HOLEY) &&
3915          (rhs->pn_count == 0 ||          lhs->pn_count <= rhs->pn_count) {
3916           rhs->pn_head->pn_type != TOK_DEFSHARP)) {          if (!EmitGroupAssignment(cx, cg, prologOp, lhs, rhs))
         if (!EmitGroupAssignment(cx, cg, declOp, lhs, rhs))  
3917              return JS_FALSE;              return JS_FALSE;
3918          *pop = JSOP_NOP;          *pop = JSOP_NOP;
3919      }      }
# Line 3574  Line 3926 
3926  EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,  EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
3927                JSBool inLetHead, ptrdiff_t *headNoteIndex)                JSBool inLetHead, ptrdiff_t *headNoteIndex)
3928  {  {
3929      JSTreeContext *tc;      bool let, forInVar, first;
     JSBool let, forInVar;  
3930  #if JS_HAS_BLOCK_SCOPE  #if JS_HAS_BLOCK_SCOPE
3931      JSBool forInLet, popScope;      bool forInLet, popScope;
3932      JSStmtInfo *stmt, *scopeStmt;      JSStmtInfo *stmt, *scopeStmt;
3933  #endif  #endif
3934      ptrdiff_t off, noteIndex, tmp;      ptrdiff_t off, noteIndex, tmp;
3935      JSParseNode *pn2, *pn3;      JSParseNode *pn2, *pn3, *next;
3936      JSOp op;      JSOp op;
3937      jsatomid atomIndex;      jsatomid atomIndex;
3938      uintN oldflags;      uintN oldflags;
# Line 3601  Line 3952 
3952       * to the start of the block, a 'for (let x = i...) ...' loop evaluates i       * to the start of the block, a 'for (let x = i...) ...' loop evaluates i
3953       * in the containing scope, and puts x in the loop body's scope.       * in the containing scope, and puts x in the loop body's scope.
3954       */       */
     tc = &cg->treeContext;  
3955      let = (pn->pn_op == JSOP_NOP);      let = (pn->pn_op == JSOP_NOP);
3956      forInVar = (pn->pn_extra & PNX_FORINVAR) != 0;      forInVar = (pn->pn_xflags & PNX_FORINVAR) != 0;
3957  #if JS_HAS_BLOCK_SCOPE  #if JS_HAS_BLOCK_SCOPE
3958      forInLet = let && forInVar;      forInLet = let && forInVar;
3959      popScope = (inLetHead || (let && (tc->flags & TCF_IN_FOR_INIT)));      popScope = (inLetHead || (let && (cg->flags & TCF_IN_FOR_INIT)));
3960        if (popScope) {
3961            stmt = cg->topStmt;
3962            scopeStmt = cg->topScopeStmt;
3963        }
3964    # ifdef __GNUC__
3965        else stmt = scopeStmt = NULL;   /* quell GCC overwarning */
3966    # endif
3967      JS_ASSERT(!popScope || let);      JS_ASSERT(!popScope || let);
3968  #endif  #endif
3969    
3970      off = noteIndex = -1;      off = noteIndex = -1;
3971      for (pn2 = pn->pn_head; ; pn2 = pn2->pn_next) {      for (pn2 = pn->pn_head; ; pn2 = next) {
3972  #if JS_HAS_DESTRUCTURING          first = pn2 == pn->pn_head;
3973            next = pn2->pn_next;
3974    
3975          if (pn2->pn_type != TOK_NAME) {          if (pn2->pn_type != TOK_NAME) {
3976    #if JS_HAS_DESTRUCTURING
3977              if (pn2->pn_type == TOK_RB || pn2->pn_type == TOK_RC) {              if (pn2->pn_type == TOK_RB || pn2->pn_type == TOK_RC) {
3978                  /*                  /*
3979                   * Emit variable binding ops, but not destructuring ops.                   * Emit variable binding ops, but not destructuring ops.
# Line 3629  Line 3989 
3989                      return JS_FALSE;                      return JS_FALSE;
3990                  break;                  break;
3991              }              }
3992    #endif
3993    
3994              /*              /*
3995               * A destructuring initialiser assignment preceded by var is               * A destructuring initialiser assignment preceded by var will
3996               * always evaluated promptly, even if it is to the left of 'in'               * never occur to the left of 'in' in a for-in loop.  As with 'for
3997               * in a for-in loop.  As with 'for (var x = i in o)...', this               * (var x = i in o)...', this will cause the entire 'var [a, b] =
3998               * will cause the entire 'var [a, b] = i' to be hoisted out of               * i' to be hoisted out of the loop.
              * the head of the loop.  
3999               */               */
4000              JS_ASSERT(pn2->pn_type == TOK_ASSIGN);              JS_ASSERT(pn2->pn_type == TOK_ASSIGN);
4001              if (pn->pn_count == 1 && !forInLet) {              JS_ASSERT(!forInVar);
4002    
4003                /*
4004                 * To allow the front end to rewrite var f = x; as f = x; when a
4005                 * function f(){} precedes the var, detect simple name assignment
4006                 * here and initialize the name.
4007                 */
4008    #if !JS_HAS_DESTRUCTURING
4009                JS_ASSERT(pn2->pn_left->pn_type == TOK_NAME);
4010    #else
4011                if (pn2->pn_left->pn_type == TOK_NAME)
4012    #endif
4013                {
4014                    pn3 = pn2->pn_right;
4015                    pn2 = pn2->pn_left;
4016                    goto do_name;
4017                }
4018    
4019    #if JS_HAS_DESTRUCTURING
4020                if (pn->pn_count == 1) {
4021                  /*                  /*
4022                   * If this is the only destructuring assignment in the list,                   * If this is the only destructuring assignment in the list,
4023                   * try to optimize to a group assignment.  If we're in a let                   * try to optimize to a group assignment.  If we're in a let
# Line 3648  Line 4027 
4027                  JS_ASSERT(noteIndex < 0 && !pn2->pn_next);                  JS_ASSERT(noteIndex < 0 && !pn2->pn_next);
4028                  op = JSOP_POP;                  op = JSOP_POP;
4029                  if (!MaybeEmitGroupAssignment(cx, cg,                  if (!MaybeEmitGroupAssignment(cx, cg,
4030                                                inLetHead ? JSOP_POP :                                                inLetHead ? JSOP_POP : PN_OP(pn),
                                               PN_OP(pn),  
4031                                                pn2, &op)) {                                                pn2, &op)) {
4032                      return JS_FALSE;                      return JS_FALSE;
4033                  }                  }
4034                  if (op == JSOP_NOP) {                  if (op == JSOP_NOP) {
4035                      pn->pn_extra = (pn->pn_extra & ~PNX_POPVAR) | PNX_GROUPINIT;                      pn->pn_xflags = (pn->pn_xflags & ~PNX_POPVAR) | PNX_GROUPINIT;
4036                      break;                      break;
4037                  }                  }
4038              }              }
# Line 3663  Line 4041 
4041              if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn3))              if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn3))
4042                  return JS_FALSE;                  return JS_FALSE;
4043    
 #if JS_HAS_BLOCK_SCOPE  
             /*  
              * If this is a 'for (let [x, y] = i in o) ...' let declaration,  
              * throw away i if it is a useless expression.  
              */  
             if (forInLet) {  
                 JSBool useful = JS_FALSE;  
   
                 JS_ASSERT(pn->pn_count == 1);  
                 if (!CheckSideEffects(cx, cg, pn2->pn_right, &useful))  
                     return JS_FALSE;  
                 if (!useful)  
                     return JS_TRUE;  
             }  
 #endif  
   
4044              if (!js_EmitTree(cx, cg, pn2->pn_right))              if (!js_EmitTree(cx, cg, pn2->pn_right))
4045                  return JS_FALSE;                  return JS_FALSE;
4046    
 #if JS_HAS_BLOCK_SCOPE  
             /*  
              * The expression i in 'for (let [x, y] = i in o) ...', which is  
              * pn2->pn_right above, appears to have side effects.  We've just  
              * emitted code to evaluate i, but we must not destructure i yet.  
              * Let the TOK_FOR: code in js_EmitTree do the destructuring to  
              * emit the right combination of source notes and bytecode for the  
              * decompiler.  
              *  
              * This has the effect of hoisting the evaluation of i out of the  
              * for-in loop, without hoisting the let variables, which must of  
              * course be scoped by the loop.  Set PNX_POPVAR to cause JSOP_POP  
              * to be emitted, just before returning from this function.  
              */  
             if (forInVar) {  
                 pn->pn_extra |= PNX_POPVAR;  
                 if (forInLet)  
                     break;  
             }  
 #endif  
   
4047              /*              /*
4048               * Veto pn->pn_op if inLetHead to avoid emitting a SRC_DESTRUCT               * Veto pn->pn_op if inLetHead to avoid emitting a SRC_DESTRUCT
4049               * that's redundant with respect to the SRC_DECL/SRC_DECL_LET that               * that's redundant with respect to the SRC_DECL/SRC_DECL_LET that
# Line 3714  Line 4055 
4055                  return JS_FALSE;                  return JS_FALSE;
4056              }              }
4057              goto emit_note_pop;              goto emit_note_pop;
         }  
 #else  
         JS_ASSERT(pn2->pn_type == TOK_NAME);  
4058  #endif  #endif
4059            }
4060    
4061            /*
4062             * Load initializer early to share code above that jumps to do_name.
4063             * NB: if this var redeclares an existing binding, then pn2 is linked
4064             * on its definition's use-chain and pn_expr has been overlayed with
4065             * pn_lexdef.
4066             */
4067            pn3 = pn2->maybeExpr();
4068    
4069         do_name:
4070          if (!BindNameToSlot(cx, cg, pn2))          if (!BindNameToSlot(cx, cg, pn2))
4071              return JS_FALSE;              return JS_FALSE;
         JS_ASSERT(pn2->pn_slot >= 0 || !let);  
4072    
4073          op = PN_OP(pn2);          op = PN_OP(pn2);
4074          if (op == JSOP_ARGUMENTS) {          if (op == JSOP_ARGUMENTS) {
4075              /* JSOP_ARGUMENTS => no initializer */              /* JSOP_ARGUMENTS => no initializer */
4076              JS_ASSERT(!pn2->pn_expr && !let);              JS_ASSERT(!pn3 && !let);
4077              pn3 = NULL;              pn3 = NULL;
4078  #ifdef __GNUC__  #ifdef __GNUC__
4079              atomIndex = 0;            /* quell GCC overwarning */              atomIndex = 0;            /* quell GCC overwarning */
4080  #endif  #endif
4081          } else {          } else {
4082                JS_ASSERT(op != JSOP_CALLEE);
4083                JS_ASSERT(pn2->pn_cookie != FREE_UPVAR_COOKIE || !let);
4084              if (!MaybeEmitVarDecl(cx, cg, PN_OP(pn), pn2, &atomIndex))              if (!MaybeEmitVarDecl(cx, cg, PN_OP(pn), pn2, &atomIndex))
4085                  return JS_FALSE;                  return JS_FALSE;
4086    
             pn3 = pn2->pn_expr;  
4087              if (pn3) {              if (pn3) {
4088  #if JS_HAS_BLOCK_SCOPE                  JS_ASSERT(!forInVar);
                 /*  
                  * If this is a 'for (let x = i in o) ...' let declaration,  
                  * throw away i if it is a useless expression.  
                  */  
                 if (forInLet) {  
                     JSBool useful = JS_FALSE;  
   
                     JS_ASSERT(pn->pn_count == 1);  
                     if (!CheckSideEffects(cx, cg, pn3, &useful))  
                         return JS_FALSE;  
                     if (!useful)  
                         return JS_TRUE;  
                 }  
 #endif  
   
4089                  if (op == JSOP_SETNAME) {                  if (op == JSOP_SETNAME) {
4090                      JS_ASSERT(!let);                      JS_ASSERT(!let);
4091                      EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);                      EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
4092                  }                  }
4093                  if (pn->pn_op == JSOP_DEFCONST &&                  if (pn->pn_op == JSOP_DEFCONST &&
4094                      !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom,                      !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom, pn3)) {
                                                   pn3)) {  
4095                      return JS_FALSE;                      return JS_FALSE;
4096                  }                  }
4097    
4098  #if JS_HAS_BLOCK_SCOPE  #if JS_HAS_BLOCK_SCOPE
4099                  /* Evaluate expr in the outer lexical scope if requested. */                  /* Evaluate expr in the outer lexical scope if requested. */
4100                  if (popScope) {                  if (popScope) {
4101                      stmt = tc->topStmt;                      cg->topStmt = stmt->down;
4102                      scopeStmt = tc->topScopeStmt;                      cg->topScopeStmt = scopeStmt->downScope;
   
                     tc->topStmt = stmt->down;  
                     tc->topScopeStmt = scopeStmt->downScope;  
                 }  
 #ifdef __GNUC__  
                 else {  
                     stmt = scopeStmt = NULL;    /* quell GCC overwarning */  
4103                  }                  }
4104  #endif  #endif
 #endif  
4105    
4106                  oldflags = cg->treeContext.flags;                  oldflags = cg->flags;
4107                  cg->treeContext.flags &= ~TCF_IN_FOR_INIT;                  cg->flags &= ~TCF_IN_FOR_INIT;
4108                  if (!js_EmitTree(cx, cg, pn3))                  if (!js_EmitTree(cx, cg, pn3))
4109                      return JS_FALSE;                      return JS_FALSE;
4110                  cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;                  cg->flags |= oldflags & TCF_IN_FOR_INIT;
4111    
4112  #if JS_HAS_BLOCK_SCOPE  #if JS_HAS_BLOCK_SCOPE
4113                  if (popScope) {                  if (popScope) {
4114                      tc->topStmt = stmt;                      cg->topStmt = stmt;
4115                      tc->topScopeStmt = scopeStmt;                      cg->topScopeStmt = scopeStmt;
4116                  }                  }
4117  #endif  #endif
4118              }              }
4119          }          }
4120    
4121          /*          /*
4122           * 'for (var x in o) ...' and 'for (var x = i in o) ...' call the           * The parser rewrites 'for (var x = i in o)' to hoist 'var x = i' --
4123           * TOK_VAR case, but only the initialized case (a strange one that           * likewise 'for (let x = i in o)' becomes 'i; for (let x in o)' using
4124           * falls out of ECMA-262's grammar) wants to run past this point.           * a TOK_SEQ node to make the two statements appear as one. Therefore
4125           * Both cases must conditionally emit a JSOP_DEFVAR, above.  Note           * if this declaration is part of a for-in loop head, we do not need to
4126           * that the parser error-checks to ensure that pn->pn_count is 1.           * emit op or any source note. Our caller, the TOK_FOR/TOK_IN case in
4127           *           * js_EmitTree, will annotate appropriately.
          * 'for (let x = i in o) ...' must evaluate i before the loop, and  
          * subject it to useless expression elimination.  The variable list  
          * in pn is a single let declaration if pn_op == JSOP_NOP.  We test  
          * the let local in order to break early in this case, as well as in  
          * the 'for (var x in o)' case.  
          *  
          * XXX Narcissus keeps track of variable declarations in the node  
          * for the script being compiled, so there's no need to share any  
          * conditional prolog code generation there.  We could do likewise,  
          * but it's a big change, requiring extra allocation, so probably  
          * not worth the trouble for SpiderMonkey.  
4128           */           */
4129          JS_ASSERT(pn3 == pn2->pn_expr);          JS_ASSERT_IF(pn2->pn_defn, pn3 == pn2->pn_expr);
4130          if (forInVar && (!pn3 || let)) {          if (forInVar) {
4131              JS_ASSERT(pn->pn_count == 1);              JS_ASSERT(pn->pn_count == 1);
4132                JS_ASSERT(!pn3);
4133              break;              break;
4134          }          }
4135    
4136          if (pn2 == pn->pn_head &&          if (first &&
4137              !inLetHead &&              !inLetHead &&
4138              js_NewSrcNote2(cx, cg, SRC_DECL,              js_NewSrcNote2(cx, cg, SRC_DECL,
4139                             (pn->pn_op == JSOP_DEFCONST)                             (pn->pn_op == JSOP_DEFCONST)
# Line 3832  Line 4146 
4146          if (op == JSOP_ARGUMENTS) {          if (op == JSOP_ARGUMENTS) {
4147              if (js_Emit1(cx, cg, op) < 0)              if (js_Emit1(cx, cg, op) < 0)
4148                  return JS_FALSE;                  return JS_FALSE;
4149          } else if (pn2->pn_slot >= 0) {          } else if (pn2->pn_cookie != FREE_UPVAR_COOKIE) {
4150              EMIT_UINT16_IMM_OP(op, atomIndex);              EMIT_UINT16_IMM_OP(op, atomIndex);
4151          } else {          } else {
4152              EMIT_INDEX_OP(op, atomIndex);              EMIT_INDEX_OP(op, atomIndex);
# Line 3846  Line 4160 
4160              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))
4161                  return JS_FALSE;                  return JS_FALSE;
4162          }          }
4163          if (!pn2->pn_next)          if (!next)
4164              break;              break;
4165          off = tmp;          off = tmp;
4166          noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);          noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
# Line 3859  Line 4173 
4173          *headNoteIndex = js_NewSrcNote(cx, cg, SRC_DECL);          *headNoteIndex = js_NewSrcNote(cx, cg, SRC_DECL);
4174          if (*headNoteIndex < 0)          if (*headNoteIndex < 0)
4175              return JS_FALSE;              return JS_FALSE;
4176          if (!(pn->pn_extra & PNX_POPVAR))          if (!(pn->pn_xflags & PNX_POPVAR))
4177              return js_Emit1(cx, cg, JSOP_NOP) >= 0;              return js_Emit1(cx, cg, JSOP_NOP) >= 0;
4178      }      }
4179    
4180      return !(pn->pn_extra & PNX_POPVAR) || js_Emit1(cx, cg, JSOP_POP) >= 0;      return !(pn->pn_xflags & PNX_POPVAR) || js_Emit1(cx, cg, JSOP_POP) >= 0;
4181  }  }
4182    
4183  #if defined DEBUG_brendanXXX || defined DEBUG_mrbkap  #if defined DEBUG_brendan || defined DEBUG_mrbkap
4184  static JSBool  static JSBool
4185  GettableNoteForNextOp(JSCodeGenerator *cg)  GettableNoteForNextOp(JSCodeGenerator *cg)
4186  {  {
# Line 3893  Line 4207 
4207             js_Emit1(cx, cg, JSOP_NOP) >= 0;             js_Emit1(cx, cg, JSOP_NOP) >= 0;
4208  }  }
4209    
4210    /* See the SRC_FOR source note offsetBias comments later in this file. */
4211    JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
4212    JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1);
4213    
4214  JSBool  JSBool
4215  js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)  js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
4216  {  {
# Line 3910  Line 4228 
4228      JSOp op;      JSOp op;
4229      JSTokenType type;      JSTokenType type;
4230      uint32 argc;      uint32 argc;
4231    #if JS_HAS_SHARP_VARS
4232        jsint sharpnum;
4233    #endif
4234    
4235      JS_CHECK_RECURSION(cx, return JS_FALSE);      JS_CHECK_RECURSION(cx, return JS_FALSE);
4236    
# Line 3918  Line 4239 
4239      pn->pn_offset = top = CG_OFFSET(cg);      pn->pn_offset = top = CG_OFFSET(cg);
4240    
4241      /* Emit notes to tell the current bytecode's source line number. */      /* Emit notes to tell the current bytecode's source line number. */
4242      UPDATE_LINE_NUMBER_NOTES(cx, cg, pn);      UPDATE_LINE_NUMBER_NOTES(cx, cg, pn->pn_pos.begin.lineno);
4243    
4244      switch (pn->pn_type) {      switch (pn->pn_type) {
4245        case TOK_FUNCTION:        case TOK_FUNCTION:
4246        {        {
4247          JSFunction *fun;          JSFunction *fun;
         void *cg2mark;  
         JSCodeGenerator *cg2;  
4248          uintN slot;          uintN slot;
4249    
4250  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
# Line 3936  Line 4255 
4255          }          }
4256  #endif  #endif
4257    
4258          fun = (JSFunction *) pn->pn_funpob->object;          fun = (JSFunction *) pn->pn_funbox->object;
4259            JS_ASSERT(FUN_INTERPRETED(fun));
4260          if (fun->u.i.script) {          if (fun->u.i.script) {
4261              /*              /*
4262               * This second pass is needed to emit JSOP_NOP with a source note               * This second pass is needed to emit JSOP_NOP with a source note
# Line 3944  Line 4264 
4264               * comments in the TOK_LC case.               * comments in the TOK_LC case.
4265               */               */
4266              JS_ASSERT(pn->pn_op == JSOP_NOP);              JS_ASSERT(pn->pn_op == JSOP_NOP);
4267              JS_ASSERT(cg->treeContext.flags & TCF_IN_FUNCTION);              JS_ASSERT(cg->flags & TCF_IN_FUNCTION);
             JS_ASSERT(pn->pn_index != (uint32) -1);  
4268              if (!EmitFunctionDefNop(cx, cg, pn->pn_index))              if (!EmitFunctionDefNop(cx, cg, pn->pn_index))
4269                  return JS_FALSE;                  return JS_FALSE;
4270              break;              break;
4271          }          }
4272    
4273          /*          JS_ASSERT_IF(cx->options & JSOPTION_ANONFUNFIX,
4274           * Limit static nesting depth to fit in 16 bits. See cg2->staticDepth                       pn->pn_defn ||
4275           * assignment below.                       (!pn->pn_used && !pn->isTopLevel()) ||
4276           */                       (fun->flags & JSFUN_LAMBDA));
4277          if (cg->staticDepth == JS_BITMASK(16)) {  
4278              JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_DEEP,          JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
4279                                   js_function_str);                       FUN_KIND(fun) == JSFUN_INTERPRETED);
             return JS_FALSE;  
         }  
4280    
4281          /* Generate code for the function's body. */          /* Generate code for the function's body. */
4282          cg2mark = JS_ARENA_MARK(cg->codePool);          void *cg2mark = JS_ARENA_MARK(cg->codePool);
4283          JS_ARENA_ALLOCATE_TYPE(cg2, JSCodeGenerator, cg->codePool);          void *cg2space;
4284          if (!cg2) {          JS_ARENA_ALLOCATE_TYPE(cg2space, JSCodeGenerator, cg->codePool);
4285            if (!cg2space) {
4286              js_ReportOutOfScriptQuota(cx);              js_ReportOutOfScriptQuota(cx);
4287              return JS_FALSE;              return JS_FALSE;
4288          }          }
4289          js_InitCodeGenerator(cx, cg2, cg->treeContext.parseContext,          JSCodeGenerator *cg2 =
4290                               cg->codePool, cg->notePool,              new (cg2space) JSCodeGenerator(cg->compiler,
4291                               pn->pn_pos.begin.lineno);                                             cg->codePool, cg->notePool,
4292          cg2->treeContext.flags = (uint16) (pn->pn_flags | TCF_IN_FUNCTION);                                             pn->pn_pos.begin.lineno);
4293          cg2->treeContext.u.fun = fun;          cg2->flags = (uint16) (pn->pn_funbox->tcflags | TCF_IN_FUNCTION);
4294          cg2->staticDepth = cg->staticDepth + 1;          cg2->fun = fun;
4295            cg2->funbox = pn->pn_funbox;
4296          cg2->parent = cg;          cg2->parent = cg;
4297    
4298          /* We metered the max scope depth when parsed the function. */          /*
4299          JS_SCOPE_DEPTH_METERING(cg2->treeContext.maxScopeDepth = (uintN) -1);           * jsparse.cpp:SetStaticLevel limited static nesting depth to fit in 16
4300          if (!js_EmitFunctionScript(cx, cg2, pn->pn_body)) {           * bits and to reserve the all-ones value, thereby reserving the magic
4301             * FREE_UPVAR_COOKIE value. Note the cg2->staticLevel assignment below.
4302             */
4303            JS_ASSERT(cg->staticLevel < JS_BITMASK(16) - 1);
4304            cg2->staticLevel = cg->staticLevel + 1;
4305    
4306            /* We measured the max scope depth when we parsed the function. */
4307            JS_SCOPE_DEPTH_METERING(cg2->maxScopeDepth = (uintN) -1);
4308            if (!js_EmitFunctionScript(cx, cg2, pn->pn_body))
4309              pn = NULL;              pn = NULL;
         } else {  
             /*  
              * We need an activation object if an inner peeks out, or if such  
              * inner-peeking caused one of our inners to become heavyweight.  
              */  
             if (cg2->treeContext.flags &  
                 (TCF_FUN_USES_NONLOCALS | TCF_FUN_HEAVYWEIGHT)) {  
                 cg->treeContext.flags |= TCF_FUN_HEAVYWEIGHT;  
             }  
         }  
4310    
4311          js_FinishCodeGenerator(cx, cg2);          cg2->~JSCodeGenerator();
4312          JS_ARENA_RELEASE(cg->codePool, cg2mark);          JS_ARENA_RELEASE(cg->codePool, cg2mark);
4313          cg2 = NULL;          cg2 = NULL;
4314          if (!pn)          if (!pn)
4315              return JS_FALSE;              return JS_FALSE;
4316    
4317          /* Make the function object a literal in the outer script's pool. */          /* Make the function object a literal in the outer script's pool. */
4318          index = IndexParsedObject(pn->pn_funpob, &cg->objectList);          index = cg->objectList.index(pn->pn_funbox);
4319    
4320          /* Emit a bytecode pointing to the closure object in its immediate. */          /* Emit a bytecode pointing to the closure object in its immediate. */
4321          if (pn->pn_op != JSOP_NOP) {          op = PN_OP(pn);
4322              if ((pn->pn_flags & TCF_GENEXP_LAMBDA) &&          if (op != JSOP_NOP) {
4323                if ((pn->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) &&
4324                  js_NewSrcNote(cx, cg, SRC_GENEXP) < 0) {                  js_NewSrcNote(cx, cg, SRC_GENEXP) < 0) {
4325                  return JS_FALSE;                  return JS_FALSE;
4326              }              }
4327              EMIT_INDEX_OP(PN_OP(pn), index);              EMIT_INDEX_OP(op, index);
4328              break;              break;
4329          }          }
4330    
# Line 4019  Line 4337 
4337           * invocation of the emitter and calls to js_EmitTree for function           * invocation of the emitter and calls to js_EmitTree for function
4338           * definitions can be scheduled before generating the rest of code.           * definitions can be scheduled before generating the rest of code.
4339           */           */
4340          if (!(cg->treeContext.flags & TCF_IN_FUNCTION)) {          if (!(cg->flags & TCF_IN_FUNCTION)) {
4341              JS_ASSERT(!cg->treeContext.topStmt);              JS_ASSERT(!cg->topStmt);
4342              CG_SWITCH_TO_PROLOG(cg);              CG_SWITCH_TO_PROLOG(cg);
4343              EMIT_INDEX_OP(JSOP_DEFFUN, index);              op = FUN_FLAT_CLOSURE(fun) ? JSOP_DEFFUN_FC : JSOP_DEFFUN;
4344                EMIT_INDEX_OP(op, index);
4345              CG_SWITCH_TO_MAIN(cg);              CG_SWITCH_TO_MAIN(cg);
4346    
4347              /* Emit NOP for the decompiler. */              /* Emit NOP for the decompiler. */
# Line 4032  Line 4351 
4351  #ifdef DEBUG  #ifdef DEBUG
4352              JSLocalKind localKind =              JSLocalKind localKind =
4353  #endif  #endif
4354                  js_LookupLocal(cx, cg->treeContext.u.fun, fun->atom, &slot);                  js_LookupLocal(cx, cg->fun, fun->atom, &slot);
4355              JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);              JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
4356              JS_ASSERT(pn->pn_index == (uint32) -1);              JS_ASSERT(index < JS_BIT(20));
4357              pn->pn_index = index;              pn->pn_index = index;
4358              if (!EmitSlotIndexOp(cx, JSOP_DEFLOCALFUN, slot, index, cg))              op = FUN_FLAT_CLOSURE(fun) ? JSOP_DEFLOCALFUN_FC : JSOP_DEFLOCALFUN;
4359                if (!EmitSlotIndexOp(cx, op, slot, index, cg))
4360                  return JS_FALSE;                  return JS_FALSE;
4361          }          }
4362          break;          break;
4363        }        }
4364    
4365          case TOK_ARGSBODY:
4366            ok = js_EmitTree(cx, cg, pn->last());
4367            break;
4368    
4369          case TOK_UPVARS:
4370            JS_ASSERT(cg->lexdeps.count == 0);
4371            JS_ASSERT(pn->pn_names.count != 0);
4372            cg->lexdeps = pn->pn_names;
4373            ok = js_EmitTree(cx, cg, pn->pn_tree);
4374            break;
4375    
4376        case TOK_IF:        case TOK_IF:
4377          /* Initialize so we can detect else-if chains and avoid recursion. */          /* Initialize so we can detect else-if chains and avoid recursion. */
# Line 4055  Line 4385 
4385              return JS_FALSE;              return JS_FALSE;
4386          top = CG_OFFSET(cg);          top = CG_OFFSET(cg);
4387          if (stmtInfo.type == STMT_IF) {          if (stmtInfo.type == STMT_IF) {
4388              js_PushStatement(&cg->treeContext, &stmtInfo, STMT_IF, top);              js_PushStatement(cg, &stmtInfo, STMT_IF, top);
4389          } else {          } else {
4390              /*              /*
4391               * We came here from the goto further below that detects else-if               * We came here from the goto further below that detects else-if
# Line 4153  Line 4483 
4483           * that bracketed the body. But given the SRC_WHILE note, it is easy           * that bracketed the body. But given the SRC_WHILE note, it is easy
4484           * to support the more efficient scheme.           * to support the more efficient scheme.
4485           */           */
4486          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_WHILE_LOOP, top);          js_PushStatement(cg, &stmtInfo, STMT_WHILE_LOOP, top);
4487          noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);          noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);
4488          if (noteIndex < 0)          if (noteIndex < 0)
4489              return JS_FALSE;              return JS_FALSE;
# Line 4161  Line 4491 
4491          if (jmp < 0)          if (jmp < 0)
4492              return JS_FALSE;              return JS_FALSE;
4493          top = CG_OFFSET(cg);          top = CG_OFFSET(cg);
4494            if (!js_Emit1(cx, cg, JSOP_LOOP))
4495                return JS_FALSE;
4496          if (!js_EmitTree(cx, cg, pn->pn_right))          if (!js_EmitTree(cx, cg, pn->pn_right))
4497              return JS_FALSE;              return JS_FALSE;
4498          CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);          CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
# Line 4182  Line 4514 
4514    
4515          /* Compile the loop body. */          /* Compile the loop body. */
4516          top = CG_OFFSET(cg);          top = CG_OFFSET(cg);
4517          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_DO_LOOP, top);          if (!js_Emit1(cx, cg, JSOP_LOOP))
4518                return JS_FALSE;
4519            js_PushStatement(cg, &stmtInfo, STMT_DO_LOOP, top);
4520          if (!js_EmitTree(cx, cg, pn->pn_left))          if (!js_EmitTree(cx, cg, pn->pn_left))
4521              return JS_FALSE;              return JS_FALSE;
4522    
# Line 4213  Line 4547 
4547          beq = 0;                /* suppress gcc warnings */          beq = 0;                /* suppress gcc warnings */
4548          jmp = -1;          jmp = -1;
4549          pn2 = pn->pn_left;          pn2 = pn->pn_left;
4550          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_FOR_LOOP, top);          js_PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top);
4551    
4552          if (pn2->pn_type == TOK_IN) {          if (pn2->pn_type == TOK_IN) {
             JSBool emitIFEQ;  
   
4553              /* Set stmtInfo type for later testing. */              /* Set stmtInfo type for later testing. */
4554              stmtInfo.type = STMT_FOR_IN_LOOP;              stmtInfo.type = STMT_FOR_IN_LOOP;
             noteIndex = -1;  
4555    
4556              /*              /*
4557               * If the left part is 'var x', emit code to define x if necessary               * If the left part is 'var x', emit code to define x if necessary
# Line 4230  Line 4561 
4561               * result off the stack.               * result off the stack.
4562               *               *
4563               * All the logic to do this is implemented in the outer switch's               * All the logic to do this is implemented in the outer switch's
4564               * TOK_VAR case, conditioned on pn_extra flags set by the parser.               * TOK_VAR case, conditioned on pn_xflags flags set by the parser.
4565               *               *
4566               * In the 'for (var x = i in o) ...' case, the js_EmitTree(...pn3)               * In the 'for (var x = i in o) ...' case, the js_EmitTree(...pn3)
4567               * called here will generate the proper note for the assignment               * called here will generate the proper note for the assignment
# Line 4249  Line 4580 
4580               */               */
4581              pn3 = pn2->pn_left;              pn3 = pn2->pn_left;
4582              type = PN_TYPE(pn3);              type = PN_TYPE(pn3);
4583              cg->treeContext.flags |= TCF_IN_FOR_INIT;              cg->flags |= TCF_IN_FOR_INIT;
4584              if (TOKEN_TYPE_IS_DECL(type) && !js_EmitTree(cx, cg, pn3))              if (TOKEN_TYPE_IS_DECL(type) && !js_EmitTree(cx, cg, pn3))
4585                  return JS_FALSE;                  return JS_FALSE;
4586              cg->treeContext.flags &= ~TCF_IN_FOR_INIT;              cg->flags &= ~TCF_IN_FOR_INIT;
4587    
4588              /* Compile the object expression to the right of 'in'. */              /* Compile the object expression to the right of 'in'. */
4589              if (!js_EmitTree(cx, cg, pn2->pn_right))              if (!js_EmitTree(cx, cg, pn2->pn_right))
# Line 4264  Line 4595 
4595               * destructuring for-in).               * destructuring for-in).
4596               */               */
4597              JS_ASSERT(pn->pn_op == JSOP_ITER);              JS_ASSERT(pn->pn_op == JSOP_ITER);
4598              if (js_Emit2(cx, cg, PN_OP(pn), (uint8) pn->pn_iflags) < 0)              if (js_Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
4599                    return JS_FALSE;
4600    
4601                /* Annotate so the decompiler can find the loop-closing jump. */
4602                noteIndex = js_NewSrcNote(cx, cg, SRC_FOR_IN);
4603                if (noteIndex < 0)
4604                    return JS_FALSE;
4605    
4606                /*
4607                 * Jump down to the loop condition to minimize overhead assuming at
4608                 * least one iteration, as the other loop forms do.
4609                 */
4610                jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
4611                if (jmp < 0)
4612                  return JS_FALSE;                  return JS_FALSE;
4613    
4614              top = CG_OFFSET(cg);              top = CG_OFFSET(cg);
4615              SET_STATEMENT_TOP(&stmtInfo, top);              SET_STATEMENT_TOP(&stmtInfo, top);
4616                if (!js_Emit1(cx, cg, JSOP_LOOP))
4617                    return JS_FALSE;
4618    
4619    #ifdef DEBUG
4620                intN loopDepth = cg->stackDepth;
4621    #endif
4622    
4623              /*              /*
4624               * Compile a JSOP_FOR* bytecode based on the left hand side.               * Compile a JSOP_FOR* bytecode based on the left hand side.
# Line 4280  Line 4630 
4630               * assignment, so JSOP_SETNAME is not critical here; many similar               * assignment, so JSOP_SETNAME is not critical here; many similar
4631               * ops could be used -- just not JSOP_NOP (which means 'let').               * ops could be used -- just not JSOP_NOP (which means 'let').
4632               */               */
             emitIFEQ = JS_TRUE;  
4633              op = JSOP_SETNAME;              op = JSOP_SETNAME;
4634              switch (type) {              switch (type) {
4635  #if JS_HAS_BLOCK_SCOPE  #if JS_HAS_BLOCK_SCOPE
# Line 4301  Line 4650 
4650  #else  #else
4651                  JS_ASSERT(pn3->pn_type == TOK_NAME);                  JS_ASSERT(pn3->pn_type == TOK_NAME);
4652  #endif  #endif
4653                    /* FALL THROUGH */
4654    
4655                  case TOK_NAME:
4656                  /*                  /*
4657                   * Always annotate JSOP_FORLOCAL if given input of the form                   * Always annotate JSOP_FORLOCAL if given input of the form
4658                   * 'for (let x in * o)' -- the decompiler must not hoist the                   * 'for (let x in * o)' -- the decompiler must not hoist the
4659                   * 'let x' out of the loop head, or x will be bound in the                   * 'let x' out of the loop head, or x will be bound in the
4660                   * wrong scope.  Likewise, but in this case only for the sake                   * wrong scope.  Likewise, but in this case only for the sake
4661                   * of higher decompilation fidelity only, do not hoist 'var x'                   * of higher decompilation fidelity only, do not hoist 'var x'
4662                   * when given 'for (var x in o)'.  But 'for (var x = i in o)'                   * when given 'for (var x in o)'.
                  * requires hoisting in order to preserve the initializer i.  
                  * The decompiler can only handle so much!  
4663                   */                   */
4664                  if ((                  if ((
4665  #if JS_HAS_BLOCK_SCOPE  #if JS_HAS_BLOCK_SCOPE
4666                       type == TOK_LET ||                       type == TOK_LET ||
4667  #endif  #endif
4668                       !pn3->pn_expr) &&                       (type == TOK_VAR && !pn3->maybeExpr())) &&
4669                      js_NewSrcNote2(cx, cg, SRC_DECL,                      js_NewSrcNote2(cx, cg, SRC_DECL,
4670                                     type == TOK_VAR                                     (type == TOK_VAR)
4671                                     ? SRC_DECL_VAR                                     ? SRC_DECL_VAR
4672                                     : SRC_DECL_LET) < 0) {                                     : SRC_DECL_LET) < 0) {
4673                      return JS_FALSE;                      return JS_FALSE;
4674                  }                  }
4675                  /* FALL THROUGH */                  if (pn3->pn_cookie != FREE_UPVAR_COOKIE) {
               case TOK_NAME:  
                 if (pn3->pn_slot >= 0) {  
4676                      op = PN_OP(pn3);                      op = PN_OP(pn3);
4677                      switch (op) {                      switch (op) {
4678                        case JSOP_GETARG:   /* FALL THROUGH */                        case JSOP_GETARG:   /* FALL THROUGH */
# Line 4341  Line 4689 
4689                          return JS_FALSE;                          return JS_FALSE;
4690                      op = PN_OP(pn3);                      op = PN_OP(pn3);
4691                  }                  }
4692                  if (pn3->pn_slot >= 0) {                  if (pn3->isConst()) {
4693                      if (pn3->pn_const) {                      js_ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR,
4694                          JS_ASSERT(op == JSOP_FORLOCAL);                                                  JSMSG_BAD_FOR_LEFTSIDE);
4695                          op = JSOP_FORCONST;                      return JS_FALSE;
4696                      }                  }
4697                      atomIndex = (jsatomid) pn3->pn_slot;                  if (pn3->pn_cookie != FREE_UPVAR_COOKIE) {
4698                        atomIndex = (jsatomid) pn3->pn_cookie;
4699                      EMIT_UINT16_IMM_OP(op, atomIndex);                      EMIT_UINT16_IMM_OP(op, atomIndex);
4700                  } else {                  } else {
4701                      if (!EmitAtomOp(cx, pn3, op, cg))                      if (!EmitAtomOp(cx, pn3, op, cg))
# Line 4355  Line 4704 
4704                  break;                  break;
4705    
4706                case TOK_DOT:                case TOK_DOT:
4707                    /*
4708                     * 'for (o.p in q)' can use JSOP_FORPROP only if evaluating 'o'
4709                     * has no side effects.
4710                     */
4711                  useful = JS_FALSE;                  useful = JS_FALSE;
4712                  if (!CheckSideEffects(cx, cg, pn3->pn_expr, &useful))                  if (!CheckSideEffects(cx, cg, pn3->expr(), &useful))
4713                      return JS_FALSE;                      return JS_FALSE;
4714                  if (!useful) {                  if (!useful) {
4715                      if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE))                      if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE))
# Line 4366  Line 4719 
4719                  /* FALL THROUGH */                  /* FALL THROUGH */
4720    
4721  #if JS_HAS_DESTRUCTURING  #if JS_HAS_DESTRUCTURING
               case TOK_RB:  
               case TOK_RC:  
4722                destructuring_for:                destructuring_for:
4723  #endif  #endif
4724  #if JS_HAS_XML_SUPPORT                default:
               case TOK_UNARYOP:  
 #endif  
 #if JS_HAS_LVALUE_RETURN  
               case TOK_LP:  
 #endif  
               case TOK_LB:  
                 /*  
                  * We separate the first/next bytecode from the enumerator  
                  * variable binding to avoid any side-effects in the index  
                  * expression (e.g., for (x[i++] in {}) should not bind x[i]  
                  * or increment i at all).  
                  */  
                 emitIFEQ = JS_FALSE;  
4725                  if (js_Emit1(cx, cg, JSOP_FORELEM) < 0)                  if (js_Emit1(cx, cg, JSOP_FORELEM) < 0)
4726                      return JS_FALSE;                      return JS_FALSE;
4727                    JS_ASSERT(cg->stackDepth >= 3);
                 /*  
                  * Emit a SRC_WHILE note with offset telling the distance to  
                  * the loop-closing jump (we can't reckon from the branch at  
                  * the top of the loop, because the loop-closing jump might  
                  * need to be an extended jump, independent of whether the  
                  * branch is short or long).  
                  */  
                 noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);  
                 if (noteIndex < 0)  
                     return JS_FALSE;  
                 beq = EmitJump(cx, cg, JSOP_IFEQ, 0);  
                 if (beq < 0)  
                     return JS_FALSE;  
4728    
4729  #if JS_HAS_DESTRUCTURING  #if JS_HAS_DESTRUCTURING
4730                  if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) {                  if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) {
# Line 4407  Line 4732 
4732                          return JS_FALSE;                          return JS_FALSE;
4733                      if (js_Emit1(cx, cg, JSOP_POP) < 0)                      if (js_Emit1(cx, cg, JSOP_POP) < 0)
4734                          return JS_FALSE;                          return JS_FALSE;
4735                      break;                  } else
                 }  
4736  #endif  #endif
4737  #if JS_HAS_LVALUE_RETURN  #if JS_HAS_LVALUE_RETURN
4738                  if (pn3->pn_type == TOK_LP) {                  if (pn3->pn_type == TOK_LP) {
# Line 4417  Line 4741 
4741                          return JS_FALSE;                          return JS_FALSE;
4742                      if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)                      if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)
4743                          return JS_FALSE;                          return JS_FALSE;
4744                      break;                  } else
                 }  
4745  #endif  #endif
4746  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
4747                  if (pn3->pn_type == TOK_UNARYOP) {                  if (pn3->pn_type == TOK_UNARYOP) {
# Line 4427  Line 4750 
4750                          return JS_FALSE;                          return JS_FALSE;
4751                      if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)                      if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)
4752                          return JS_FALSE;                          return JS_FALSE;
4753                      break;                  } else
                 }  
4754  #endif  #endif
   
                 /* Now that we're safely past the IFEQ, commit side effects. */  
4755                  if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))                  if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))
4756                      return JS_FALSE;                      return JS_FALSE;
4757                  break;                  break;
   
               default:  
                 JS_ASSERT(0);  
4758              }              }
4759    
4760              if (emitIFEQ) {              /* The stack should be balanced around the JSOP_FOR* opcode sequence. */
4761                  /* Annotate so the decompiler can find the loop-closing jump. */              JS_ASSERT(cg->stackDepth == loopDepth);
                 noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);  
                 if (noteIndex < 0)  
                     return JS_FALSE;  
4762    
4763                  /* Pop and test the loop condition generated by JSOP_FOR*. */              /* Set the first srcnote offset so we can find the start of the loop body. */
4764                  beq = EmitJump(cx, cg, JSOP_IFEQ, 0);              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, CG_OFFSET(cg) - jmp))
4765                  if (beq < 0)                  return JS_FALSE;
                     return JS_FALSE;  
             }  
4766    
4767              /* Emit code for the loop body. */              /* Emit code for the loop body. */
4768              if (!js_EmitTree(cx, cg, pn->pn_right))              if (!js_EmitTree(cx, cg, pn->pn_right))
4769                  return JS_FALSE;                  return JS_FALSE;
4770    
4771              /* Emit the loop-closing jump and fixup all jump offsets. */              /* Set loop and enclosing "update" offsets, for continue. */
4772              jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg));              stmt = &stmtInfo;
4773              if (jmp < 0)              do {
4774                    stmt->update = CG_OFFSET(cg);
4775                } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
4776    
4777                /*
4778                 * Fixup the goto that starts the loop to jump down to JSOP_NEXTITER.
4779                 */
4780                CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
4781                if (js_Emit1(cx, cg, JSOP_NEXTITER) < 0)
4782                    return JS_FALSE;
4783                beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
4784                if (beq < 0)
4785                  return JS_FALSE;                  return JS_FALSE;
             if (beq > 0)  
                 CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);  
4786    
4787              /* Set the SRC_WHILE note offset so we can find the closing jump. */              /* Set the second srcnote offset so we can find the closing jump. */
4788              JS_ASSERT(noteIndex != -1);              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp))
             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, jmp - beq))  
4789                  return JS_FALSE;                  return JS_FALSE;
4790          } else {          } else {
4791              /* C-style for (init; cond; update) ... loop. */              /* C-style for (init; cond; update) ... loop. */
# Line 4475  Line 4795 
4795                  /* No initializer: emit an annotated nop for the decompiler. */                  /* No initializer: emit an annotated nop for the decompiler. */
4796                  op = JSOP_NOP;                  op = JSOP_NOP;
4797              } else {              } else {
4798                  cg->treeContext.flags |= TCF_IN_FOR_INIT;                  cg->flags |= TCF_IN_FOR_INIT;
4799  #if JS_HAS_DESTRUCTURING  #if JS_HAS_DESTRUCTURING
4800                  if (pn3->pn_type == TOK_ASSIGN &&                  if (pn3->pn_type == TOK_ASSIGN &&
4801                      !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {                      !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
# Line 4493  Line 4813 
4813                           * just for the decompiler.                           * just for the decompiler.
4814                           */                           */
4815                          JS_ASSERT(pn3->pn_arity == PN_LIST);                          JS_ASSERT(pn3->pn_arity == PN_LIST);
4816                          if (pn3->pn_extra & PNX_GROUPINIT)                          if (pn3->pn_xflags & PNX_GROUPINIT)
4817                              op = JSOP_NOP;                              op = JSOP_NOP;
4818                      }                      }
4819                  }                  }
4820                  cg->treeContext.flags &= ~TCF_IN_FOR_INIT;                  cg->flags &= ~TCF_IN_FOR_INIT;
4821              }              }
4822    
4823                /*
4824                 * NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH).
4825                 * Use tmp to hold the biased srcnote "top" offset, which differs
4826                 * from the top local variable by the length of the JSOP_GOTO{,X}
4827                 * emitted in between tmp and top if this loop has a condition.
4828                 */
4829              noteIndex = js_NewSrcNote(cx, cg, SRC_FOR);              noteIndex = js_NewSrcNote(cx, cg, SRC_FOR);
4830              if (noteIndex < 0 ||              if (noteIndex < 0 || js_Emit1(cx, cg, op) < 0)
                 js_Emit1(cx, cg, op) < 0) {  
4831                  return JS_FALSE;                  return JS_FALSE;
4832              }              tmp = CG_OFFSET(cg);
4833    
4834              if (pn2->pn_kid2) {              if (pn2->pn_kid2) {
4835                  /* Goto the loop condition, which branches back to iterate. */                  /* Goto the loop condition, which branches back to iterate. */
# Line 4511  Line 4837 
4837                  if (jmp < 0)                  if (jmp < 0)
4838                      return JS_FALSE;                      return JS_FALSE;
4839              }              }
4840    
4841              top = CG_OFFSET(cg);              top = CG_OFFSET(cg);
4842              SET_STATEMENT_TOP(&stmtInfo, top);              SET_STATEMENT_TOP(&stmtInfo, top);
4843    
4844              /* Emit code for the loop body. */              /* Emit code for the loop body. */
4845                if (!js_Emit1(cx, cg, JSOP_LOOP))
4846                    return JS_FALSE;
4847              if (!js_EmitTree(cx, cg, pn->pn_right))              if (!js_EmitTree(cx, cg, pn->pn_right))
4848                  return JS_FALSE;                  return JS_FALSE;
4849    
4850              /* Set the second note offset so we can find the update part. */              /* Set the second note offset so we can find the update part. */
4851              JS_ASSERT(noteIndex != -1);              JS_ASSERT(noteIndex != -1);
4852              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,
4853                                       CG_OFFSET(cg) - top)) {                                       CG_OFFSET(cg) - tmp)) {
4854                  return JS_FALSE;                  return JS_FALSE;
4855              }              }
4856    
# Line 4541  Line 4870 
4870                      return JS_FALSE;                      return JS_FALSE;
4871                  }                  }
4872  #endif  #endif
4873                  if (op == JSOP_POP) {                  if (op == JSOP_POP && !js_EmitTree(cx, cg, pn3))
4874                      if (!js_EmitTree(cx, cg, pn3))                      return JS_FALSE;
4875                          return JS_FALSE;  
4876                      if (js_Emit1(cx, cg, op) < 0)                  /* Always emit the POP or NOP, to help the decompiler. */
4877                          return JS_FALSE;                  if (js_Emit1(cx, cg, op) < 0)
4878                  }                      return JS_FALSE;
4879    
4880                  /* Restore the absolute line number for source note readers. */                  /* Restore the absolute line number for source note readers. */
4881                  off = (ptrdiff_t) pn->pn_pos.end.lineno;                  off = (ptrdiff_t) pn->pn_pos.end.lineno;
# Line 4559  Line 4888 
4888    
4889              /* Set the first note offset so we can find the loop condition. */              /* Set the first note offset so we can find the loop condition. */
4890              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
4891                                       CG_OFFSET(cg) - top)) {                                       CG_OFFSET(cg) - tmp)) {
4892                  return JS_FALSE;                  return JS_FALSE;
4893              }              }
4894    
# Line 4574  Line 4903 
4903    
4904              /* The third note offset helps us find the loop-closing jump. */              /* The third note offset helps us find the loop-closing jump. */
4905              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2,              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2,
4906                                       CG_OFFSET(cg) - top)) {                                       CG_OFFSET(cg) - tmp)) {
4907                  return JS_FALSE;                  return JS_FALSE;
4908              }              }
4909    
# Line 4596  Line 4925 
4925    
4926          if (pn2->pn_type == TOK_IN) {          if (pn2->pn_type == TOK_IN) {
4927              /*              /*
4928               * JSOP_ENDITER needs a slot to save an exception thrown from the               * JSOP_ENDITER must have a slot to save an exception thrown from
4929               * body of for-in loop when closing the iterator object.               * the body of for-in loop when closing the iterator object, and
4930                 * fortunately it does: the slot that was set by JSOP_NEXTITER to
4931                 * the return value of iterator.next().
4932               */               */
4933              JS_ASSERT(js_CodeSpec[JSOP_ENDITER].format & JOF_TMPSLOT);              JS_ASSERT(js_CodeSpec[JSOP_ENDITER].nuses == 2);
4934              if (!NewTryNote(cx, cg, JSTN_ITER, cg->stackDepth, top,              if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) ||
                             CG_OFFSET(cg)) ||  
4935                  js_Emit1(cx, cg, JSOP_ENDITER) < 0) {                  js_Emit1(cx, cg, JSOP_ENDITER) < 0) {
4936                  return JS_FALSE;                  return JS_FALSE;
4937              }              }
# Line 4609  Line 4939 
4939          break;          break;
4940    
4941        case TOK_BREAK:        case TOK_BREAK:
4942          stmt = cg->treeContext.topStmt;          stmt = cg->topStmt;
4943          atom = pn->pn_atom;          atom = pn->pn_atom;
4944          if (atom) {          if (atom) {
4945              ale = js_IndexAtom(cx, atom, &cg->atomList);              ale = cg->atomList.add(cg->compiler, atom);
4946              if (!ale)              if (!ale)
4947                  return JS_FALSE;                  return JS_FALSE;
4948              while (stmt->type != STMT_LABEL || stmt->u.label != atom)              while (stmt->type != STMT_LABEL || stmt->label != atom)
4949                  stmt = stmt->down;                  stmt = stmt->down;
4950              noteType = SRC_BREAK2LABEL;              noteType = SRC_BREAK2LABEL;
4951          } else {          } else {
# Line 4630  Line 4960 
4960          break;          break;
4961    
4962        case TOK_CONTINUE:        case TOK_CONTINUE:
4963          stmt = cg->treeContext.topStmt;          stmt = cg->topStmt;
4964          atom = pn->pn_atom;          atom = pn->pn_atom;
4965          if (atom) {          if (atom) {
4966              /* Find the loop statement enclosed by the matching label. */              /* Find the loop statement enclosed by the matching label. */
4967              JSStmtInfo *loop = NULL;              JSStmtInfo *loop = NULL;
4968              ale = js_IndexAtom(cx, atom, &cg->atomList);              ale = cg->atomList.add(cg->compiler, atom);
4969              if (!ale)              if (!ale)
4970                  return JS_FALSE;                  return JS_FALSE;
4971              while (stmt->type != STMT_LABEL || stmt->u.label != atom) {              while (stmt->type != STMT_LABEL || stmt->label != atom) {
4972                  if (STMT_IS_LOOP(stmt))                  if (STMT_IS_LOOP(stmt))
4973                      loop = stmt;                      loop = stmt;
4974                  stmt = stmt->down;                  stmt = stmt->down;
# Line 4659  Line 4989 
4989        case TOK_WITH:        case TOK_WITH:
4990          if (!js_EmitTree(cx, cg, pn->pn_left))          if (!js_EmitTree(cx, cg, pn->pn_left))
4991              return JS_FALSE;              return JS_FALSE;
4992          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_WITH, CG_OFFSET(cg));          js_PushStatement(cg, &stmtInfo, STMT_WITH, CG_OFFSET(cg));
4993          if (js_Emit1(cx, cg, JSOP_ENTERWITH) < 0)          if (js_Emit1(cx, cg, JSOP_ENTERWITH) < 0)
4994              return JS_FALSE;              return JS_FALSE;
4995          if (!js_EmitTree(cx, cg, pn->pn_right))          if (!js_EmitTree(cx, cg, pn->pn_right))
# Line 4681  Line 5011 
5011           * Push stmtInfo to track jumps-over-catches and gosubs-to-finally           * Push stmtInfo to track jumps-over-catches and gosubs-to-finally
5012           * for later fixup.           * for later fixup.
5013           *           *
5014           * When a finally block is 'active' (STMT_FINALLY on the treeContext),           * When a finally block is active (STMT_FINALLY in our tree context),
5015           * non-local jumps (including jumps-over-catches) result in a GOSUB           * non-local jumps (including jumps-over-catches) result in a GOSUB
5016           * being written into the bytecode stream and fixed-up later (c.f.           * being written into the bytecode stream and fixed-up later (c.f.
5017           * EmitBackPatchOp and BackPatch).           * EmitBackPatchOp and BackPatch).
5018           */           */
5019          js_PushStatement(&cg->treeContext, &stmtInfo,          js_PushStatement(cg, &stmtInfo,
5020                           pn->pn_kid3 ? STMT_FINALLY : STMT_TRY,                           pn->pn_kid3 ? STMT_FINALLY : STMT_TRY,
5021                           CG_OFFSET(cg));                           CG_OFFSET(cg));
5022    
# Line 4805  Line 5135 
5135                   * guardJump at the next catch (the guard mismatch case).                   * guardJump at the next catch (the guard mismatch case).
5136                   */                   */
5137                  JS_ASSERT(pn3->pn_type == TOK_LEXICALSCOPE);                  JS_ASSERT(pn3->pn_type == TOK_LEXICALSCOPE);
5138                  count = OBJ_BLOCK_COUNT(cx, pn3->pn_pob->object);                  count = OBJ_BLOCK_COUNT(cx, pn3->pn_objbox->object);
5139                  if (!js_EmitTree(cx, cg, pn3))                  if (!js_EmitTree(cx, cg, pn3))
5140                      return JS_FALSE;                      return JS_FALSE;
5141    
# Line 4832  Line 5162 
5162                   * Save a pointer to the last catch node to handle try-finally                   * Save a pointer to the last catch node to handle try-finally
5163                   * and try-catch(guard)-finally special cases.                   * and try-catch(guard)-finally special cases.
5164                   */                   */
5165                  lastCatch = pn3->pn_expr;                  lastCatch = pn3->expr();
5166              }              }
5167          }          }
5168    
# Line 4875  Line 5205 
5205    
5206              /* Indicate that we're emitting a subroutine body. */              /* Indicate that we're emitting a subroutine body. */
5207              stmtInfo.type = STMT_SUBROUTINE;              stmtInfo.type = STMT_SUBROUTINE;
5208              if (!UpdateLineNumberNotes(cx, cg, pn->pn_kid3))              if (!UpdateLineNumberNotes(cx, cg, pn->pn_kid3->pn_pos.begin.lineno))
5209                  return JS_FALSE;                  return JS_FALSE;
5210              if (js_Emit1(cx, cg, JSOP_FINALLY) < 0 ||              if (js_Emit1(cx, cg, JSOP_FINALLY) < 0 ||
5211                  !js_EmitTree(cx, cg, pn->pn_kid3) ||                  !js_EmitTree(cx, cg, pn->pn_kid3) ||
# Line 4901  Line 5231 
5231           * (first to last for a given nesting level, inner to outer by level).           * (first to last for a given nesting level, inner to outer by level).
5232           */           */
5233          if (pn->pn_kid2 &&          if (pn->pn_kid2 &&
5234              !NewTryNote(cx, cg, JSTN_CATCH, depth, tryStart, tryEnd)) {              !NewTryNote(cx, cg, JSTRY_CATCH, depth, tryStart, tryEnd)) {
5235              return JS_FALSE;              return JS_FALSE;
5236          }          }
5237    
# Line 4911  Line 5241 
5241           * for the try{}finally{} case.           * for the try{}finally{} case.
5242           */           */
5243          if (pn->pn_kid3 &&          if (pn->pn_kid3 &&
5244              !NewTryNote(cx, cg, JSTN_FINALLY, depth, tryStart, finallyStart)) {              !NewTryNote(cx, cg, JSTRY_FINALLY, depth, tryStart, finallyStart)) {
5245              return JS_FALSE;              return JS_FALSE;
5246          }          }
5247          break;          break;
# Line 4926  Line 5256 
5256           * Morph STMT_BLOCK to STMT_CATCH, note the block entry code offset,           * Morph STMT_BLOCK to STMT_CATCH, note the block entry code offset,
5257           * and save the block object atom.           * and save the block object atom.
5258           */           */
5259          stmt = cg->treeContext.topStmt;          stmt = cg->topStmt;
5260          JS_ASSERT(stmt->type == STMT_BLOCK && (stmt->flags & SIF_SCOPE));          JS_ASSERT(stmt->type == STMT_BLOCK && (stmt->flags & SIF_SCOPE));
5261          stmt->type = STMT_CATCH;          stmt->type = STMT_CATCH;
5262          catchStart = stmt->update;          catchStart = stmt->update;
5263          blockObj = stmt->u.blockObj;          blockObj = stmt->blockObj;
5264    
5265          /* Go up one statement info record to the TRY or FINALLY record. */          /* Go up one statement info record to the TRY or FINALLY record. */
5266          stmt = stmt->down;          stmt = stmt->down;
# Line 4960  Line 5290 
5290  #endif  #endif
5291    
5292            case TOK_NAME:            case TOK_NAME:
5293              /* Inline BindNameToSlot for pn2. */              /* Inline and specialize BindNameToSlot for pn2. */
5294              JS_ASSERT(pn2->pn_slot == -1);              JS_ASSERT(pn2->pn_cookie != FREE_UPVAR_COOKIE);
5295              pn2->pn_slot = AdjustBlockSlot(cx, cg,              EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, pn2->pn_cookie);
                                            OBJ_BLOCK_DEPTH(cx, blockObj));  
             if (pn2->pn_slot < 0)  
                 return JS_FALSE;  
             EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, pn2->pn_slot);  
5296              break;              break;
5297    
5298            default:            default:
# Line 5047  Line 5373 
5373    
5374  #if JS_HAS_GENERATORS  #if JS_HAS_GENERATORS
5375        case TOK_YIELD:        case TOK_YIELD:
5376          if (!(cg->treeContext.flags & TCF_IN_FUNCTION)) {          if (!(cg->flags & TCF_IN_FUNCTION)) {
5377              js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR,              js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR,
5378                                          JSMSG_BAD_RETURN_OR_YIELD,                                          JSMSG_BAD_RETURN_OR_YIELD,
5379                                          js_yield_str);                                          js_yield_str);
# Line 5068  Line 5394 
5394  #endif  #endif
5395    
5396        case TOK_LC:        case TOK_LC:
5397          {
5398  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
5399          if (pn->pn_arity == PN_UNARY) {          if (pn->pn_arity == PN_UNARY) {
5400              if (!js_EmitTree(cx, cg, pn->pn_kid))              if (!js_EmitTree(cx, cg, pn->pn_kid))
# Line 5082  Line 5409 
5409    
5410          noteIndex = -1;          noteIndex = -1;
5411          tmp = CG_OFFSET(cg);          tmp = CG_OFFSET(cg);
5412          if (pn->pn_extra & PNX_NEEDBRACES) {          if (pn->pn_xflags & PNX_NEEDBRACES) {
5413              noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0);              noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0);
5414              if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0)              if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0)
5415                  return JS_FALSE;                  return JS_FALSE;
5416          }          }
5417    
5418          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_BLOCK, top);          js_PushStatement(cg, &stmtInfo, STMT_BLOCK, top);
5419          if (pn->pn_extra & PNX_FUNCDEFS) {  
5420            JSParseNode *pnchild = pn->pn_head;
5421            if (pn->pn_xflags & PNX_FUNCDEFS) {
5422              /*              /*
5423               * This block contains top-level function definitions. To ensure               * This block contains top-level function definitions. To ensure
5424               * that we emit the bytecode defining them prior the rest of code               * that we emit the bytecode defining them before the rest of code
5425               * in the block we use a separate pass over functions. During the               * in the block we use a separate pass over functions. During the
5426               * main pass later the emitter will add JSOP_NOP with source notes               * main pass later the emitter will add JSOP_NOP with source notes
5427               * for the function to preserve the original functions position               * for the function to preserve the original functions position
# Line 5101  Line 5430 
5430               * Currently this is used only for functions, as compile-as-we go               * Currently this is used only for functions, as compile-as-we go
5431               * mode for scripts does not allow separate emitter passes.               * mode for scripts does not allow separate emitter passes.
5432               */               */
5433              JS_ASSERT(cg->treeContext.flags & TCF_IN_FUNCTION);              JS_ASSERT(cg->flags & TCF_IN_FUNCTION);
5434              for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {              if (pn->pn_xflags & PNX_DESTRUCT) {
5435                    /*
5436                     * Assign the destructuring arguments before defining any
5437                     * functions, see bug 419662.
5438                     */
5439                    JS_ASSERT(pnchild->pn_type == TOK_SEMI);
5440                    JS_ASSERT(pnchild->pn_kid->pn_type == TOK_COMMA);
5441                    if (!js_EmitTree(cx, cg, pnchild))
5442                        return JS_FALSE;
5443                    pnchild = pnchild->pn_next;
5444                }
5445    
5446                for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
5447                  if (pn2->pn_type == TOK_FUNCTION) {                  if (pn2->pn_type == TOK_FUNCTION) {
5448                      if (pn2->pn_op == JSOP_NOP) {                      if (pn2->pn_op == JSOP_NOP) {
5449                          if (!js_EmitTree(cx, cg, pn2))                          if (!js_EmitTree(cx, cg, pn2))
# Line 5119  Line 5460 
5460                  }                  }
5461              }              }
5462          }          }
5463          for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {          for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
5464              if (!js_EmitTree(cx, cg, pn2))              if (!js_EmitTree(cx, cg, pn2))
5465                  return JS_FALSE;                  return JS_FALSE;
5466          }          }
# Line 5132  Line 5473 
5473    
5474          ok = js_PopStatementCG(cx, cg);          ok = js_PopStatementCG(cx, cg);
5475          break;          break;
5476          }
5477    
5478        case TOK_BODY:        case TOK_SEQ:
5479          JS_ASSERT(pn->pn_arity == PN_LIST);          JS_ASSERT(pn->pn_arity == PN_LIST);
5480          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_BODY, top);          js_PushStatement(cg, &stmtInfo, STMT_SEQ, top);
5481          for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {          for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
5482              if (!js_EmitTree(cx, cg, pn2))              if (!js_EmitTree(cx, cg, pn2))
5483                  return JS_FALSE;                  return JS_FALSE;
# Line 5155  Line 5497 
5497               * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when               * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
5498               * calling JS_Compile* to suppress JSOP_POPV.               * calling JS_Compile* to suppress JSOP_POPV.
5499               */               */
5500              useful = wantval =              useful = wantval = !(cg->flags & (TCF_IN_FUNCTION | TCF_NO_SCRIPT_RVAL));
                 !(cg->treeContext.flags & (TCF_IN_FUNCTION | TCF_NO_SCRIPT_RVAL));  
5501              if (!useful) {              if (!useful) {
5502                  if (!CheckSideEffects(cx, cg, pn2, &useful))                  if (!CheckSideEffects(cx, cg, pn2, &useful))
5503                      return JS_FALSE;                      return JS_FALSE;
# Line 5169  Line 5510 
5510               * labeled compound statement.               * labeled compound statement.
5511               */               */
5512              if (!useful &&              if (!useful &&
5513                  (!cg->treeContext.topStmt ||                  (!cg->topStmt ||
5514                   cg->treeContext.topStmt->type != STMT_LABEL ||                   cg->topStmt->type != STMT_LABEL ||
5515                   cg->treeContext.topStmt->update < CG_OFFSET(cg))) {                   cg->topStmt->update < CG_OFFSET(cg))) {
5516                  CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno;                  CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno;
5517                  if (!js_ReportCompileErrorNumber(cx, CG_TS(cg), pn2,                  if (!js_ReportCompileErrorNumber(cx, CG_TS(cg), pn2,
5518                                                   JSREPORT_WARNING |                                                   JSREPORT_WARNING |
# Line 5201  Line 5542 
5542        case TOK_COLON:        case TOK_COLON:
5543          /* Emit an annotated nop so we know to decompile a label. */          /* Emit an annotated nop so we know to decompile a label. */
5544          atom = pn->pn_atom;          atom = pn->pn_atom;
5545          ale = js_IndexAtom(cx, atom, &cg->atomList);          ale = cg->atomList.add(cg->compiler, atom);
5546          if (!ale)          if (!ale)
5547              return JS_FALSE;              return JS_FALSE;
5548          pn2 = pn->pn_expr;          pn2 = pn->expr();
5549          noteType = (pn2->pn_type == TOK_LC ||          noteType = (pn2->pn_type == TOK_LC ||
5550                      (pn2->pn_type == TOK_LEXICALSCOPE &&                      (pn2->pn_type == TOK_LEXICALSCOPE &&
5551                       pn2->pn_expr->pn_type == TOK_LC))                       pn2->expr()->pn_type == TOK_LC))
5552                     ? SRC_LABELBRACE                     ? SRC_LABELBRACE
5553                     : SRC_LABEL;                     : SRC_LABEL;
5554          noteIndex = js_NewSrcNote2(cx, cg, noteType,          noteIndex = js_NewSrcNote2(cx, cg, noteType,
# Line 5218  Line 5559 
5559          }          }
5560    
5561          /* Emit code for the labeled statement. */          /* Emit code for the labeled statement. */
5562          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_LABEL,          js_PushStatement(cg, &stmtInfo, STMT_LABEL, CG_OFFSET(cg));
5563                           CG_OFFSET(cg));          stmtInfo.label = atom;
         stmtInfo.u.label = atom;  
5564          if (!js_EmitTree(cx, cg, pn2))          if (!js_EmitTree(cx, cg, pn2))
5565              return JS_FALSE;              return JS_FALSE;
5566          if (!js_PopStatementCG(cx, cg))          if (!js_PopStatementCG(cx, cg))
# Line 5274  Line 5614 
5614            case TOK_NAME:            case TOK_NAME:
5615              if (!BindNameToSlot(cx, cg, pn2))              if (!BindNameToSlot(cx, cg, pn2))
5616                  return JS_FALSE;                  return JS_FALSE;
5617              if (pn2->pn_slot >= 0) {              if (pn2->pn_cookie != FREE_UPVAR_COOKIE) {
5618                  atomIndex = (jsatomid) pn2->pn_slot;                  atomIndex = (jsatomid) pn2->pn_cookie;
5619              } else {              } else {
5620                  ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);                  ale = cg->atomList.add(cg->compiler, pn2->pn_atom);
5621                  if (!ale)                  if (!ale)
5622                      return JS_FALSE;                      return JS_FALSE;
5623                  atomIndex = ALE_INDEX(ale);                  atomIndex = ALE_INDEX(ale);
5624                  EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);                  if (!pn2->isConst())
5625                        EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
5626              }              }
5627              break;              break;
5628            case TOK_DOT:            case TOK_DOT:
5629              if (!js_EmitTree(cx, cg, pn2->pn_expr))              if (!js_EmitTree(cx, cg, pn2->expr()))
5630                  return JS_FALSE;                  return JS_FALSE;
5631              ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);              ale = cg->atomList.add(cg->compiler, pn2->pn_atom);
5632              if (!ale)              if (!ale)
5633                  return JS_FALSE;                  return JS_FALSE;
5634              atomIndex = ALE_INDEX(ale);              atomIndex = ALE_INDEX(ale);
# Line 5332  Line 5673 
5673                   * supported.                   * supported.
5674                   */                   */
5675                  js_ReportCompileErrorNumber(cx,                  js_ReportCompileErrorNumber(cx,
5676                                              TS(cg->treeContext.parseContext),                                              TS(cg->compiler),
5677                                              pn2, JSREPORT_ERROR,                                              pn2, JSREPORT_ERROR,
5678                                              JSMSG_BAD_GETTER_OR_SETTER,                                              JSMSG_BAD_GETTER_OR_SETTER,
5679                                              (op == JSOP_GETTER)                                              (op == JSOP_GETTER)
# Line 5348  Line 5689 
5689          if (op != JSOP_NOP) {          if (op != JSOP_NOP) {
5690              switch (pn2->pn_type) {              switch (pn2->pn_type) {
5691                case TOK_NAME:                case TOK_NAME:
5692                  if (pn2->pn_op != JSOP_SETNAME) {                  if (pn2->isConst()) {
5693                      EMIT_UINT16_IMM_OP((pn2->pn_op == JSOP_SETGVAR)                      if (PN_OP(pn2) == JSOP_CALLEE) {
5694                            if (js_Emit1(cx, cg, JSOP_CALLEE) < 0)
5695                                return JS_FALSE;
5696                        } else {
5697                            EMIT_INDEX_OP(PN_OP(pn2), atomIndex);
5698                        }
5699                    } else if (PN_OP(pn2) == JSOP_SETNAME) {
5700                        if (js_Emit1(cx, cg, JSOP_DUP) < 0)
5701                            return JS_FALSE;
5702                        EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex);
5703                    } else {
5704                        EMIT_UINT16_IMM_OP((PN_OP(pn2) == JSOP_SETGVAR)
5705                                         ? JSOP_GETGVAR                                         ? JSOP_GETGVAR
5706                                         : (pn2->pn_op == JSOP_SETARG)                                         : (PN_OP(pn2) == JSOP_GETUPVAR)
5707                                           ? JSOP_GETUPVAR
5708                                           : (PN_OP(pn2) == JSOP_SETARG)
5709                                         ? JSOP_GETARG                                         ? JSOP_GETARG
5710                                         : JSOP_GETLOCAL,                                         : JSOP_GETLOCAL,
5711                                         atomIndex);                                         atomIndex);
                     break;  
5712                  }                  }
                 if (js_Emit1(cx, cg, JSOP_DUP) < 0)  
                     return JS_FALSE;  
                 EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex);  
5713                  break;                  break;
5714                case TOK_DOT:                case TOK_DOT:
5715                  if (js_Emit1(cx, cg, JSOP_DUP) < 0)                  if (js_Emit1(cx, cg, JSOP_DUP) < 0)
# Line 5367  Line 5717 
5717                  if (pn2->pn_atom == cx->runtime->atomState.lengthAtom) {                  if (pn2->pn_atom == cx->runtime->atomState.lengthAtom) {
5718                      if (js_Emit1(cx, cg, JSOP_LENGTH) < 0)                      if (js_Emit1(cx, cg, JSOP_LENGTH) < 0)
5719                          return JS_FALSE;                          return JS_FALSE;
5720                    } else if (pn2->pn_atom == cx->runtime->atomState.protoAtom) {
5721                        if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, cg))
5722                            return JS_FALSE;
5723                        if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
5724                            return JS_FALSE;
5725                  } else {                  } else {
5726                      EMIT_INDEX_OP(JSOP_GETPROP, atomIndex);                      EMIT_INDEX_OP(JSOP_GETPROP, atomIndex);
5727                  }                  }
# Line 5394  Line 5749 
5749          /* If += etc., emit the binary operator with a decompiler note. */          /* If += etc., emit the binary operator with a decompiler note. */
5750          if (op != JSOP_NOP) {          if (op != JSOP_NOP) {
5751              /*              /*
5752               * Take care to avoid SRC_ASSIGNOP if the left-hand side is a               * Take care to avoid SRC_ASSIGNOP if the left-hand side is a const
5753               * const declared in a function (i.e., with non-negative pn_slot               * declared in the current compilation unit, as in this case (just
5754               * and when pn_const is true), as in this case (just a bit further               * a bit further below) we will avoid emitting the assignment op.
5755               * below) we will avoid emitting the assignment op.               */
5756               */              if (pn2->pn_type != TOK_NAME || !pn2->isConst()) {
             if (pn2->pn_type != TOK_NAME ||  
                 pn2->pn_slot < 0 ||  
                 !pn2->pn_const) {  
5757                  if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0)                  if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0)
5758                      return JS_FALSE;                      return JS_FALSE;
5759              }              }
# Line 5422  Line 5774 
5774          /* Finally, emit the specialized assignment bytecode. */          /* Finally, emit the specialized assignment bytecode. */
5775          switch (pn2->pn_type) {          switch (pn2->pn_type) {
5776            case TOK_NAME:            case TOK_NAME:
5777              if (pn2->pn_slot >= 0) {              if (pn2->isConst())
                 if (!pn2->pn_const)  
                     EMIT_UINT16_IMM_OP(PN_OP(pn2), atomIndex);  
5778                  break;                  break;
             }  
5779              /* FALL THROUGH */              /* FALL THROUGH */
5780            case TOK_DOT:            case TOK_DOT:
5781              EMIT_INDEX_OP(PN_OP(pn2), atomIndex);              EMIT_INDEX_OP(PN_OP(pn2), atomIndex);
# Line 5588  Line 5937 
5937    
5938        case TOK_DBLCOLON:        case TOK_DBLCOLON:
5939              if (pn->pn_arity == PN_NAME) {              if (pn->pn_arity == PN_NAME) {
5940                  if (!js_EmitTree(cx, cg, pn->pn_expr))                  if (!js_EmitTree(cx, cg, pn->expr()))
5941                      return JS_FALSE;                      return JS_FALSE;
5942                  if (!EmitAtomOp(cx, pn, PN_OP(pn), cg))                  if (!EmitAtomOp(cx, pn, PN_OP(pn), cg))
5943                      return JS_FALSE;                      return JS_FALSE;
# Line 5600  Line 5949 
5949               * possibly including a let (a = b) ... expression.  We must clear               * possibly including a let (a = b) ... expression.  We must clear
5950               * TCF_IN_FOR_INIT to avoid mis-compiling such beasts.               * TCF_IN_FOR_INIT to avoid mis-compiling such beasts.
5951               */               */
5952              oldflags = cg->treeContext.flags;              oldflags = cg->flags;
5953              cg->treeContext.flags &= ~TCF_IN_FOR_INIT;              cg->flags &= ~TCF_IN_FOR_INIT;
5954  #endif  #endif
5955    
5956              /* Binary operators that evaluate both operands unconditionally. */              /* Binary operators that evaluate both operands unconditionally. */
# Line 5610  Line 5959 
5959              if (!js_EmitTree(cx, cg, pn->pn_right))              if (!js_EmitTree(cx, cg, pn->pn_right))
5960                  return JS_FALSE;                  return JS_FALSE;
5961  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
5962              cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;              cg->flags |= oldflags & TCF_IN_FOR_INIT;
5963  #endif  #endif
5964              if (js_Emit1(cx, cg, PN_OP(pn)) < 0)              if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
5965                  return JS_FALSE;                  return JS_FALSE;
# Line 5644  Line 5993 
5993              if (pn3->pn_type != TOK_NAME)              if (pn3->pn_type != TOK_NAME)
5994                  op = JSOP_TYPEOFEXPR;                  op = JSOP_TYPEOFEXPR;
5995          }          }
5996          oldflags = cg->treeContext.flags;          oldflags = cg->flags;
5997          cg->treeContext.flags &= ~TCF_IN_FOR_INIT;          cg->flags &= ~TCF_IN_FOR_INIT;
5998          if (!js_EmitTree(cx, cg, pn2))          if (!js_EmitTree(cx, cg, pn2))
5999              return JS_FALSE;              return JS_FALSE;
6000          cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;          cg->flags |= oldflags & TCF_IN_FOR_INIT;
6001          if (js_Emit1(cx, cg, op) < 0)          if (js_Emit1(cx, cg, op) < 0)
6002              return JS_FALSE;              return JS_FALSE;
6003          break;          break;
# Line 5667  Line 6016 
6016              if (!BindNameToSlot(cx, cg, pn2))              if (!BindNameToSlot(cx, cg, pn2))
6017                  return JS_FALSE;                  return JS_FALSE;
6018              op = PN_OP(pn2);              op = PN_OP(pn2);
6019              if (pn2->pn_slot >= 0) {              if (op == JSOP_CALLEE) {
6020                  if (pn2->pn_const) {                  if (js_Emit1(cx, cg, op) < 0)
6021                      /* Incrementing a declared const: just get its value. */                      return JS_FALSE;
6022                      op = (JOF_OPTYPE(op) == JOF_ATOM)              } else if (pn2->pn_cookie != FREE_UPVAR_COOKIE) {
6023                           ? JSOP_GETGVAR                  atomIndex = (jsatomid) pn2->pn_cookie;
                          : JSOP_GETLOCAL;  
                 }  
                 atomIndex = (jsatomid) pn2->pn_slot;  
6024                  EMIT_UINT16_IMM_OP(op, atomIndex);                  EMIT_UINT16_IMM_OP(op, atomIndex);
6025              } else {              } else {
6026                    JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
6027                  if (!EmitAtomOp(cx, pn2, op, cg))                  if (!EmitAtomOp(cx, pn2, op, cg))
6028                      return JS_FALSE;                      return JS_FALSE;
6029                    break;
6030                }
6031                if (pn2->isConst()) {
6032                    if (js_Emit1(cx, cg, JSOP_POS) < 0)
6033                        return JS_FALSE;
6034                    op = PN_OP(pn);
6035                    if (!(js_CodeSpec[op].format & JOF_POST)) {
6036                        if (js_Emit1(cx, cg, JSOP_ONE) < 0)
6037                            return JS_FALSE;
6038                        op = (js_CodeSpec[op].format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
6039                        if (js_Emit1(cx, cg, op) < 0)
6040                            return JS_FALSE;
6041                    }
6042              }              }
6043              break;              break;
6044            case TOK_DOT:            case TOK_DOT:
# Line 5723  Line 6083 
6083          pn2 = pn->pn_kid;          pn2 = pn->pn_kid;
6084          switch (pn2->pn_type) {          switch (pn2->pn_type) {
6085            case TOK_NAME:            case TOK_NAME:
             pn2->pn_op = JSOP_DELNAME;  
6086              if (!BindNameToSlot(cx, cg, pn2))              if (!BindNameToSlot(cx, cg, pn2))
6087                  return JS_FALSE;                  return JS_FALSE;
6088              op = PN_OP(pn2);              op = PN_OP(pn2);
# Line 5763  Line 6122 
6122            default:            default:
6123              /*              /*
6124               * If useless, just emit JSOP_TRUE; otherwise convert delete foo()               * If useless, just emit JSOP_TRUE; otherwise convert delete foo()
6125               * to foo(), true (a comma expression, requiring SRC_PCDELTA, and               * to foo(), true (a comma expression, requiring SRC_PCDELTA).
              * also JSOP_GROUP for correctly parenthesized decompilation).  
6126               */               */
6127              useful = JS_FALSE;              useful = JS_FALSE;
6128              if (!CheckSideEffects(cx, cg, pn2, &useful))              if (!CheckSideEffects(cx, cg, pn2, &useful))
# Line 5786  Line 6144 
6144                  if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))                  if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))
6145                      return JS_FALSE;                      return JS_FALSE;
6146              }              }
             if (js_Emit1(cx, cg, JSOP_GROUP) < 0)  
                 return JS_FALSE;  
6147          }          }
6148          break;          break;
6149    
# Line 5799  Line 6155 
6155          if (jmp < 0)          if (jmp < 0)
6156              return JS_FALSE;              return JS_FALSE;
6157          top = CG_OFFSET(cg);          top = CG_OFFSET(cg);
6158            if (!js_Emit1(cx, cg, JSOP_LOOP))
6159                return JS_FALSE;
6160          if (!js_EmitTree(cx, cg, pn->pn_right))          if (!js_EmitTree(cx, cg, pn->pn_right))
6161              return JS_FALSE;              return JS_FALSE;
6162          CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);          CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
# Line 5866  Line 6224 
6224            default:            default:
6225              /*              /*
6226               * Push null as a placeholder for the global object, per ECMA-262               * Push null as a placeholder for the global object, per ECMA-262
6227               * 11.2.3 step 6. We use JSOP_NULLTHIS to distinguish this opcode               * 11.2.3 step 6.
              * from JSOP_NULL (see jstracer.cpp for one use-case).  
6228               */               */
6229              if (!js_EmitTree(cx, cg, pn2))              if (!js_EmitTree(cx, cg, pn2))
6230                  return JS_FALSE;                  return JS_FALSE;
6231              if (js_Emit1(cx, cg, JSOP_NULLTHIS) < 0)              if (js_Emit1(cx, cg, JSOP_NULL) < 0)
6232                  return JS_FALSE;                  return JS_FALSE;
6233          }          }
6234    
# Line 5883  Line 6240 
6240           * JSOP_NEW bytecode with a two-byte immediate telling how many args           * JSOP_NEW bytecode with a two-byte immediate telling how many args
6241           * were pushed on the operand stack.           * were pushed on the operand stack.
6242           */           */
6243          oldflags = cg->treeContext.flags;          oldflags = cg->flags;
6244          cg->treeContext.flags &= ~TCF_IN_FOR_INIT;          cg->flags &= ~TCF_IN_FOR_INIT;
6245          for (pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {          for (pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
6246              if (!js_EmitTree(cx, cg, pn3))              if (!js_EmitTree(cx, cg, pn3))
6247                  return JS_FALSE;                  return JS_FALSE;
6248          }          }
6249          cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;          cg->flags |= oldflags & TCF_IN_FOR_INIT;
6250          if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)          if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)
6251              return JS_FALSE;              return JS_FALSE;
6252    
6253          argc = pn->pn_count - 1;          argc = pn->pn_count - 1;
6254          if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)          if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)
6255              return JS_FALSE;              return JS_FALSE;
6256          if (js_Emit1(cx, cg, JSOP_RESUME) < 0)          if (PN_OP(pn) == JSOP_EVAL)
             return JS_FALSE;  
         if (PN_OP(pn) == JSOP_EVAL)  
6257              EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);              EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
6258          break;          break;
6259        }        }
6260    
6261        case TOK_LEXICALSCOPE:        case TOK_LEXICALSCOPE:
6262        {        {
6263          JSParsedObjectBox *pob;          JSObjectBox *objbox;
6264          uintN count;          uintN count;
6265    
6266          pob = pn->pn_pob;          objbox = pn->pn_objbox;
6267          js_PushBlockScope(&cg->treeContext, &stmtInfo, pob->object,          js_PushBlockScope(cg, &stmtInfo, objbox->object, CG_OFFSET(cg));
                           CG_OFFSET(cg));  
6268    
6269          /*          /*
6270           * If this lexical scope is not for a catch block, let block or let           * If this lexical scope is not for a catch block, let block or let
# Line 5921  Line 6275 
6275           * statements get braces by default from the decompiler.           * statements get braces by default from the decompiler.
6276           */           */
6277          noteIndex = -1;          noteIndex = -1;
6278          type = PN_TYPE(pn->pn_expr);          type = PN_TYPE(pn->expr());
6279          if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR &&          if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR &&
6280              (!(stmt = stmtInfo.down)              (!(stmt = stmtInfo.down)
6281               ? !(cg->treeContext.flags & TCF_IN_FUNCTION)               ? !(cg->flags & TCF_IN_FUNCTION)
6282               : stmt->type == STMT_BLOCK)) {               : stmt->type == STMT_BLOCK)) {
6283  #if defined DEBUG_brendanXXX || defined DEBUG_mrbkap  #if defined DEBUG_brendan || defined DEBUG_mrbkap
6284              /* There must be no source note already output for the next op. */              /* There must be no source note already output for the next op. */
6285              JS_ASSERT(CG_NOTE_COUNT(cg) == 0 ||              JS_ASSERT(CG_NOTE_COUNT(cg) == 0 ||
6286                        CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) ||                        CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) ||
# Line 5938  Line 6292 
6292          }          }
6293    
6294          JS_ASSERT(CG_OFFSET(cg) == top);          JS_ASSERT(CG_OFFSET(cg) == top);
6295          if (!EmitObjectOp(cx, pob, JSOP_ENTERBLOCK, cg))          if (!EmitEnterBlock(cx, pn, cg))
6296              return JS_FALSE;              return JS_FALSE;
6297    
6298          if (!js_EmitTree(cx, cg, pn->pn_expr))          if (!js_EmitTree(cx, cg, pn->pn_expr))
# Line 5957  Line 6311 
6311          }          }
6312    
6313          /* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */          /* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */
6314          count = OBJ_BLOCK_COUNT(cx, pob->object);          count = OBJ_BLOCK_COUNT(cx, objbox->object);
6315          EMIT_UINT16_IMM_OP(op, count);          EMIT_UINT16_IMM_OP(op, count);
6316    
6317          ok = js_PopStatementCG(cx, cg);          ok = js_PopStatementCG(cx, cg);
# Line 6003  Line 6357 
6357           */           */
6358          if (!js_EmitTree(cx, cg, pn->pn_kid))          if (!js_EmitTree(cx, cg, pn->pn_kid))
6359              return JS_FALSE;              return JS_FALSE;
6360          slot = cg->arrayCompDepth;          slot = AdjustBlockSlot(cx, cg, cg->arrayCompDepth);
         slot = AdjustBlockSlot(cx, cg, slot);  
6361          if (slot < 0)          if (slot < 0)
6362              return JS_FALSE;              return JS_FALSE;
6363          EMIT_UINT16_IMM_OP(PN_OP(pn), slot);          EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
# Line 6017  Line 6370 
6370        case TOK_ARRAYCOMP:        case TOK_ARRAYCOMP:
6371  #endif  #endif
6372          /*          /*
6373           * Emit code for [a, b, c] of the form:           * Emit code for [a, b, c] that is equivalent to constructing a new
6374           *           * array and in source order evaluating each element value and adding
6375           *   t = new Array; t[0] = a; t[1] = b; t[2] = c; t;           * it to the array, without invoking latent setters.  We use the
6376             * JSOP_NEWINIT and JSOP_INITELEM bytecodes to ignore setters and to
6377             * avoid dup'ing and popping the array as each element is added, as
6378             * JSOP_SETELEM/JSOP_SETPROP would do.
6379           *           *
6380           * but use a stack slot for t and avoid dup'ing and popping it using           * If no sharp variable is defined, the initializer is not for an array
6381           * the JSOP_NEWINIT and JSOP_INITELEM bytecodes.           * comprehension, the initializer is not overlarge, and the initializer
6382           *           * is not in global code (whose stack growth cannot be precisely modeled
6383           * If no sharp variable is defined and the initialiser is not for an           * due to the need to reserve space for global variables and regular
6384           * array comprehension, use JSOP_NEWARRAY.           * expressions), use JSOP_NEWARRAY to minimize opcodes and to create the
6385             * array using a fast, all-at-once process rather than a slow, element-
6386             * by-element process.
6387           */           */
         pn2 = pn->pn_head;  
         op = JSOP_NEWINIT;      // FIXME: 260106 patch disabled for now  
   
6388  #if JS_HAS_SHARP_VARS  #if JS_HAS_SHARP_VARS
6389          if (pn2 && pn2->pn_type == TOK_DEFSHARP)          sharpnum = -1;
6390              op = JSOP_NEWINIT;        do_emit_array:
6391  #endif  #endif
6392    
6393            op = (JS_LIKELY(pn->pn_count < JS_BIT(16)) && (cg->flags & TCF_IN_FUNCTION))
6394                 ? JSOP_NEWARRAY
6395                 : JSOP_NEWINIT;
6396    
6397  #if JS_HAS_GENERATORS  #if JS_HAS_GENERATORS
6398          if (pn->pn_type == TOK_ARRAYCOMP)          if (pn->pn_type == TOK_ARRAYCOMP)
6399              op = JSOP_NEWINIT;              op = JSOP_NEWINIT;
6400  #endif  #endif
6401    #if JS_HAS_SHARP_VARS
6402            JS_ASSERT_IF(sharpnum >= 0, cg->flags & TCF_HAS_SHARPS);
6403            if (cg->flags & TCF_HAS_SHARPS)
6404                op = JSOP_NEWINIT;
6405    #endif
6406    
6407          if (op == JSOP_NEWINIT &&          if (op == JSOP_NEWINIT) {
6408              js_Emit2(cx, cg, op, (jsbytecode) JSProto_Array) < 0) {              if (js_Emit2(cx, cg, op, (jsbytecode) JSProto_Array) < 0)
6409              return JS_FALSE;                  return JS_FALSE;
         }  
   
6410  #if JS_HAS_SHARP_VARS  #if JS_HAS_SHARP_VARS
6411          if (pn2 && pn2->pn_type == TOK_DEFSHARP) {              if (sharpnum >= 0)
6412              EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);                  EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) sharpnum);
6413              pn2 = pn2->pn_next;  # endif
6414          }          }
 #endif  
6415    
6416  #if JS_HAS_GENERATORS  #if JS_HAS_GENERATORS
6417          if (pn->pn_type == TOK_ARRAYCOMP) {          if (pn->pn_type == TOK_ARRAYCOMP) {
6418              uintN saveDepth;              uintN saveDepth;
6419    
6420              /*              /*
6421               * Pass the new array's stack index to the TOK_ARRAYPUSH case by               * Pass the new array's stack index to the TOK_ARRAYPUSH case via
6422               * storing it in pn->pn_extra, then simply traverse the TOK_FOR               * cg->arrayCompDepth, then simply traverse the TOK_FOR node and
6423               * node and its kids under pn2 to generate this comprehension.               * its kids under pn2 to generate this comprehension.
6424               */               */
6425              JS_ASSERT(cg->stackDepth > 0);              JS_ASSERT(cg->stackDepth > 0);
6426              saveDepth = cg->arrayCompDepth;              saveDepth = cg->arrayCompDepth;
6427              cg->arrayCompDepth = (uint32) (cg->stackDepth - 1);              cg->arrayCompDepth = (uint32) (cg->stackDepth - 1);
6428              if (!js_EmitTree(cx, cg, pn2))              if (!js_EmitTree(cx, cg, pn->pn_head))
6429                  return JS_FALSE;                  return JS_FALSE;
6430              cg->arrayCompDepth = saveDepth;              cg->arrayCompDepth = saveDepth;
6431    
# Line 6074  Line 6436 
6436          }          }
6437  #endif /* JS_HAS_GENERATORS */  #endif /* JS_HAS_GENERATORS */
6438    
6439            pn2 = pn->pn_head;
6440          for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {          for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
6441              if (op == JSOP_NEWINIT && !EmitNumberOp(cx, atomIndex, cg))              if (op == JSOP_NEWINIT && !EmitNumberOp(cx, atomIndex, cg))
6442                  return JS_FALSE;                  return JS_FALSE;
   
6443              if (pn2->pn_type == TOK_COMMA) {              if (pn2->pn_type == TOK_COMMA) {
6444                  if (js_Emit1(cx, cg, JSOP_HOLE) < 0)                  if (js_Emit1(cx, cg, JSOP_HOLE) < 0)
6445                      return JS_FALSE;                      return JS_FALSE;
# Line 6085  Line 6447 
6447                  if (!js_EmitTree(cx, cg, pn2))                  if (!js_EmitTree(cx, cg, pn2))
6448                      return JS_FALSE;                      return JS_FALSE;
6449              }              }
   
6450              if (op == JSOP_NEWINIT && js_Emit1(cx, cg, JSOP_INITELEM) < 0)              if (op == JSOP_NEWINIT && js_Emit1(cx, cg, JSOP_INITELEM) < 0)
6451                  return JS_FALSE;                  return JS_FALSE;
6452          }          }
6453            JS_ASSERT(atomIndex == pn->pn_count);
6454    
6455          if (pn->pn_extra & PNX_ENDCOMMA) {          if (pn->pn_xflags & PNX_ENDCOMMA) {
6456              /* Emit a source note so we know to decompile an extra comma. */              /* Emit a source note so we know to decompile an extra comma. */
6457              if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0)              if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0)
6458                  return JS_FALSE;                  return JS_FALSE;
6459          }          }
6460    
6461          if (op == JSOP_NEWARRAY) {          if (op == JSOP_NEWINIT) {
6462              JS_ASSERT(atomIndex == pn->pn_count);              /*
6463              off = js_EmitN(cx, cg, op, 3);               * Emit an op to finish the array and, secondarily, to aid in sharp
6464              if (off < 0)               * array cleanup (if JS_HAS_SHARP_VARS) and decompilation.
6465                  return JS_FALSE;               */
             pc = CG_CODE(cg, off);  
             SET_UINT24(pc, atomIndex);  
             UpdateDepth(cx, cg, off);  
         } else {  
             /* Emit an op for sharp array cleanup and decompilation. */  
6466              if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)              if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)
6467                  return JS_FALSE;                  return JS_FALSE;
6468                break;
6469          }          }
6470    
6471            JS_ASSERT(atomIndex < JS_BIT(16));
6472            EMIT_UINT16_IMM_OP(JSOP_NEWARRAY, atomIndex);
6473          break;          break;
6474    
6475        case TOK_RC:        case TOK_RC:
6476    #if JS_HAS_SHARP_VARS
6477            sharpnum = -1;
6478          do_emit_object:
6479    #endif
6480  #if JS_HAS_DESTRUCTURING_SHORTHAND  #if JS_HAS_DESTRUCTURING_SHORTHAND
6481