/[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 507 by siliconforks, Sun Jan 10 07:23:34 2010 UTC
# Line 1  Line 1 
1  /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-  /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2   * vim: set ts=8 sw=4 et tw=99:   * vim: set ts=8 sw=4 et tw=99:
3   *   *
4   * ***** BEGIN LICENSE BLOCK *****   * ***** BEGIN LICENSE BLOCK *****
# Line 41  Line 41 
41  /*  /*
42   * JS bytecode generation.   * JS bytecode generation.
43   */   */
 #include "jsstddef.h"  
44  #ifdef HAVE_MEMORY_H  #ifdef HAVE_MEMORY_H
45  #include <memory.h>  #include <memory.h>
46  #endif  #endif
47    #include <new>
48  #include <string.h>  #include <string.h>
49  #include "jstypes.h"  #include "jstypes.h"
50    #include "jsstdint.h"
51  #include "jsarena.h" /* Added by JSIFY */  #include "jsarena.h" /* Added by JSIFY */
52  #include "jsutil.h" /* Added by JSIFY */  #include "jsutil.h" /* Added by JSIFY */
53  #include "jsbit.h"  #include "jsbit.h"
# 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);          compiler->context->free(spanDeps);
116    
117      if (cg->upvarMap.vector)      if (upvarMap.vector)
118          JS_free(cx, cg->upvarMap.vector);          compiler->context->free(upvarMap.vector);
119  }  }
120    
121  static ptrdiff_t  static ptrdiff_t
# Line 126  Line 128 
128      base = CG_BASE(cg);      base = CG_BASE(cg);
129      next = CG_NEXT(cg);      next = CG_NEXT(cg);
130      limit = CG_LIMIT(cg);      limit = CG_LIMIT(cg);
131      offset = PTRDIFF(next, base, jsbytecode);      offset = next - base;
132      if (next + delta > limit) {      if (next + delta > limit) {
133          length = offset + delta;          length = offset + delta;
134          length = (length <= BYTECODE_CHUNK)          length = (length <= BYTECODE_CHUNK)
# Line 136  Line 138 
138          if (!base) {          if (!base) {
139              JS_ARENA_ALLOCATE_CAST(base, jsbytecode *, cg->codePool, incr);              JS_ARENA_ALLOCATE_CAST(base, jsbytecode *, cg->codePool, incr);
140          } else {          } else {
141              size = BYTECODE_SIZE(PTRDIFF(limit, base, jsbytecode));              size = BYTECODE_SIZE(limit - base);
142              incr -= size;              incr -= size;
143              JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);              JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);
144          }          }
# 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 541  Line 549 
549      if ((index & (index - 1)) == 0 &&      if ((index & (index - 1)) == 0 &&
550          (!(sdbase = cg->spanDeps) || index >= SPANDEPS_MIN)) {          (!(sdbase = cg->spanDeps) || index >= SPANDEPS_MIN)) {
551          size = sdbase ? SPANDEPS_SIZE(index) : SPANDEPS_SIZE_MIN / 2;          size = sdbase ? SPANDEPS_SIZE(index) : SPANDEPS_SIZE_MIN / 2;
552          sdbase = (JSSpanDep *) JS_realloc(cx, sdbase, size + size);          sdbase = (JSSpanDep *) cx->realloc(sdbase, size + size);
553          if (!sdbase)          if (!sdbase)
554              return JS_FALSE;              return JS_FALSE;
555          cg->spanDeps = sdbase;          cg->spanDeps = sdbase;
# Line 549  Line 557 
557    
558      cg->numSpanDeps = index + 1;      cg->numSpanDeps = index + 1;
559      sd = cg->spanDeps + index;      sd = cg->spanDeps + index;
560      sd->top = PTRDIFF(pc, CG_BASE(cg), jsbytecode);      sd->top = pc - CG_BASE(cg);
561      sd->offset = sd->before = PTRDIFF(pc2, CG_BASE(cg), jsbytecode);      sd->offset = sd->before = pc2 - CG_BASE(cg);
562    
563      if (js_CodeSpec[*pc].format & JOF_BACKPATCH) {      if (js_CodeSpec[*pc].format & JOF_BACKPATCH) {
564          /* Jump offset will be backpatched if off is a non-zero "bpdelta". */          /* Jump offset will be backpatched if off is a non-zero "bpdelta". */
# Line 665  Line 673 
673      if (index != SPANDEP_INDEX_HUGE)      if (index != SPANDEP_INDEX_HUGE)
674          return cg->spanDeps + index;          return cg->spanDeps + index;
675    
676      offset = PTRDIFF(pc, CG_BASE(cg), jsbytecode);      offset = pc - CG_BASE(cg);
677      lo = 0;      lo = 0;
678      hi = cg->numSpanDeps - 1;      hi = cg->numSpanDeps - 1;
679      while (lo <= hi) {      while (lo <= hi) {
# 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 902  Line 910 
910          next = base + length;          next = base + length;
911          if (next > limit) {          if (next > limit) {
912              JS_ASSERT(length > BYTECODE_CHUNK);              JS_ASSERT(length > BYTECODE_CHUNK);
913              size = BYTECODE_SIZE(PTRDIFF(limit, base, jsbytecode));              size = BYTECODE_SIZE(limit - base);
914              incr = BYTECODE_SIZE(length) - size;              incr = BYTECODE_SIZE(length) - size;
915              JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);              JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);
916              if (!base) {              if (!base) {
# Line 1157  Line 1165 
1165       * can span top-level statements, because JS lacks goto.       * can span top-level statements, because JS lacks goto.
1166       */       */
1167      size = SPANDEPS_SIZE(JS_BIT(JS_CeilingLog2(cg->numSpanDeps)));      size = SPANDEPS_SIZE(JS_BIT(JS_CeilingLog2(cg->numSpanDeps)));
1168      JS_free(cx, cg->spanDeps);      cx->free(cg->spanDeps);
1169      cg->spanDeps = NULL;      cg->spanDeps = NULL;
1170      FreeJumpTargets(cg, cg->jumpTargets);      FreeJumpTargets(cg, cg->jumpTargets);
1171      cg->jumpTargets = NULL;      cg->jumpTargets = NULL;
# 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 1421  Line 1427 
1427      stop = CG_CODE(cg, -1);      stop = CG_CODE(cg, -1);
1428      while (pc != stop) {      while (pc != stop) {
1429          delta = GetJumpOffset(cg, pc);          delta = GetJumpOffset(cg, pc);
1430          span = PTRDIFF(target, pc, jsbytecode);          span = target - pc;
1431          CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, span);          CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, span);
1432    
1433          /*          /*
# 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(obj->getClass() == &js_BlockClass);
1529          scope = OBJ_SCOPE(obj);          scope = OBJ_SCOPE(obj);
1530          sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));          sprop = scope->lookup(ATOM_TO_JSID(atom));
1531          if (sprop) {          if (sprop) {
1532              JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);              JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
1533    
# 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->lookupProperty(cx, ATOM_TO_JSID(atom), &objbox, &prop);
                                          &prop);  
1605                  if (!ok)                  if (!ok)
1606                      return JS_FALSE;                      return JS_FALSE;
1607                  if (pobj == obj) {                  if (objbox == obj) {
1608                      /*                      /*
1609                       * We're compiling code that will be executed immediately,                       * We're compiling code that will be executed immediately,
1610                       * not re-executed against a different scope chain and/or                       * not re-executed against a different scope chain and/or
1611                       * variable object.  Therefore we can get constant values                       * variable object.  Therefore we can get constant values
1612                       * from our variable object here.                       * from our variable object here.
1613                       */                       */
1614                      ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop,                      ok = obj->getAttributes(cx, ATOM_TO_JSID(atom), prop, &attrs);
                                             &attrs);  
1615                      if (ok && IS_CONSTANT_PROPERTY(attrs)) {                      if (ok && IS_CONSTANT_PROPERTY(attrs)) {
1616                          ok = OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);                          ok = obj->getProperty(cx, ATOM_TO_JSID(atom), vp);
1617                          JS_ASSERT_IF(ok, *vp != JSVAL_HOLE);                          JS_ASSERT_IF(ok, *vp != JSVAL_HOLE);
1618                      }                      }
1619                  }                  }
1620                  if (prop)                  if (prop)
1621                      OBJ_DROP_PROPERTY(cx, pobj, prop);                      objbox->dropProperty(cx, prop);
1622                  if (!ok)                  if (!ok)
1623                      return JS_FALSE;                      return JS_FALSE;
1624                  if (prop)                  if (prop)
1625                      break;                      break;
1626              }              }
1627          }          }
1628      } while ((cg = cg->parent) != NULL);      } while ((cg = (JSCodeGenerator *) cg->parent) != NULL);
1629      return JS_TRUE;      return JS_TRUE;
1630  }  }
1631    
# Line 1697  Line 1700 
1700              return JS_FALSE;                                                  \              return JS_FALSE;                                                  \
1701      JS_END_MACRO      JS_END_MACRO
1702    
   
1703  static JSBool  static JSBool
1704  EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)  EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
1705  {  {
# Line 1708  Line 1710 
1710          pn->pn_atom == cx->runtime->atomState.lengthAtom) {          pn->pn_atom == cx->runtime->atomState.lengthAtom) {
1711          return js_Emit1(cx, cg, JSOP_LENGTH) >= 0;          return js_Emit1(cx, cg, JSOP_LENGTH) >= 0;
1712      }      }
1713      ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);      ale = cg->atomList.add(cg->compiler, pn->pn_atom);
1714      if (!ale)      if (!ale)
1715          return JS_FALSE;          return JS_FALSE;
1716      return EmitIndexOp(cx, op, ALE_INDEX(ale), cg);      return EmitIndexOp(cx, op, ALE_INDEX(ale), cg);
1717  }  }
1718    
 static uintN  
 IndexParsedObject(JSParsedObjectBox *pob, JSEmittedObjectList *list);  
   
1719  static JSBool  static JSBool
1720  EmitObjectOp(JSContext *cx, JSParsedObjectBox *pob, JSOp op,  EmitObjectOp(JSContext *cx, JSObjectBox *objbox, JSOp op,
1721               JSCodeGenerator *cg)               JSCodeGenerator *cg)
1722  {  {
1723      JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);      JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
1724      return EmitIndexOp(cx, op, IndexParsedObject(pob, &cg->objectList), cg);      return EmitIndexOp(cx, op, cg->objectList.index(objbox), cg);
1725  }  }
1726    
1727  /*  /*
# Line 1737  Line 1736 
1736    
1737  static JSBool  static JSBool
1738  EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index,  EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index,
1739                   JSCodeGenerator *cg)                  JSCodeGenerator *cg)
1740  {  {
1741      JSOp bigSuffix;      JSOp bigSuffix;
1742      ptrdiff_t off;      ptrdiff_t off;
# Line 1764  Line 1763 
1763   * 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
1764   * 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
1765   * 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
1766   * js_CompileScript; see comments there.   * JSCompiler::compileScript; see comments there.
1767   *   *
1768   * The function returns -1 on failures.   * The function returns -1 on failures.
1769   */   */
# Line 1772  Line 1771 
1771  AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot)  AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot)
1772  {  {
1773      JS_ASSERT((jsuint) slot < cg->maxStackDepth);      JS_ASSERT((jsuint) slot < cg->maxStackDepth);
1774      if (cg->treeContext.flags & TCF_IN_FUNCTION) {      if (cg->flags & TCF_IN_FUNCTION) {
1775          slot += cg->treeContext.u.fun->u.i.nvars;          slot += cg->fun->u.i.nvars;
1776          if ((uintN) slot >= SLOTNO_LIMIT) {          if ((uintN) slot >= SLOTNO_LIMIT) {
1777              js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL,              js_ReportCompileErrorNumber(cx, CG_TS(cg), NULL,
1778                                          JSREPORT_ERROR,                                          JSREPORT_ERROR,
# Line 1784  Line 1783 
1783      return slot;      return slot;
1784  }  }
1785    
1786    static bool
1787    EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
1788    {
1789        JS_ASSERT(PN_TYPE(pn) == TOK_LEXICALSCOPE);
1790        if (!EmitObjectOp(cx, pn->pn_objbox, JSOP_ENTERBLOCK, cg))
1791            return false;
1792    
1793        JSObject *blockObj = pn->pn_objbox->object;
1794        jsint depth = AdjustBlockSlot(cx, cg, OBJ_BLOCK_DEPTH(cx, blockObj));
1795        if (depth < 0)
1796            return false;
1797    
1798        for (uintN slot = JSSLOT_FREE(&js_BlockClass),
1799                   limit = slot + OBJ_BLOCK_COUNT(cx, blockObj);
1800             slot < limit; slot++) {
1801            jsval v = STOBJ_GET_SLOT(blockObj, slot);
1802    
1803            /* Beware the empty destructuring dummy. */
1804            if (JSVAL_IS_VOID(v)) {
1805                JS_ASSERT(slot + 1 <= limit);
1806                continue;
1807            }
1808    
1809            JSDefinition *dn = (JSDefinition *) JSVAL_TO_PRIVATE(v);
1810            JS_ASSERT(dn->pn_defn);
1811            JS_ASSERT(uintN(dn->frameSlot() + depth) < JS_BIT(16));
1812            dn->pn_cookie += depth;
1813    #ifdef DEBUG
1814            for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
1815                JS_ASSERT(pnu->pn_lexdef == dn);
1816                JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
1817                JS_ASSERT(pnu->pn_cookie == FREE_UPVAR_COOKIE);
1818            }
1819    #endif
1820        }
1821    
1822        OBJ_SCOPE(blockObj)->freeslot = JSSLOT_FREE(&js_BlockClass);
1823        return js_GrowSlots(cx, blockObj, JSSLOT_FREE(&js_BlockClass));
1824    }
1825    
1826  /*  /*
1827   * This routine tries to optimize name gets and sets to stack slot loads and   * When eval is called from a function, the eval code or function code it
1828   * stores, given the variables object and scope chain in cx's top frame, the   * compiles may reference upvars that live in the eval-calling function. The
1829   * compile-time context in tc, and a TOK_NAME node pn.  It returns false on   * eval-invoked compiler does not have explicit definitions for these upvars
1830   * error, true on success.   * and we do not attempt to create them a-priori (by inspecting the function's
1831     * args and vars) -- we could, but we'd take an avoidable penalty for each
1832     * function local not referenced by any upvar. Instead, we map such upvars
1833     * lazily, growing upvarMap.vector by powers of two.
1834   *   *
1835   * The caller can inspect pn->pn_slot for a non-negative slot number to tell   * This function knows that it is called with pn pointing to a PN_NAME-arity
1836   * whether optimization occurred, in which case BindNameToSlot also updated   * node, and cg->compiler->callerFrame having a non-null fun member, and the
1837   * pn->pn_op.  If pn->pn_slot is still -1 on return, pn->pn_op nevertheless   * static level of cg at least one greater than the eval-calling function's
1838   * may have been optimized, e.g., from JSOP_NAME to JSOP_ARGUMENTS.  Whether   * static level.
1839   * or not pn->pn_op was modified, if this function finds an argument or local   */
1840   * variable name, pn->pn_const will be true for const properties after a  static bool
1841    MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg)
1842    {
1843        JSContext *cx = cg->compiler->context;
1844        JSFunction *fun = cg->compiler->callerFrame->fun;
1845        uintN upvarLevel = fun->u.i.script->staticLevel;
1846    
1847        JSFunctionBox *funbox = cg->funbox;
1848        if (funbox) {
1849            /*
1850             * Treat top-level function definitions as escaping (i.e., as funargs),
1851             * required since we compile each such top level function or statement
1852             * and throw away the AST, so we can't yet see all funarg uses of this
1853             * function being compiled (cg->funbox->object). See bug 493177.
1854             */
1855            if (funbox->level == fun->u.i.script->staticLevel + 1U &&
1856                !(((JSFunction *) funbox->object)->flags & JSFUN_LAMBDA)) {
1857                JS_ASSERT_IF(cx->options & JSOPTION_ANONFUNFIX,
1858                             ((JSFunction *) funbox->object)->atom);
1859                return true;
1860            }
1861    
1862            while (funbox->level >= upvarLevel) {
1863                if (funbox->node->pn_dflags & PND_FUNARG)
1864                    return true;
1865                funbox = funbox->parent;
1866                if (!funbox)
1867                    break;
1868            }
1869        }
1870    
1871        JSAtom *atom = pn->pn_atom;
1872    
1873        uintN index;
1874        JSLocalKind localKind = js_LookupLocal(cx, fun, atom, &index);
1875        if (localKind == JSLOCAL_NONE)
1876            return true;
1877    
1878        JS_ASSERT(cg->staticLevel > upvarLevel);
1879        if (cg->staticLevel >= JS_DISPLAY_SIZE || upvarLevel >= JS_DISPLAY_SIZE)
1880            return true;
1881    
1882        JSAtomListElement *ale = cg->upvarList.lookup(atom);
1883        if (!ale) {
1884            if ((cg->flags & TCF_IN_FUNCTION) &&
1885                !js_AddLocal(cx, cg->fun, atom, JSLOCAL_UPVAR)) {
1886                return false;
1887            }
1888    
1889            ale = cg->upvarList.add(cg->compiler, atom);
1890            if (!ale)
1891                return false;
1892            JS_ASSERT(ALE_INDEX(ale) == cg->upvarList.count - 1);
1893    
1894            uint32 *vector = cg->upvarMap.vector;
1895            uint32 length = cg->upvarMap.length;
1896    
1897            JS_ASSERT(ALE_INDEX(ale) <= length);
1898            if (ALE_INDEX(ale) == length) {
1899                length = 2 * JS_MAX(2, length);
1900                vector = (uint32 *) cx->realloc(vector, length * sizeof *vector);
1901                if (!vector)
1902                    return false;
1903                cg->upvarMap.vector = vector;
1904                cg->upvarMap.length = length;
1905            }
1906    
1907            if (localKind != JSLOCAL_ARG)
1908                index += fun->nargs;
1909            JS_ASSERT(index < JS_BIT(16));
1910    
1911            uintN skip = cg->staticLevel - upvarLevel;
1912            vector[ALE_INDEX(ale)] = MAKE_UPVAR_COOKIE(skip, index);
1913        }
1914    
1915        pn->pn_op = JSOP_GETUPVAR;
1916        pn->pn_cookie = MAKE_UPVAR_COOKIE(cg->staticLevel, ALE_INDEX(ale));
1917        pn->pn_dflags |= PND_BOUND;
1918        return true;
1919    }
1920    
1921    /*
1922     * BindNameToSlot attempts to optimize name gets and sets to stack slot loads
1923     * and stores, given the compile-time information in cg and a TOK_NAME node pn.
1924     * It returns false on error, true on success.
1925     *
1926     * The caller can inspect pn->pn_cookie for FREE_UPVAR_COOKIE to tell whether
1927     * optimization occurred, in which case BindNameToSlot also updated pn->pn_op.
1928     * If pn->pn_cookie is still FREE_UPVAR_COOKIE on return, pn->pn_op still may
1929     * have been optimized, e.g., from JSOP_NAME to JSOP_CALLEE.  Whether or not
1930     * pn->pn_op was modified, if this function finds an argument or local variable
1931     * name, PND_CONST will be set in pn_dflags for read-only properties after a
1932   * successful return.   * successful return.
1933   *   *
1934   * 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 1938 
1938  static JSBool  static JSBool
1939  BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)  BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
1940  {  {
1941      JSTreeContext *tc;      JSDefinition *dn;
     JSAtom *atom;  
     JSStmtInfo *stmt;  
     jsint slot;  
1942      JSOp op;      JSOp op;
1943      JSLocalKind localKind;      JSAtom *atom;
1944      uintN index;      uint32 cookie;
1945        JSDefinition::Kind dn_kind;
1946      JSAtomListElement *ale;      JSAtomListElement *ale;
1947      JSBool constOp;      uintN index;
1948    
1949      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;  
1950    
1951      /* QNAME references can never be optimized to use arg/var storage. */      /* Idempotency tests come first, since we may be called more than once. */
1952      if (pn->pn_op == JSOP_QNAMEPART)      if (pn->pn_dflags & PND_BOUND)
1953          return JS_TRUE;          return JS_TRUE;
1954    
1955        /* No cookie initialized for these two, they're pre-bound by definition. */
1956        JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE);
1957    
1958      /*      /*
1959       * We can't optimize if we are compiling a with statement and its body,       * The parser linked all uses (including forward references) to their
1960       * 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.  
1961       */       */
1962      tc = &cg->treeContext;      if (pn->pn_used) {
1963      atom = pn->pn_atom;          JS_ASSERT(pn->pn_cookie == FREE_UPVAR_COOKIE);
1964      stmt = js_LexicalLookup(tc, atom, &slot);          dn = pn->pn_lexdef;
1965      if (stmt) {          JS_ASSERT(dn->pn_defn);
1966          if (stmt->type == STMT_WITH)          pn->pn_dflags |= (dn->pn_dflags & PND_CONST);
1967        } else {
1968            if (!pn->pn_defn)
1969              return JS_TRUE;              return JS_TRUE;
1970            dn = (JSDefinition *) pn;
1971        }
1972    
1973          JS_ASSERT(stmt->flags & SIF_SCOPE);      op = PN_OP(pn);
1974          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;  
         }  
1975          return JS_TRUE;          return JS_TRUE;
1976      }  
1977        JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
1978        atom = pn->pn_atom;
1979        cookie = dn->pn_cookie;
1980        dn_kind = dn->kind();
1981    
1982      /*      /*
1983       * 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
1984       * expression and not at top-level within another's body) collide.       * pre-increment and pre-decrement ops, our caller will have to emit
1985       * XXX suboptimal: keep track of colliding names and deoptimize only those       * JSOP_POS, JSOP_ONE, and JSOP_ADD as well).
1986         *
1987         * Turn JSOP_DELNAME into JSOP_FALSE if dn is known, as all declared
1988         * bindings visible to the compiler are permanent in JS unless the
1989         * declaration originates in eval code. We detect eval code by testing
1990         * cg->compiler->callerFrame, which is set only by eval or a debugger
1991         * equivalent.
1992         *
1993         * Note that this callerFrame non-null test must be qualified by testing
1994         * !cg->funbox to exclude function code nested in eval code, which is not
1995         * subject to the deletable binding exception.
1996       */       */
1997      if (tc->flags & TCF_FUN_CLOSURE_VS_VAR)      switch (op) {
1998          return JS_TRUE;        case JSOP_NAME:
1999          case JSOP_SETCONST:
2000      if (!(tc->flags & TCF_IN_FUNCTION)) {          break;
2001          JSStackFrame *caller;        case JSOP_DELNAME:
2002            if (dn_kind != JSDefinition::UNKNOWN) {
2003                if (cg->compiler->callerFrame && !cg->funbox)
2004                    JS_ASSERT(cg->flags & TCF_COMPILE_N_GO);
2005                else
2006                    pn->pn_op = JSOP_FALSE;
2007                pn->pn_dflags |= PND_BOUND;
2008                return JS_TRUE;
2009            }
2010            break;
2011          default:
2012            if (pn->isConst())
2013                pn->pn_op = op = JSOP_NAME;
2014        }
2015    
2016          caller = tc->parseContext->callerFrame;      if (cookie == FREE_UPVAR_COOKIE) {
2017            JSStackFrame *caller = cg->compiler->callerFrame;
2018          if (caller) {          if (caller) {
2019              JS_ASSERT(tc->flags & TCF_COMPILE_N_GO);              JS_ASSERT(cg->flags & TCF_COMPILE_N_GO);
2020    
2021                /*
2022                 * Don't generate upvars on the left side of a for loop. See
2023                 * bug 470758.
2024                 */
2025                if (cg->flags & TCF_IN_FOR_INIT)
2026                    return JS_TRUE;
2027    
2028              JS_ASSERT(caller->script);              JS_ASSERT(caller->script);
2029              if (!caller->fun || caller->varobj != tc->u.scopeChain)              if (!caller->fun)
2030                    return JS_TRUE;
2031    
2032                /*
2033                 * Make sure the variable object used by the compiler to initialize
2034                 * parent links matches the caller's varobj. Compile-n-go compiler-
2035                 * created function objects have the top-level cg's scopeChain set
2036                 * as their parent by JSCompiler::newFunction.
2037                 */
2038                JSObject *scopeobj = (cg->flags & TCF_IN_FUNCTION)
2039                                     ? STOBJ_GET_PARENT(FUN_OBJECT(cg->fun))
2040                                     : cg->scopeChain;
2041                if (scopeobj != caller->varobj)
2042                  return JS_TRUE;                  return JS_TRUE;
2043    
2044              /*              /*
2045               * We are compiling eval or debug script inside a function frame               * We are compiling eval or debug script inside a function frame
2046               * and the scope chain matches function's variable object.               * and the scope chain matches the function's variable object.
2047               * Optimize access to function's arguments and variable and the               * Optimize access to function's arguments and variable and the
2048               * arguments object.               * arguments object.
2049               */               */
2050              if (PN_OP(pn) != JSOP_NAME || cg->staticDepth > JS_DISPLAY_SIZE)              if (op != JSOP_NAME)
2051                  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;  
             }  
2052    
2053              pn->pn_op = JSOP_GETUPVAR;              return MakeUpvarForEval(pn, cg);
             pn->pn_slot = ALE_INDEX(ale);  
             return JS_TRUE;  
2054          }          }
2055            return JS_TRUE;
2056        }
2057    
2058        if (dn->pn_dflags & PND_GVAR) {
2059          /*          /*
2060           * 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
2061           * 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
2062           * 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
2063             * calls to the function.
2064           */           */
2065          ATOM_LIST_SEARCH(ale, &tc->decls, atom);          if (cg->flags & TCF_IN_FUNCTION)
         if (!ale) {  
             /* Use precedes declaration, or name is never declared. */  
2066              return JS_TRUE;              return JS_TRUE;
         }  
         constOp = (ALE_JSOP(ale) == JSOP_DEFCONST);  
2067    
2068          /* Index atom so we can map fast global number to name. */          /*
2069          ale = js_IndexAtom(cx, atom, &cg->atomList);           * We are optimizing global variables and there may be no pre-existing
2070          if (!ale)           * global property named atom when this global script runs. If atom was
2071              return JS_FALSE;           * declared via const or var, optimize pn to access fp->vars using the
2072             * appropriate JSOP_*GVAR op.
2073          /* Defend against tc->ngvars 16-bit overflow. */           *
2074          slot = ALE_INDEX(ale);           * FIXME: should be able to optimize global function access too.
2075          if ((slot + 1) >> 16)           */
2076              return JS_TRUE;          JS_ASSERT(dn_kind == JSDefinition::VAR || dn_kind == JSDefinition::CONST);
   
         if ((uint16)(slot + 1) > tc->ngvars)  
             tc->ngvars = (uint16)(slot + 1);  
2077    
         op = PN_OP(pn);  
2078          switch (op) {          switch (op) {
2079            case JSOP_NAME:     op = JSOP_GETGVAR; break;            case JSOP_NAME:     op = JSOP_GETGVAR; break;
2080            case JSOP_SETNAME:  op = JSOP_SETGVAR; break;            case JSOP_SETNAME:  op = JSOP_SETGVAR; break;
# Line 1966  Line 2087 
2087            case JSOP_DELNAME:  /* NB: no change */ break;            case JSOP_DELNAME:  /* NB: no change */ break;
2088            default: JS_NOT_REACHED("gvar");            default: JS_NOT_REACHED("gvar");
2089          }          }
2090          pn->pn_const = constOp;          pn->pn_op = op;
2091          if (op != pn->pn_op) {          pn->pn_cookie = cookie;
2092              pn->pn_op = op;          pn->pn_dflags |= PND_BOUND;
             pn->pn_slot = slot;  
         }  
2093          return JS_TRUE;          return JS_TRUE;
2094      }      }
2095    
2096      if (tc->flags & TCF_IN_FUNCTION) {      uintN level = UPVAR_FRAME_SKIP(cookie);
2097        JS_ASSERT(cg->staticLevel >= level);
2098    
2099        /*
2100         * A JSDefinition witnessed as a declaration by the parser cannot be an
2101         * upvar, unless it is the degenerate kind of upvar selected above (in the
2102         * code before the PND_GVAR test) for the special case of compile-and-go
2103         * code generated from eval called from a function, where the eval code
2104         * uses local vars defined in the function. We detect this upvar-for-eval
2105         * case by checking dn's op.
2106         */
2107        if (PN_OP(dn) == JSOP_GETUPVAR) {
2108            JS_ASSERT(cg->staticLevel >= level);
2109            if (op != JSOP_NAME)
2110                return JS_TRUE;
2111    
2112            JSStackFrame *caller = cg->compiler->callerFrame;
2113            JS_ASSERT(caller);
2114            JS_ASSERT(caller->script);
2115    
2116            JSTreeContext *tc = cg;
2117            while (tc->staticLevel != level)
2118                tc = tc->parent;
2119            JS_ASSERT(tc->flags & TCF_COMPILING);
2120    
2121            JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
2122            JS_ASSERT(evalcg->flags & TCF_COMPILE_N_GO);
2123            JS_ASSERT(caller->fun && caller->varobj == evalcg->scopeChain);
2124    
2125            /*
2126             * Don't generate upvars on the left side of a for loop. See
2127             * bug 470758 and bug 520513.
2128             */
2129            if (evalcg->flags & TCF_IN_FOR_INIT)
2130                return JS_TRUE;
2131    
2132            if (cg->staticLevel == level) {
2133                pn->pn_op = JSOP_GETUPVAR;
2134                pn->pn_cookie = cookie;
2135                pn->pn_dflags |= PND_BOUND;
2136                return JS_TRUE;
2137            }
2138    
2139            return MakeUpvarForEval(pn, cg);
2140        }
2141    
2142        uintN skip = cg->staticLevel - level;
2143        if (skip != 0) {
2144            JS_ASSERT(cg->flags & TCF_IN_FUNCTION);
2145            JS_ASSERT_IF(UPVAR_FRAME_SLOT(cookie) != CALLEE_UPVAR_SLOT,
2146                         cg->lexdeps.lookup(atom));
2147            JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
2148            JS_ASSERT(cg->fun->u.i.skipmin <= skip);
2149    
2150          /*          /*
2151           * 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
2152           * 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
2153           * rewrite pn_op and update pn accordingly.           * on JSOP_*NAME*.
2154           */           */
2155          localKind = js_LookupLocal(cx, tc->u.fun, atom, &index);          if (op != JSOP_NAME)
2156          if (localKind != JSLOCAL_NONE) {              return JS_TRUE;
2157              op = PN_OP(pn);          if (level >= JS_DISPLAY_SIZE)
2158              if (localKind == JSLOCAL_ARG) {              return JS_TRUE;
2159                  switch (op) {          if (cg->flags & TCF_FUN_HEAVYWEIGHT)
2160                    case JSOP_NAME:     op = JSOP_GETARG; break;              return JS_TRUE;
2161                    case JSOP_SETNAME:  op = JSOP_SETARG; break;  
2162                    case JSOP_INCNAME:  op = JSOP_INCARG; break;          if (FUN_FLAT_CLOSURE(cg->fun)) {
2163                    case JSOP_NAMEINC:  op = JSOP_ARGINC; break;              op = JSOP_GETDSLOT;
2164                    case JSOP_DECNAME:  op = JSOP_DECARG; break;          } else {
2165                    case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;              /*
2166                    case JSOP_FORNAME:  op = JSOP_FORARG; break;               * The function we're compiling may not be heavyweight, but if it
2167                    case JSOP_DELNAME:  op = JSOP_FALSE; break;               * escapes as a funarg, we can't use JSOP_GETUPVAR/JSOP_CALLUPVAR.
2168                    default: JS_NOT_REACHED("arg");               * JSCompiler::analyzeFunctions has arranged for this function's
2169                  }               * enclosing functions to be heavyweight, so we can safely stick
2170                  pn->pn_const = JS_FALSE;               * with JSOP_NAME/JSOP_CALLNAME.
2171              } else {               */
2172                  JS_ASSERT(localKind == JSLOCAL_VAR ||              if (cg->funbox->node->pn_dflags & PND_FUNARG)
2173                            localKind == JSLOCAL_CONST);                  return JS_TRUE;
2174                  switch (op) {  
2175                    case JSOP_NAME:     op = JSOP_GETLOCAL; break;              /*
2176                    case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;               * Generator functions may be resumed from any call stack, which
2177                    case JSOP_SETCONST: op = JSOP_SETLOCAL; break;               * defeats the display optimization to static link searching used
2178                    case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;               * by JSOP_{GET,CALL}UPVAR.
2179                    case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;               */
2180                    case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;              if (cg->flags & TCF_FUN_IS_GENERATOR)
2181                    case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;                  return JS_TRUE;
2182                    case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;  
2183                    case JSOP_DELNAME:  op = JSOP_FALSE; break;              op = JSOP_GETUPVAR;
2184                    default: JS_NOT_REACHED("local");          }
2185    
2186            ale = cg->upvarList.lookup(atom);
2187            if (ale) {
2188                index = ALE_INDEX(ale);
2189            } else {
2190                if (!js_AddLocal(cx, cg->fun, atom, JSLOCAL_UPVAR))
2191                    return JS_FALSE;
2192    
2193                ale = cg->upvarList.add(cg->compiler, atom);
2194                if (!ale)
2195                    return JS_FALSE;
2196                index = ALE_INDEX(ale);
2197                JS_ASSERT(index == cg->upvarList.count - 1);
2198    
2199                uint32 *vector = cg->upvarMap.vector;
2200                if (!vector) {
2201                    uint32 length = cg->lexdeps.count;
2202    
2203                    vector = (uint32 *) js_calloc(length * sizeof *vector);
2204                    if (!vector) {
2205                        JS_ReportOutOfMemory(cx);
2206                        return JS_FALSE;
2207                  }                  }
2208                  pn->pn_const = (localKind == JSLOCAL_CONST);                  cg->upvarMap.vector = vector;
2209                    cg->upvarMap.length = length;
2210              }              }
2211              pn->pn_op = op;  
2212              pn->pn_slot = index;              uintN slot = UPVAR_FRAME_SLOT(cookie);
2213              return JS_TRUE;              if (slot != CALLEE_UPVAR_SLOT && dn_kind != JSDefinition::ARG) {
2214                    JSTreeContext *tc = cg;
2215                    do {
2216                        tc = tc->parent;
2217                    } while (tc->staticLevel != level);
2218                    if (tc->flags & TCF_IN_FUNCTION)
2219                        slot += tc->fun->nargs;
2220                }
2221    
2222                vector[index] = MAKE_UPVAR_COOKIE(skip, slot);
2223          }          }
2224          tc->flags |= TCF_FUN_USES_NONLOCALS;  
2225            pn->pn_op = op;
2226            pn->pn_cookie = index;
2227            pn->pn_dflags |= PND_BOUND;
2228            return JS_TRUE;
2229      }      }
2230    
   arguments_check:  
2231      /*      /*
2232       * 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
2233       * 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
2234       * 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.  
2235       */       */
2236      JS_ASSERT((tc->flags & TCF_IN_FUNCTION) ||      switch (dn_kind) {
2237                (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;  
2238          return JS_TRUE;          return JS_TRUE;
2239    
2240          case JSDefinition::LET:
2241            switch (op) {
2242              case JSOP_NAME:     op = JSOP_GETLOCAL; break;
2243              case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
2244              case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
2245              case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
2246              case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
2247              case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
2248              case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;
2249              default: JS_NOT_REACHED("let");
2250            }
2251            break;
2252    
2253          case JSDefinition::ARG:
2254            switch (op) {
2255              case JSOP_NAME:     op = JSOP_GETARG; break;
2256              case JSOP_SETNAME:  op = JSOP_SETARG; break;
2257              case JSOP_INCNAME:  op = JSOP_INCARG; break;
2258              case JSOP_NAMEINC:  op = JSOP_ARGINC; break;
2259              case JSOP_DECNAME:  op = JSOP_DECARG; break;
2260              case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;
2261              case JSOP_FORNAME:  op = JSOP_FORARG; break;
2262              default: JS_NOT_REACHED("arg");
2263            }
2264            JS_ASSERT(!pn->isConst());
2265            break;
2266    
2267          case JSDefinition::VAR:
2268            if (PN_OP(dn) == JSOP_CALLEE) {
2269                JS_ASSERT(op != JSOP_CALLEE);
2270                JS_ASSERT((cg->fun->flags & JSFUN_LAMBDA) && atom == cg->fun->atom);
2271    
2272                switch (op) {
2273                  default:
2274                    /*
2275                     * Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight, as
2276                     * we cannot be sure cg->fun is not something of the form:
2277                     *
2278                     *   var ff = (function f(s) { eval(s); return f; });
2279                     *
2280                     * where a caller invokes ff("var f = 42"). The result returned
2281                     * for such an invocation must be 42, since the callee name is
2282                     * lexically bound in an outer declarative environment from the
2283                     * function's activation. See jsfun.cpp:call_resolve.
2284                     */
2285                    JS_ASSERT(op != JSOP_DELNAME);
2286                    if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) {
2287                        op = JSOP_CALLEE;
2288                        pn->pn_dflags |= PND_CONST;
2289                    }
2290                    break;
2291                }
2292                pn->pn_op = op;
2293                pn->pn_dflags |= PND_BOUND;
2294                return JS_TRUE;
2295            }
2296            /* FALL THROUGH */
2297    
2298          default:
2299            JS_ASSERT_IF(dn_kind != JSDefinition::FUNCTION,
2300                         dn_kind == JSDefinition::VAR ||
2301                         dn_kind == JSDefinition::CONST);
2302            switch (op) {
2303              case JSOP_NAME:     op = JSOP_GETLOCAL; break;
2304              case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
2305              case JSOP_SETCONST: op = JSOP_SETLOCAL; break;
2306              case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
2307              case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
2308              case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
2309              case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
2310              case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;
2311              default: JS_NOT_REACHED("local");
2312            }
2313            JS_ASSERT_IF(dn_kind == JSDefinition::CONST, pn->pn_dflags & PND_CONST);
2314            break;
2315      }      }
2316    
2317        JS_ASSERT(op != PN_OP(pn));
2318        pn->pn_op = op;
2319        pn->pn_cookie = UPVAR_FRAME_SLOT(cookie);
2320        pn->pn_dflags |= PND_BOUND;
2321      return JS_TRUE;      return JS_TRUE;
2322  }  }
2323    
# Line 2056  Line 2338 
2338                   JSBool *answer)                   JSBool *answer)
2339  {  {
2340      JSBool ok;      JSBool ok;
     JSFunction *fun;  
2341      JSParseNode *pn2;      JSParseNode *pn2;
2342    
2343      ok = JS_TRUE;      ok = JS_TRUE;
# Line 2066  Line 2347 
2347      switch (pn->pn_arity) {      switch (pn->pn_arity) {
2348        case PN_FUNC:        case PN_FUNC:
2349          /*          /*
2350           * 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
2351           * not called.  The side effects are the creation of a scope object           * bind its name lexically (using JSOP_CALLEE) instead of creating an
2352           * to parent this function object, and the binding of the function's           * Object instance and binding a readonly, permanent property in it
2353           * name in that scope object.  See comments at case JSOP_NAMEDFUNOBJ:           * (the object and binding can be detected and hijacked or captured).
2354           * in jsinterp.c.           * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
2355           */           */
2356          fun = (JSFunction *) pn->pn_funpob->object;          *answer = JS_FALSE;
         if (fun->atom)  
             *answer = JS_TRUE;  
2357          break;          break;
2358    
2359        case PN_LIST:        case PN_LIST:
2360          if (pn->pn_type == TOK_NEW ||          if (pn->pn_op == JSOP_NOP ||
2361              pn->pn_type == TOK_LP ||              pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
2362              pn->pn_type == TOK_LB ||              pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
2363              pn->pn_type == TOK_RB ||              /*
2364              pn->pn_type == TOK_RC) {               * Non-operators along with ||, &&, ===, and !== never invoke
2365                 * toString or valueOf.
2366                 */
2367                for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
2368                    ok &= CheckSideEffects(cx, cg, pn2, answer);
2369            } else {
2370              /*              /*
2371               * All invocation operations (construct: TOK_NEW, call: TOK_LP)               * All invocation operations (construct: TOK_NEW, call: TOK_LP)
2372               * 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 2378 
2378               * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,               * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,
2379               * does not apply here: arguments[i][j] might invoke a getter).               * does not apply here: arguments[i][j] might invoke a getter).
2380               *               *
2381               * Array and object initializers (TOK_RB and TOK_RC lists) must be               * Likewise, array and object initialisers may call prototype
2382               * considered useful, because they are sugar for constructor calls               * setters (the __defineSetter__ built-in, and writable __proto__
2383               * (to Array and Object, respectively).               * on Array.prototype create this hazard). Initialiser list nodes
2384                 * have JSOP_NEWINIT in their pn_op.
2385               */               */
2386              *answer = JS_TRUE;              *answer = JS_TRUE;
         } else {  
             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)  
                 ok &= CheckSideEffects(cx, cg, pn2, answer);  
2387          }          }
2388          break;          break;
2389    
# Line 2130  Line 2412 
2412                      return JS_FALSE;                      return JS_FALSE;
2413                  if (!CheckSideEffects(cx, cg, pn->pn_right, answer))                  if (!CheckSideEffects(cx, cg, pn->pn_right, answer))
2414                      return JS_FALSE;                      return JS_FALSE;
2415                  if (!*answer &&                  if (!*answer && (pn->pn_op != JSOP_NOP || !pn2->isConst()))
                     (pn->pn_op != JSOP_NOP ||  
                      pn2->pn_slot < 0 ||  
                      !pn2->pn_const)) {  
2416                      *answer = JS_TRUE;                      *answer = JS_TRUE;
                 }  
2417              }              }
2418          } else {          } else {
2419              /*              if (pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
2420               * We can't easily prove that neither operand ever denotes an                  pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
2421               * object with a toString or valueOf method.                  /*
2422               */                   * ||, &&, ===, and !== do not convert their operands via
2423              *answer = JS_TRUE;                   * toString or valueOf method calls.
2424                     */
2425                    ok = CheckSideEffects(cx, cg, pn->pn_left, answer) &&
2426                         CheckSideEffects(cx, cg, pn->pn_right, answer);
2427                } else {
2428                    /*
2429                     * We can't easily prove that neither operand ever denotes an
2430                     * object with a toString or valueOf method.
2431                     */
2432                    *answer = JS_TRUE;
2433                }
2434          }          }
2435          break;          break;
2436    
2437        case PN_UNARY:        case PN_UNARY:
2438          switch (pn->pn_type) {          switch (pn->pn_type) {
           case TOK_RP:  
             ok = CheckSideEffects(cx, cg, pn->pn_kid, answer);  
             break;  
   
2439            case TOK_DELETE:            case TOK_DELETE:
2440              pn2 = pn->pn_kid;              pn2 = pn->pn_kid;
2441              switch (pn2->pn_type) {              switch (pn2->pn_type) {
2442                case TOK_NAME:                case TOK_NAME:
2443                    if (!BindNameToSlot(cx, cg, pn2))
2444                        return JS_FALSE;
2445                    if (pn2->isConst()) {
2446                        *answer = JS_FALSE;
2447                        break;
2448                    }
2449                    /* FALL THROUGH */
2450                case TOK_DOT:                case TOK_DOT:
2451  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
2452                case TOK_DBLDOT:                case TOK_DBLDOT:
# Line 2173  Line 2464 
2464              }              }
2465              break;              break;
2466    
2467              case TOK_UNARYOP:
2468                if (pn->pn_op == JSOP_NOT) {
2469                    /* ! does not convert its operand via toString or valueOf. */
2470                    ok = CheckSideEffects(cx, cg, pn->pn_kid, answer);
2471                    break;
2472                }
2473                /* FALL THROUGH */
2474    
2475            default:            default:
2476              /*              /*
2477               * 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 2493 
2493          if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) {          if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) {
2494              if (!BindNameToSlot(cx, cg, pn))              if (!BindNameToSlot(cx, cg, pn))
2495                  return JS_FALSE;                  return JS_FALSE;
2496              if (pn->pn_slot < 0 && pn->pn_op != JSOP_ARGUMENTS) {              if (pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE &&
2497                    pn->pn_cookie == FREE_UPVAR_COOKIE) {
2498                  /*                  /*
2499                   * Not an argument or local variable use, so this expression                   * Not an argument or local variable use, and not a use of a
2500                   * could invoke a getter that has side effects.                   * unshadowed named function expression's given name, so this
2501                     * expression could invoke a getter that has side effects.
2502                   */                   */
2503                  *answer = JS_TRUE;                  *answer = JS_TRUE;
2504              }              }
2505          }          }
2506          pn2 = pn->pn_expr;          pn2 = pn->maybeExpr();
2507          if (pn->pn_type == TOK_DOT) {          if (pn->pn_type == TOK_DOT) {
2508              if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2))              if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2))
2509                  return JS_FALSE;                  return JS_FALSE;
# Line 2218  Line 2519 
2519          ok = CheckSideEffects(cx, cg, pn2, answer);          ok = CheckSideEffects(cx, cg, pn2, answer);
2520          break;          break;
2521    
2522          case PN_NAMESET:
2523            ok = CheckSideEffects(cx, cg, pn->pn_tree, answer);
2524            break;
2525    
2526        case PN_NULLARY:        case PN_NULLARY:
2527          if (pn->pn_type == TOK_DEBUGGER)          if (pn->pn_type == TOK_DEBUGGER)
2528              *answer = JS_TRUE;              *answer = JS_TRUE;
# Line 2253  Line 2558 
2558            case JSOP_GETUPVAR:            case JSOP_GETUPVAR:
2559              op = JSOP_CALLUPVAR;              op = JSOP_CALLUPVAR;
2560              break;              break;
2561              case JSOP_GETDSLOT:
2562                op = JSOP_CALLDSLOT;
2563                break;
2564            default:            default:
2565              JS_ASSERT(op == JSOP_ARGUMENTS);              JS_ASSERT(op == JSOP_ARGUMENTS || op == JSOP_CALLEE);
2566              break;              break;
2567          }          }
2568      }      }
2569    
2570      if (op == JSOP_ARGUMENTS) {      if (op == JSOP_ARGUMENTS || op == JSOP_CALLEE) {
2571          if (js_Emit1(cx, cg, op) < 0)          if (js_Emit1(cx, cg, op) < 0)
2572              return JS_FALSE;              return JS_FALSE;
2573          if (callContext && js_Emit1(cx, cg, JSOP_NULL) < 0)          if (callContext && js_Emit1(cx, cg, JSOP_NULL) < 0)
2574              return JS_FALSE;              return JS_FALSE;
2575      } else {      } else {
2576          if (pn->pn_slot >= 0) {          if (pn->pn_cookie != FREE_UPVAR_COOKIE) {
2577              EMIT_UINT16_IMM_OP(op, pn->pn_slot);              EMIT_UINT16_IMM_OP(op, pn->pn_cookie);
2578          } else {          } else {
2579              if (!EmitAtomOp(cx, pn, op, cg))              if (!EmitAtomOp(cx, pn, op, cg))
2580                  return JS_FALSE;                  return JS_FALSE;
# Line 2288  Line 2596 
2596      JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME);      JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME);
2597    
2598      pn2 = pn->pn_kid;      pn2 = pn->pn_kid;
2599      oldflags = cg->treeContext.flags;      oldflags = cg->flags;
2600      cg->treeContext.flags &= ~TCF_IN_FOR_INIT;      cg->flags &= ~TCF_IN_FOR_INIT;
2601      if (!js_EmitTree(cx, cg, pn2))      if (!js_EmitTree(cx, cg, pn2))
2602          return JS_FALSE;          return JS_FALSE;
2603      cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;      cg->flags |= oldflags & TCF_IN_FOR_INIT;
2604      if (js_NewSrcNote2(cx, cg, SRC_PCBASE,      if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
2605                         CG_OFFSET(cg) - pn2->pn_offset) < 0) {                         CG_OFFSET(cg) - pn2->pn_offset) < 0) {
2606          return JS_FALSE;          return JS_FALSE;
# Line 2303  Line 2611 
2611  #endif  #endif
2612    
2613  static JSBool  static JSBool
2614    EmitSpecialPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
2615    {
2616        /*
2617         * Special case for obj.__proto__, obj.__parent__, obj.__count__ to
2618         * deoptimize away from fast paths in the interpreter and trace recorder,
2619         * which skip dense array instances by going up to Array.prototype before
2620         * looking up the property name.
2621         */
2622        JSAtomListElement *ale = cg->atomList.add(cg->compiler, pn->pn_atom);
2623        if (!ale)
2624            return JS_FALSE;
2625        if (!EmitIndexOp(cx, JSOP_QNAMEPART, ALE_INDEX(ale), cg))
2626            return JS_FALSE;
2627        if (js_Emit1(cx, cg, op) < 0)
2628            return JS_FALSE;
2629        return JS_TRUE;
2630    }
2631    
2632    static JSBool
2633  EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,  EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
2634             JSBool callContext)             JSBool callContext)
2635  {  {
2636      JSParseNode *pn2, *pndot, *pnup, *pndown;      JSParseNode *pn2, *pndot, *pnup, *pndown;
2637      ptrdiff_t top;      ptrdiff_t top;
2638    
2639      pn2 = pn->pn_expr;      JS_ASSERT(pn->pn_arity == PN_NAME);
2640        pn2 = pn->maybeExpr();
2641    
2642        /* Special case deoptimization on __proto__, __count__ and __parent__. */
2643        if ((op == JSOP_GETPROP || op == JSOP_CALLPROP) &&
2644            (pn->pn_atom == cx->runtime->atomState.protoAtom ||
2645             pn->pn_atom == cx->runtime->atomState.parentAtom ||
2646             pn->pn_atom == cx->runtime->atomState.countAtom)) {
2647            if (pn2 && !js_EmitTree(cx, cg, pn2))
2648                return JS_FALSE;
2649            return EmitSpecialPropOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, cg);
2650        }
2651    
2652      if (callContext) {      if (callContext) {
2653          JS_ASSERT(pn->pn_type == TOK_DOT);          JS_ASSERT(pn->pn_type == TOK_DOT);
2654          JS_ASSERT(op == JSOP_GETPROP);          JS_ASSERT(op == JSOP_GETPROP);
# Line 2344  Line 2683 
2683                    do_indexconst: {                    do_indexconst: {
2684                          JSAtomListElement *ale;                          JSAtomListElement *ale;
2685                          jsatomid atomIndex;                          jsatomid atomIndex;
2686                            
2687                          ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);                          ale = cg->atomList.add(cg->compiler, pn->pn_atom);
2688                          if (!ale)                          if (!ale)
2689                              return JS_FALSE;                              return JS_FALSE;
2690                          atomIndex = ALE_INDEX(ale);                          atomIndex = ALE_INDEX(ale);
2691                          return EmitSlotIndexOp(cx, op, pn2->pn_slot, atomIndex, cg);                          return EmitSlotIndexOp(cx, op, pn2->pn_cookie, atomIndex, cg);
2692                      }                      }
2693                        
2694                    default:;                    default:;
2695                  }                  }
2696              }              }
# Line 2370  Line 2709 
2709          for (;;) {          for (;;) {
2710              /* Reverse pndot->pn_expr to point up, not down. */              /* Reverse pndot->pn_expr to point up, not down. */
2711              pndot->pn_offset = top;              pndot->pn_offset = top;
2712                JS_ASSERT(!pndot->pn_used);
2713              pndown = pndot->pn_expr;              pndown = pndot->pn_expr;
2714              pndot->pn_expr = pnup;              pndot->pn_expr = pnup;
2715              if (pndown->pn_type != TOK_DOT)              if (pndown->pn_type != TOK_DOT)
# Line 2388  Line 2728 
2728                                 CG_OFFSET(cg) - pndown->pn_offset) < 0) {                                 CG_OFFSET(cg) - pndown->pn_offset) < 0) {
2729                  return JS_FALSE;                  return JS_FALSE;
2730              }              }
2731              if (!EmitAtomOp(cx, pndot, PN_OP(pndot), cg))  
2732                /*
2733                 * Special case deoptimization on __proto__, __count__ and
2734                 * __parent__, as above.
2735                 */
2736                if (pndot->pn_arity == PN_NAME &&
2737                    (pndot->pn_atom == cx->runtime->atomState.protoAtom ||
2738                     pndot->pn_atom == cx->runtime->atomState.parentAtom ||
2739                     pndot->pn_atom == cx->runtime->atomState.countAtom)) {
2740                    if (!EmitSpecialPropOp(cx, pndot, JSOP_GETELEM, cg))
2741                        return JS_FALSE;
2742                } else if (!EmitAtomOp(cx, pndot, PN_OP(pndot), cg)) {
2743                  return JS_FALSE;                  return JS_FALSE;
2744                }
2745    
2746              /* Reverse the pn_expr link again. */              /* Reverse the pn_expr link again. */
2747              pnup = pndot->pn_expr;              pnup = pndot->pn_expr;
# Line 2422  Line 2774 
2774          JS_ASSERT(pn->pn_op == JSOP_GETELEM);          JS_ASSERT(pn->pn_op == JSOP_GETELEM);
2775          JS_ASSERT(pn->pn_count >= 3);          JS_ASSERT(pn->pn_count >= 3);
2776          left = pn->pn_head;          left = pn->pn_head;
2777          right = PN_LAST(pn);          right = pn->last();
2778          next = left->pn_next;          next = left->pn_next;
2779          JS_ASSERT(next != right);          JS_ASSERT(next != right);
2780    
# Line 2478  Line 2830 
2830               * the base expression (pn_expr) of the name may be null, which               * the base expression (pn_expr) of the name may be null, which
2831               * means we have to emit a JSOP_BINDNAME.               * means we have to emit a JSOP_BINDNAME.
2832               */               */
2833              left = pn->pn_expr;              left = pn->maybeExpr();
2834              if (!left) {              if (!left) {
2835                  left = &ltmp;                  left = &ltmp;
2836                  left->pn_type = TOK_STRING;                  left->pn_type = TOK_STRING;
# Line 2572  Line 2924 
2924      if (!atom)      if (!atom)
2925          return JS_FALSE;          return JS_FALSE;
2926    
2927      ale = js_IndexAtom(cx, atom, &cg->atomList);      ale = cg->atomList.add(cg->compiler, atom);
2928      if (!ale)      if (!ale)
2929          return JS_FALSE;          return JS_FALSE;
2930      return EmitIndexOp(cx, JSOP_DOUBLE, ALE_INDEX(ale), cg);      return EmitIndexOp(cx, JSOP_DOUBLE, ALE_INDEX(ale), cg);
# Line 2622  Line 2974 
2974           * the stack so that case-dispatch bytecodes can find the discriminant           * the stack so that case-dispatch bytecodes can find the discriminant
2975           * on top of stack.           * on top of stack.
2976           */           */
2977          count = OBJ_BLOCK_COUNT(cx, pn2->pn_pob->object);          count = OBJ_BLOCK_COUNT(cx, pn2->pn_objbox->object);
2978          js_PushBlockScope(&cg->treeContext, stmtInfo, pn2->pn_pob->object, -1);          js_PushBlockScope(cg, stmtInfo, pn2->pn_objbox->object, -1);
2979          stmtInfo->type = STMT_SWITCH;          stmtInfo->type = STMT_SWITCH;
2980    
2981          /* Emit JSOP_ENTERBLOCK before code to evaluate the discriminant. */          /* Emit JSOP_ENTERBLOCK before code to evaluate the discriminant. */
2982          if (!EmitObjectOp(cx, pn2->pn_pob, JSOP_ENTERBLOCK, cg))          if (!EmitEnterBlock(cx, pn2, cg))
2983              return JS_FALSE;              return JS_FALSE;
2984    
2985          /*          /*
2986           * Pop the switch's statement info around discriminant code-gen.  Note           * Pop the switch's statement info around discriminant code-gen.  Note
2987           * how this leaves cg->treeContext.blockChain referencing the switch's           * how this leaves cg->blockChain referencing the switch's
2988           * block scope object, which is necessary for correct block parenting           * block scope object, which is necessary for correct block parenting
2989           * in the case where the discriminant contains a let expression.           * in the case where the discriminant contains a let expression.
2990           */           */
2991          cg->treeContext.topStmt = stmtInfo->down;          cg->topStmt = stmtInfo->down;
2992          cg->treeContext.topScopeStmt = stmtInfo->downScope;          cg->topScopeStmt = stmtInfo->downScope;
2993      }      }
2994  #ifdef __GNUC__  #ifdef __GNUC__
2995      else {      else {
# Line 2656  Line 3008 
3008      /* Switch bytecodes run from here till end of final case. */      /* Switch bytecodes run from here till end of final case. */
3009      top = CG_OFFSET(cg);      top = CG_OFFSET(cg);
3010  #if !JS_HAS_BLOCK_SCOPE  #if !JS_HAS_BLOCK_SCOPE
3011      js_PushStatement(&cg->treeContext, stmtInfo, STMT_SWITCH, top);      js_PushStatement(cg, stmtInfo, STMT_SWITCH, top);
3012  #else  #else
3013      if (pn2->pn_type == TOK_LC) {      if (pn2->pn_type == TOK_LC) {
3014          js_PushStatement(&cg->treeContext, stmtInfo, STMT_SWITCH, top);          js_PushStatement(cg, stmtInfo, STMT_SWITCH, top);
3015      } else {      } else {
3016          /* Re-push the switch's statement info record. */          /* Re-push the switch's statement info record. */
3017          cg->treeContext.topStmt = cg->treeContext.topScopeStmt = stmtInfo;          cg->topStmt = cg->topScopeStmt = stmtInfo;
3018    
3019          /* Set the statement info record's idea of top. */          /* Set the statement info record's idea of top. */
3020          stmtInfo->update = top;          stmtInfo->update = top;
3021    
3022          /* Advance pn2 to refer to the switch case list. */          /* Advance pn2 to refer to the switch case list. */
3023          pn2 = pn2->pn_expr;          pn2 = pn2->expr();
3024      }      }
3025  #endif  #endif
3026    
# Line 2703  Line 3055 
3055                  continue;                  continue;
3056    
3057              pn4 = pn3->pn_left;              pn4 = pn3->pn_left;
3058                while (pn4->pn_type == TOK_RP)
3059                    pn4 = pn4->pn_kid;
3060              switch (pn4->pn_type) {              switch (pn4->pn_type) {
3061                case TOK_NUMBER:                case TOK_NUMBER:
3062                  d = pn4->pn_dval;                  d = pn4->pn_dval;
# Line 2721  Line 3075 
3075                  pn3->pn_val = ATOM_KEY(pn4->pn_atom);                  pn3->pn_val = ATOM_KEY(pn4->pn_atom);
3076                  break;                  break;
3077                case TOK_NAME:                case TOK_NAME:
3078                  if (!pn4->pn_expr) {                  if (!pn4->maybeExpr()) {
3079                      ok = LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &v);                      ok = LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &v);
3080                      if (!ok)                      if (!ok)
3081                          goto release;                          goto release;
# Line 2789  Line 3143 
3143                      /* Just grab 8K for the worst-case bitmap. */                      /* Just grab 8K for the worst-case bitmap. */
3144                      intmap_bitlen = JS_BIT(16);                      intmap_bitlen = JS_BIT(16);
3145                      intmap = (jsbitmap *)                      intmap = (jsbitmap *)
3146                          JS_malloc(cx,                          cx->malloc((JS_BIT(16) >> JS_BITS_PER_WORD_LOG2)
3147                                    (JS_BIT(16) >> JS_BITS_PER_WORD_LOG2)                                     * sizeof(jsbitmap));
                                   * sizeof(jsbitmap));  
3148                      if (!intmap) {                      if (!intmap) {
3149                          JS_ReportOutOfMemory(cx);                          JS_ReportOutOfMemory(cx);
3150                          return JS_FALSE;                          return JS_FALSE;
# Line 2808  Line 3161 
3161    
3162        release:        release:
3163          if (intmap && intmap != intmap_space)          if (intmap && intmap != intmap_space)
3164              JS_free(cx, intmap);              cx->free(intmap);
3165          if (!ok)          if (!ok)
3166              return JS_FALSE;              return JS_FALSE;
3167    
# Line 2952  Line 3305 
3305               */               */
3306              if (tableLength != 0) {              if (tableLength != 0) {
3307                  tableSize = (size_t)tableLength * sizeof *table;                  tableSize = (size_t)tableLength * sizeof *table;
3308                  table = (JSParseNode **) JS_malloc(cx, tableSize);                  table = (JSParseNode **) cx->malloc(tableSize);
3309                  if (!table)                  if (!table)
3310                      return JS_FALSE;                      return JS_FALSE;
3311                  memset(table, 0, tableSize);                  memset(table, 0, tableSize);
# Line 3005  Line 3358 
3358                          (pn4 = pn3->pn_left) != NULL &&                          (pn4 = pn3->pn_left) != NULL &&
3359                          pn4->pn_type == TOK_NAME) {                          pn4->pn_type == TOK_NAME) {
3360                          /* Note a propagated constant with the const's name. */                          /* Note a propagated constant with the const's name. */
3361                          JS_ASSERT(!pn4->pn_expr);                          JS_ASSERT(!pn4->maybeExpr());
3362                          ale = js_IndexAtom(cx, pn4->pn_atom, &cg->atomList);                          ale = cg->atomList.add(cg->compiler, pn4->pn_atom);
3363                          if (!ale)                          if (!ale)
3364                              goto bad;                              goto bad;
3365                          CG_NEXT(cg) = pc;                          CG_NEXT(cg) = pc;
# Line 3022  Line 3375 
3375                      pn4 = pn3->pn_left;                      pn4 = pn3->pn_left;
3376                      if (pn4 && pn4->pn_type == TOK_NAME) {                      if (pn4 && pn4->pn_type == TOK_NAME) {
3377                          /* Note a propagated constant with the const's name. */                          /* Note a propagated constant with the const's name. */
3378                          JS_ASSERT(!pn4->pn_expr);                          JS_ASSERT(!pn4->maybeExpr());
3379                          ale = js_IndexAtom(cx, pn4->pn_atom, &cg->atomList);                          ale = cg->atomList.add(cg->compiler, pn4->pn_atom);
3380                          if (!ale)                          if (!ale)
3381                              goto bad;                              goto bad;
3382                          CG_NEXT(cg) = pc;                          CG_NEXT(cg) = pc;
# Line 3104  Line 3457 
3457                  continue;                  continue;
3458              if (!js_AtomizePrimitiveValue(cx, pn3->pn_val, &atom))              if (!js_AtomizePrimitiveValue(cx, pn3->pn_val, &atom))
3459                  goto bad;                  goto bad;
3460              ale = js_IndexAtom(cx, atom, &cg->atomList);              ale = cg->atomList.add(cg->compiler, atom);
3461              if (!ale)              if (!ale)
3462                  goto bad;                  goto bad;
3463              SET_INDEX(pc, ALE_INDEX(ale));              SET_INDEX(pc, ALE_INDEX(ale));
# Line 3120  Line 3473 
3473    
3474  out:  out:
3475      if (table)      if (table)
3476          JS_free(cx, table);          cx->free(table);
3477      if (ok) {      if (ok) {
3478          ok = js_PopStatementCG(cx, cg);          ok = js_PopStatementCG(cx, cg);
3479    
# Line 3139  Line 3492 
3492  JSBool  JSBool
3493  js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)  js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
3494  {  {
3495      if (cg->treeContext.flags & TCF_FUN_IS_GENERATOR) {      if (cg->flags & TCF_FUN_IS_GENERATOR) {
3496          /* JSOP_GENERATOR must be the first instruction. */          /* JSOP_GENERATOR must be the first instruction. */
3497          CG_SWITCH_TO_PROLOG(cg);          CG_SWITCH_TO_PROLOG(cg);
3498          JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg));          JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg));
3499          if (js_Emit1(cx, cg, JSOP_GENERATOR) < 0)          if (js_Emit1(cx, cg, JSOP_GENERATOR) < 0)
3500              return JS_FALSE;              return JS_FALSE;
3501          CG_SWITCH_TO_MAIN(cg);          CG_SWITCH_TO_MAIN(cg);
3502        } else {
3503            /*
3504             * Emit a trace hint opcode only if not in a generator, since generators
3505             * are not yet traced and both want to be the first instruction.
3506             */
3507            if (js_Emit1(cx, cg, JSOP_TRACE) < 0)
3508                return JS_FALSE;
3509      }      }
3510    
3511      return js_EmitTree(cx, cg, body) &&      return js_EmitTree(cx, cg, body) &&
# Line 3154  Line 3514 
3514  }  }
3515    
3516  /* 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). */
3517  #define UPDATE_LINE_NUMBER_NOTES(cx, cg, pn)                                  \  #define UPDATE_LINE_NUMBER_NOTES(cx, cg, line)                                \
3518      JS_BEGIN_MACRO                                                            \      JS_BEGIN_MACRO                                                            \
3519          uintN line_ = (pn)->pn_pos.begin.lineno;                              \          uintN line_ = (line);                                                 \
3520          uintN delta_ = line_ - CG_CURRENT_LINE(cg);                           \          uintN delta_ = line_ - CG_CURRENT_LINE(cg);                           \
3521          if (delta_ != 0) {                                                    \          if (delta_ != 0) {                                                    \
3522              /*                                                                \              /*                                                                \
# Line 3185  Line 3545 
3545    
3546  /* A function, so that we avoid macro-bloating all the other callsites. */  /* A function, so that we avoid macro-bloating all the other callsites. */
3547  static JSBool  static JSBool
3548  UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)  UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, uintN line)
3549  {  {
3550      UPDATE_LINE_NUMBER_NOTES(cx, cg, pn);      UPDATE_LINE_NUMBER_NOTES(cx, cg, line);
3551      return JS_TRUE;      return JS_TRUE;
3552  }  }
3553    
# Line 3198  Line 3558 
3558      jsatomid atomIndex;      jsatomid atomIndex;
3559      JSAtomListElement *ale;      JSAtomListElement *ale;
3560    
3561      if (pn->pn_slot >= 0) {      if (pn->pn_cookie != FREE_UPVAR_COOKIE) {
3562          atomIndex = (jsatomid) pn->pn_slot;          atomIndex = (jsatomid) UPVAR_FRAME_SLOT(pn->pn_cookie);
3563      } else {      } else {
3564          ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);          ale = cg->atomList.add(cg->compiler, pn->pn_atom);
3565          if (!ale)          if (!ale)
3566              return JS_FALSE;              return JS_FALSE;
3567          atomIndex = ALE_INDEX(ale);          atomIndex = ALE_INDEX(ale);
3568      }      }
3569    
3570      if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM &&      if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM &&
3571          (!(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. */  
3572          CG_SWITCH_TO_PROLOG(cg);          CG_SWITCH_TO_PROLOG(cg);
3573          if (!UpdateLineNumberNotes(cx, cg, pn))          if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno))
3574              return JS_FALSE;              return JS_FALSE;
3575          EMIT_INDEX_OP(prologOp, atomIndex);          EMIT_INDEX_OP(prologOp, atomIndex);
3576          CG_SWITCH_TO_MAIN(cg);          CG_SWITCH_TO_MAIN(cg);
# Line 3237  Line 3595 
3595      if (!BindNameToSlot(cx, cg, pn))      if (!BindNameToSlot(cx, cg, pn))
3596          return JS_FALSE;          return JS_FALSE;
3597    
3598      JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS);      JS_ASSERT(PN_OP(pn) != JSOP_ARGUMENTS && PN_OP(pn) != JSOP_CALLEE);
3599      return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL);      return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL);
3600  }  }
3601    
# Line 3280  Line 3638 
3638  {  {
3639      jsuint slot;      jsuint slot;
3640    
     /* Skip any parenthesization. */  
     while (pn->pn_type == TOK_RP)  
         pn = pn->pn_kid;  
   
3641      /*      /*
3642       * Now emit the lvalue opcode sequence.  If the lvalue is a nested       * Now emit the lvalue opcode sequence.  If the lvalue is a nested
3643       * destructuring initialiser-form, call ourselves to handle it, then       * destructuring initialiser-form, call ourselves to handle it, then
# 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 && pn->pn_arity == PN_NULLARY));
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;  
4103                  }                  }
 #ifdef __GNUC__  
                 else {  
                     stmt = scopeStmt = NULL;    /* quell GCC overwarning */  
                 }  
 #endif  
4104  #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;
4490          jmp = EmitJump(cx, cg, JSOP_GOTO, 0);          jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
4491          if (jmp < 0)          if (jmp < 0)
4492              return JS_FALSE;              return JS_FALSE;
4493          top = CG_OFFSET(cg);          top = js_Emit1(cx, cg, JSOP_TRACE);
4494            if (top < 0)
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 4181  Line 4513 
4513              return JS_FALSE;              return JS_FALSE;
4514    
4515          /* Compile the loop body. */          /* Compile the loop body. */
4516          top = CG_OFFSET(cg);          top = js_Emit1(cx, cg, JSOP_TRACE);
4517          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_DO_LOOP, top);          if (top < 0)
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_TRACE) < 0)
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_TRACE) < 0)
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 5268  Line 5608 
5608           * stack, which impose pervasive runtime "GetValue" costs.           * stack, which impose pervasive runtime "GetValue" costs.
5609           */           */
5610          pn2 = pn->pn_left;          pn2 = pn->pn_left;
         JS_ASSERT(pn2->pn_type != TOK_RP);  
5611          atomIndex = (jsatomid) -1;              /* quell GCC overwarning */          atomIndex = (jsatomid) -1;              /* quell GCC overwarning */
5612          switch (pn2->pn_type) {          switch (pn2->pn_type) {
5613            case TOK_NAME:            case TOK_NAME:
5614              if (!BindNameToSlot(cx, cg, pn2))              if (!BindNameToSlot(cx, cg, pn2))
5615                  return JS_FALSE;                  return JS_FALSE;
5616              if (pn2->pn_slot >= 0) {              if (pn2->pn_cookie != FREE_UPVAR_COOKIE) {
5617                  atomIndex = (jsatomid) pn2->pn_slot;                  atomIndex = (jsatomid) pn2->pn_cookie;
5618              } else {              } else {
5619                  ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);                  ale = cg->atomList.add(cg->compiler, pn2->pn_atom);
5620                  if (!ale)                  if (!ale)
5621                      return JS_FALSE;                      return JS_FALSE;
5622                  atomIndex = ALE_INDEX(ale);                  atomIndex = ALE_INDEX(ale);
5623                  EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);                  if (!pn2->isConst())
5624                        EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
5625              }              }
5626              break;              break;
5627            case TOK_DOT:            case TOK_DOT:
5628              if (!js_EmitTree(cx, cg, pn2->pn_expr))              if (!js_EmitTree(cx, cg, pn2->expr()))
5629                  return JS_FALSE;                  return JS_FALSE;
5630              ale = js_IndexAtom(cx, pn2->pn_atom, &cg->atomList);              ale = cg->atomList.add(cg->compiler, pn2->pn_atom);
5631              if (!ale)              if (!ale)
5632                  return JS_FALSE;                  return JS_FALSE;
5633              atomIndex = ALE_INDEX(ale);              atomIndex = ALE_INDEX(ale);
# Line 5332  Line 5672 
5672                   * supported.                   * supported.
5673                   */                   */
5674                  js_ReportCompileErrorNumber(cx,                  js_ReportCompileErrorNumber(cx,
5675                                              TS(cg->treeContext.parseContext),                                              TS(cg->compiler),
5676                                              pn2, JSREPORT_ERROR,                                              pn2, JSREPORT_ERROR,
5677                                              JSMSG_BAD_GETTER_OR_SETTER,                                              JSMSG_BAD_GETTER_OR_SETTER,
5678                                              (op == JSOP_GETTER)                                              (op == JSOP_GETTER)
# Line 5348  Line 5688 
5688          if (op != JSOP_NOP) {          if (op != JSOP_NOP) {
5689              switch (pn2->pn_type) {              switch (pn2->pn_type) {
5690                case TOK_NAME:                case TOK_NAME:
5691                  if (pn2->pn_op != JSOP_SETNAME) {                  if (pn2->isConst()) {
5692                      EMIT_UINT16_IMM_OP((pn2->pn_op == JSOP_SETGVAR)                      if (PN_OP(pn2) == JSOP_CALLEE) {
5693                            if (js_Emit1(cx, cg, JSOP_CALLEE) < 0)
5694                                return JS_FALSE;
5695                        } else {
5696                            EMIT_INDEX_OP(PN_OP(pn2), atomIndex);
5697                        }
5698                    } else if (PN_OP(pn2) == JSOP_SETNAME) {
5699                        if (js_Emit1(cx, cg, JSOP_DUP) < 0)
5700                            return JS_FALSE;
5701                        EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex);
5702                    } else {
5703                        EMIT_UINT16_IMM_OP((PN_OP(pn2) == JSOP_SETGVAR)
5704                                         ? JSOP_GETGVAR                                         ? JSOP_GETGVAR
5705                                         : (pn2->pn_op == JSOP_SETARG)                                         : (PN_OP(pn2) == JSOP_GETUPVAR)
5706                                           ? JSOP_GETUPVAR
5707                                           : (PN_OP(pn2) == JSOP_SETARG)
5708                                         ? JSOP_GETARG                                         ? JSOP_GETARG
5709                                         : JSOP_GETLOCAL,                                         : JSOP_GETLOCAL,
5710                                         atomIndex);                                         atomIndex);
                     break;  
5711                  }                  }
                 if (js_Emit1(cx, cg, JSOP_DUP) < 0)  
                     return JS_FALSE;  
                 EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex);  
5712                  break;                  break;
5713                case TOK_DOT:                case TOK_DOT:
5714                  if (js_Emit1(cx, cg, JSOP_DUP) < 0)                  if (js_Emit1(cx, cg, JSOP_DUP) < 0)
# Line 5367  Line 5716 
5716                  if (pn2->pn_atom == cx->runtime->atomState.lengthAtom) {                  if (pn2->pn_atom == cx->runtime->atomState.lengthAtom) {
5717                      if (js_Emit1(cx, cg, JSOP_LENGTH) < 0)                      if (js_Emit1(cx, cg, JSOP_LENGTH) < 0)
5718                          return JS_FALSE;                          return JS_FALSE;
5719                    } else if (pn2->pn_atom == cx->runtime->atomState.protoAtom) {
5720                        if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, cg))
5721                            return JS_FALSE;
5722                        if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
5723                            return JS_FALSE;
5724                  } else {                  } else {
5725                      EMIT_INDEX_OP(JSOP_GETPROP, atomIndex);                      EMIT_INDEX_OP(JSOP_GETPROP, atomIndex);
5726                  }                  }
# Line 5394  Line 5748 
5748          /* If += etc., emit the binary operator with a decompiler note. */          /* If += etc., emit the binary operator with a decompiler note. */
5749          if (op != JSOP_NOP) {          if (op != JSOP_NOP) {
5750              /*              /*
5751               * 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
5752               * const declared in a function (i.e., with non-negative pn_slot               * declared in the current compilation unit, as in this case (just
5753               * 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.
5754               * below) we will avoid emitting the assignment op.               */
5755               */              if (pn2->pn_type != TOK_NAME || !pn2->isConst()) {
             if (pn2->pn_type != TOK_NAME ||  
                 pn2->pn_slot < 0 ||  
                 !pn2->pn_const) {  
5756                  if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0)                  if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0)
5757                      return JS_FALSE;                      return JS_FALSE;
5758              }              }
# Line 5422  Line 5773 
5773          /* Finally, emit the specialized assignment bytecode. */          /* Finally, emit the specialized assignment bytecode. */
5774          switch (pn2->pn_type) {          switch (pn2->pn_type) {
5775            case TOK_NAME:            case TOK_NAME:
5776              if (pn2->pn_slot >= 0) {              if (pn2->isConst())
                 if (!pn2->pn_const)  
                     EMIT_UINT16_IMM_OP(PN_OP(pn2), atomIndex);  
5777                  break;                  break;
             }  
5778              /* FALL THROUGH */              /* FALL THROUGH */
5779            case TOK_DOT:            case TOK_DOT:
5780              EMIT_INDEX_OP(PN_OP(pn2), atomIndex);              EMIT_INDEX_OP(PN_OP(pn2), atomIndex);
# Line 5558  Line 5906 
5906          }          }
5907          break;          break;
5908    
5909          case TOK_PLUS:
5910            /* For TCF_IN_FUNCTION test, see TOK_RB concerning JSOP_NEWARRAY. */
5911            if (pn->pn_arity == PN_LIST && pn->pn_count < JS_BIT(16) &&
5912                (cg->flags & TCF_IN_FUNCTION)) {
5913                /* Emit up to the first string literal conventionally. */
5914                for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
5915                    if (pn2->pn_type == TOK_STRING)
5916                        break;
5917                    if (!js_EmitTree(cx, cg, pn2))
5918                        return JS_FALSE;
5919                    if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)
5920                        return JS_FALSE;
5921                }
5922    
5923                /* Emit remainder as a single JSOP_CONCATN. */
5924                for (index = 0; pn2; pn2 = pn2->pn_next, index++) {
5925                    if (!js_EmitTree(cx, cg, pn2))
5926                        return JS_FALSE;
5927                }
5928    
5929                if (index != 0) {
5930                    EMIT_UINT16_IMM_OP(JSOP_CONCATN, index);
5931    
5932                    /* If we had a prefix, we need to be added to it now. */
5933                    if (pn->pn_head->pn_type != TOK_STRING &&
5934                        js_Emit1(cx, cg, JSOP_ADD) < 0) {
5935                        return JS_FALSE;
5936                    }
5937                }
5938                break;
5939            }
5940        case TOK_BITOR:        case TOK_BITOR:
5941        case TOK_BITXOR:        case TOK_BITXOR:
5942        case TOK_BITAND:        case TOK_BITAND:
# Line 5566  Line 5945 
5945        case TOK_IN:        case TOK_IN:
5946        case TOK_INSTANCEOF:        case TOK_INSTANCEOF:
5947        case TOK_SHOP:        case TOK_SHOP:
       case TOK_PLUS:  
5948        case TOK_MINUS:        case TOK_MINUS:
5949        case TOK_STAR:        case TOK_STAR:
5950        case TOK_DIVOP:        case TOK_DIVOP:
# Line 5588  Line 5966 
5966    
5967        case TOK_DBLCOLON:        case TOK_DBLCOLON:
5968              if (pn->pn_arity == PN_NAME) {              if (pn->pn_arity == PN_NAME) {
5969                  if (!js_EmitTree(cx, cg, pn->pn_expr))                  if (!js_EmitTree(cx, cg, pn->expr()))
5970                      return JS_FALSE;                      return JS_FALSE;
5971                  if (!EmitAtomOp(cx, pn, PN_OP(pn), cg))                  if (!EmitAtomOp(cx, pn, PN_OP(pn), cg))
5972                      return JS_FALSE;                      return JS_FALSE;
# Line 5600  Line 5978 
5978               * possibly including a let (a = b) ... expression.  We must clear               * possibly including a let (a = b) ... expression.  We must clear
5979               * TCF_IN_FOR_INIT to avoid mis-compiling such beasts.               * TCF_IN_FOR_INIT to avoid mis-compiling such beasts.
5980               */               */
5981              oldflags = cg->treeContext.flags;              oldflags = cg->flags;
5982              cg->treeContext.flags &= ~TCF_IN_FOR_INIT;              cg->flags &= ~TCF_IN_FOR_INIT;
5983  #endif  #endif
5984    
5985              /* Binary operators that evaluate both operands unconditionally. */              /* Binary operators that evaluate both operands unconditionally. */
# Line 5610  Line 5988 
5988              if (!js_EmitTree(cx, cg, pn->pn_right))              if (!js_EmitTree(cx, cg, pn->pn_right))
5989                  return JS_FALSE;                  return JS_FALSE;
5990  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
5991              cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;              cg->flags |= oldflags & TCF_IN_FOR_INIT;
5992  #endif  #endif
5993              if (js_Emit1(cx, cg, PN_OP(pn)) < 0)              if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
5994                  return JS_FALSE;                  return JS_FALSE;
# Line 5638  Line 6016 
6016          }          }
6017  #endif  #endif
6018          pn2 = pn->pn_kid;          pn2 = pn->pn_kid;
6019          if (op == JSOP_TYPEOF) {  
6020              for (pn3 = pn2; pn3->pn_type == TOK_RP; pn3 = pn3->pn_kid)          /* See js_FoldConstants for why this assertion holds true. */
6021                  continue;          JS_ASSERT_IF(op == JSOP_TYPEOF, pn2->pn_type == TOK_NAME);
6022              if (pn3->pn_type != TOK_NAME)  
6023                  op = JSOP_TYPEOFEXPR;          oldflags = cg->flags;
6024          }          cg->flags &= ~TCF_IN_FOR_INIT;
         oldflags = cg->treeContext.flags;  
         cg->treeContext.flags &= ~TCF_IN_FOR_INIT;  
6025          if (!js_EmitTree(cx, cg, pn2))          if (!js_EmitTree(cx, cg, pn2))
6026              return JS_FALSE;              return JS_FALSE;
6027          cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;          cg->flags |= oldflags & TCF_IN_FOR_INIT;
6028          if (js_Emit1(cx, cg, op) < 0)          if (js_Emit1(cx, cg, op) < 0)
6029              return JS_FALSE;              return JS_FALSE;
6030          break;          break;
# Line 5667  Line 6043 
6043              if (!BindNameToSlot(cx, cg, pn2))              if (!BindNameToSlot(cx, cg, pn2))
6044                  return JS_FALSE;                  return JS_FALSE;
6045              op = PN_OP(pn2);              op = PN_OP(pn2);
6046              if (pn2->pn_slot >= 0) {              if (op == JSOP_CALLEE) {
6047                  if (pn2->pn_const) {                  if (js_Emit1(cx, cg, op) < 0)
6048                      /* Incrementing a declared const: just get its value. */                      return JS_FALSE;
6049                      op = (JOF_OPTYPE(op) == JOF_ATOM)              } else if (pn2->pn_cookie != FREE_UPVAR_COOKIE) {
6050                           ? JSOP_GETGVAR                  atomIndex = (jsatomid) pn2->pn_cookie;
                          : JSOP_GETLOCAL;  
                 }  
                 atomIndex = (jsatomid) pn2->pn_slot;  
6051                  EMIT_UINT16_IMM_OP(op, atomIndex);                  EMIT_UINT16_IMM_OP(op, atomIndex);
6052              } else {              } else {
6053                    JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
6054                  if (!EmitAtomOp(cx, pn2, op, cg))                  if (!EmitAtomOp(cx, pn2, op, cg))
6055                      return JS_FALSE;                      return JS_FALSE;
6056                    break;
6057                }
6058                if (pn2->isConst()) {
6059                    if (js_Emit1(cx, cg, JSOP_POS) < 0)
6060                        return JS_FALSE;
6061                    op = PN_OP(pn);
6062                    if (!(js_CodeSpec[op].format & JOF_POST)) {
6063                        if (js_Emit1(cx, cg, JSOP_ONE) < 0)
6064                            return JS_FALSE;
6065                        op = (js_CodeSpec[op].format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
6066                        if (js_Emit1(cx, cg, op) < 0)
6067                            return JS_FALSE;
6068                    }
6069              }              }
6070              break;              break;
6071            case TOK_DOT:            case TOK_DOT:
# Line 5723  Line 6110 
6110          pn2 = pn->pn_kid;          pn2 = pn->pn_kid;
6111          switch (pn2->pn_type) {          switch (pn2->pn_type) {
6112            case TOK_NAME:            case TOK_NAME:
             pn2->pn_op = JSOP_DELNAME;  
6113              if (!BindNameToSlot(cx, cg, pn2))              if (!BindNameToSlot(cx, cg, pn2))
6114                  return JS_FALSE;                  return JS_FALSE;
6115              op = PN_OP(pn2);              op = PN_OP(pn2);
# Line 5763  Line 6149 
6149            default:            default:
6150              /*              /*
6151               * If useless, just emit JSOP_TRUE; otherwise convert delete foo()               * If useless, just emit JSOP_TRUE; otherwise convert delete foo()
6152               * 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).  
6153               */               */
6154              useful = JS_FALSE;              useful = JS_FALSE;
6155              if (!CheckSideEffects(cx, cg, pn2, &useful))              if (!CheckSideEffects(cx, cg, pn2, &useful))
# Line 5786  Line 6171 
6171                  if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))                  if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))
6172                      return JS_FALSE;                      return