/[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 399 by siliconforks, Tue Dec 9 03:37:47 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 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;  
                 }  
   
                 JS_ASSERT(cg->staticDepth > caller->fun->u.i.script->staticDepth);  
                 uintN skip = cg->staticDepth - caller->fun->u.i.script->staticDepth;  
                 cg->upvarMap.vector[ALE_INDEX(ale)] = MAKE_UPVAR_COOKIE(skip, index);  
             }  
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);  
   
         /* Index atom so we can map fast global number to name. */  
         ale = js_IndexAtom(cx, atom, &cg->atomList);  
         if (!ale)  
             return JS_FALSE;  
2067    
2068          /* Defend against tc->ngvars 16-bit overflow. */          /*
2069          slot = ALE_INDEX(ale);           * We are optimizing global variables and there may be no pre-existing
2070          if ((slot + 1) >> 16)           * global property named atom when this global script runs. If atom was
2071              return JS_TRUE;           * declared via const or var, optimize pn to access fp->vars using the
2072             * appropriate JSOP_*GVAR op.
2073          if ((uint16)(slot + 1) > tc->ngvars)           *
2074              tc->ngvars = (uint16)(slot + 1);           * FIXME: should be able to optimize global function access too.
2075             */
2076            JS_ASSERT(dn_kind == JSDefinition::VAR || dn_kind == JSDefinition::CONST);
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 1967  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           * We are compiling a function body and may be able to optimize name           * Don't generate upvars on the left side of a for loop. See
2127           * to stack slot. Look for an argument or variable in the function and           * bug 470758 and bug 520513.
          * rewrite pn_op and update pn accordingly.  
2128           */           */
2129          localKind = js_LookupLocal(cx, tc->u.fun, atom, &index);          if (evalcg->flags & TCF_IN_FOR_INIT)
2130          if (localKind != JSLOCAL_NONE) {              return JS_TRUE;
2131              op = PN_OP(pn);  
2132              if (localKind == JSLOCAL_ARG) {          if (cg->staticLevel == level) {
2133                  switch (op) {              pn->pn_op = JSOP_GETUPVAR;
2134                    case JSOP_NAME:     op = JSOP_GETARG; break;              pn->pn_cookie = cookie;
2135                    case JSOP_SETNAME:  op = JSOP_SETARG; break;              pn->pn_dflags |= PND_BOUND;
2136                    case JSOP_INCNAME:  op = JSOP_INCARG; break;              return JS_TRUE;
2137                    case JSOP_NAMEINC:  op = JSOP_ARGINC; break;          }
2138                    case JSOP_DECNAME:  op = JSOP_DECARG; break;  
2139                    case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;          return MakeUpvarForEval(pn, cg);
2140                    case JSOP_FORNAME:  op = JSOP_FORARG; break;      }
2141                    case JSOP_DELNAME:  op = JSOP_FALSE; break;  
2142                    default: JS_NOT_REACHED("arg");      uintN skip = cg->staticLevel - level;
2143                  }      if (skip != 0) {
2144                  pn->pn_const = JS_FALSE;          JS_ASSERT(cg->flags & TCF_IN_FUNCTION);
2145              } else {          JS_ASSERT_IF(UPVAR_FRAME_SLOT(cookie) != CALLEE_UPVAR_SLOT,
2146                  JS_ASSERT(localKind == JSLOCAL_VAR ||                       cg->lexdeps.lookup(atom));
2147                            localKind == JSLOCAL_CONST);          JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
2148                  switch (op) {          JS_ASSERT(cg->fun->u.i.skipmin <= skip);
2149                    case JSOP_NAME:     op = JSOP_GETLOCAL; break;  
2150                    case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;          /*
2151                    case JSOP_SETCONST: op = JSOP_SETLOCAL; break;           * If op is a mutating opcode, this upvar's static level is too big to
2152                    case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;           * index into the display, or the function is heavyweight, we fall back
2153                    case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;           * on JSOP_*NAME*.
2154                    case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;           */
2155                    case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;          if (op != JSOP_NAME)
2156                    case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;              return JS_TRUE;
2157                    case JSOP_DELNAME:  op = JSOP_FALSE; break;          if (level >= JS_DISPLAY_SIZE)
2158                    default: JS_NOT_REACHED("local");              return JS_TRUE;
2159            if (cg->flags & TCF_FUN_HEAVYWEIGHT)
2160                return JS_TRUE;
2161    
2162            if (FUN_FLAT_CLOSURE(cg->fun)) {
2163                op = JSOP_GETDSLOT;
2164            } else {
2165                /*
2166                 * The function we're compiling may not be heavyweight, but if it
2167                 * escapes as a funarg, we can't use JSOP_GETUPVAR/JSOP_CALLUPVAR.
2168                 * JSCompiler::analyzeFunctions has arranged for this function's
2169                 * enclosing functions to be heavyweight, so we can safely stick
2170                 * with JSOP_NAME/JSOP_CALLNAME.
2171                 */
2172                if (cg->funbox->node->pn_dflags & PND_FUNARG)
2173                    return JS_TRUE;
2174    
2175                /*
2176                 * Generator functions may be resumed from any call stack, which
2177                 * defeats the display optimization to static link searching used
2178                 * by JSOP_{GET,CALL}UPVAR.
2179                 */
2180                if (cg->flags & TCF_FUN_IS_GENERATOR)
2181                    return JS_TRUE;
2182    
2183                op = JSOP_GETUPVAR;
2184            }
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 2057  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 2067  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:
# Line 2134  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 ||              if (pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
# Line 2162  Line 2436 
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 2216  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 2240  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 2275  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 2310  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 2325  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 2367  Line 2684 
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:;
# Line 2392  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 2410  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 2444  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 2500  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 2594  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 2644  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 2678  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 2725  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 2743  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 2811  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 2830  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 2974  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 3027  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 3044  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 3126  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 3142  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 3161  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 3176  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 3207  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 3220  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 3259  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 3302  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 3318  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 3338  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 3404  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 3488  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 3497  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 3508  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 3522  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 3570  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 3580  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 3596  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 3623  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 3651  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 will               * A destructuring initialiser assignment preceded by var will
# Line 3660  Line 3999 
3999               */               */
4000              JS_ASSERT(pn2->pn_type == TOK_ASSIGN);              JS_ASSERT(pn2->pn_type == TOK_ASSIGN);
4001              JS_ASSERT(!forInVar);              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) {              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,
# Line 3675  Line 4032 
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 3698  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                  JS_ASSERT(!forInVar);                  JS_ASSERT(!forInVar);
4089                  if (op == JSOP_SETNAME) {                  if (op == JSOP_SETNAME) {
# Line 3727  Line 4091 
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              }              }
# Line 3769  Line 4126 
4126           * emit op or any source note. Our caller, the TOK_FOR/TOK_IN case in           * emit op or any source note. Our caller, the TOK_FOR/TOK_IN case in
4127           * js_EmitTree, will annotate appropriately.           * js_EmitTree, will annotate appropriately.
4128           */           */
4129          JS_ASSERT(pn3 == pn2->pn_expr);          JS_ASSERT_IF(pn2->pn_defn, pn3 == pn2->pn_expr);
4130          if (forInVar) {          if (forInVar) {
4131              JS_ASSERT(pn->pn_count == 1);              JS_ASSERT(pn->pn_count == 1);
4132              JS_ASSERT(!pn3);              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 3789  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 3803  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 3816  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 3871  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 3879  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 3897  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 3905  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 3980  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 3993  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 4016  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 4114  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 4142  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 4174  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) {
4553              /* Set stmtInfo type for later testing. */              /* Set stmtInfo type for later testing. */
# Line 4188  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 4207  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 4240  Line 4613 
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  #ifdef DEBUG
4620              intN loopDepth = cg->stackDepth;              intN loopDepth = cg->stackDepth;
# Line 4290  Line 4665 
4665  #if JS_HAS_BLOCK_SCOPE  #if JS_HAS_BLOCK_SCOPE
4666                       type == TOK_LET ||                       type == TOK_LET ||
4667  #endif  #endif
4668                       (type == TOK_VAR && !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                  if (pn3->pn_slot >= 0) {                  if (pn3->pn_cookie != FREE_UPVAR_COOKIE) {
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 4314  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                          js_ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR,                      return JS_FALSE;
4696                                                      JSMSG_BAD_FOR_LEFTSIDE);                  }
4697                          return JS_FALSE;                  if (pn3->pn_cookie != FREE_UPVAR_COOKIE) {
4698                      }                      atomIndex = (jsatomid) pn3->pn_cookie;
                     atomIndex = (jsatomid) pn3->pn_slot;  
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 4335  Line 4709 
4709                   * has no side effects.                   * 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 4421  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 4439  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              /*              /*
# Line 4468  Line 4842 
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    
# Line 4563  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 4584  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 4613  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 4635  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 4759  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 4786  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 4829  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 4880  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 4914  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 5001  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 5022  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 5036  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 5055  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 5073  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 5086  Line 5473 
5473    
5474          ok = js_PopStatementCG(cx, cg);          ok = js_PopStatementCG(cx, cg);
5475          break;          break;
5476          }
5477    
5478        case TOK_SEQ:        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_SEQ, 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 5109  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 5123  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 5155  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 5172  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 5222  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 5286  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 5302  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 5321  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 5348  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 5376  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 5512  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 5520  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 5542  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 5554  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 5564  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 5592  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 5621  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 5677  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 5749  Line 6181 
6181          jmp = js_Emit3(cx, cg, JSOP_FILTER, 0, 0);          jmp = js_Emit3(cx, cg, JSOP_FILTER, 0, 0);
6182          if (jmp < 0)          if (jmp < 0)
6183              return JS_FALSE;              return JS_FALSE;
6184          top = CG_OFFSET(cg);          top = js_Emit1(cx, cg, JSOP_TRACE);
6185            if (top < 0)
6186                return JS_FALSE;
6187          if (!js_EmitTree(cx, cg, pn->pn_right))          if (!js_EmitTree(cx, cg, pn->pn_right))
6188              return JS_FALSE;              return JS_FALSE;
6189          CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);          CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
# Line 5817  Line 6251 
6251            default:            default:
6252              /*              /*
6253               * Push null as a placeholder for the global object, per ECMA-262               * Push null as a placeholder for the global object, per ECMA-262
6254               * 11.2.3 step 6. We use JSOP_NULLTHIS to distinguish this opcode               * 11.2.3 step 6.
              * from JSOP_NULL (see jstracer.cpp for one use-case).  
6255               */               */
6256              if (!js_EmitTree(cx, cg, pn2))              if (!js_EmitTree(cx, cg, pn2))
6257                  return JS_FALSE;                  return JS_FALSE;
6258              if (js_Emit1(cx, cg, JSOP_NULLTHIS) < 0)              if (js_Emit1(cx, cg, JSOP_NULL) < 0)
6259                  return JS_FALSE;                  return JS_FALSE;
6260          }          }
6261    
# Line 5834  Line 6267 
6267           * JSOP_NEW bytecode with a two-byte immediate telling how many args           * JSOP_NEW bytecode with a two-byte immediate telling how many args
6268           * were pushed on the operand stack.           * were pushed on the operand stack.
6269           */           */
6270          oldflags = cg->treeContext.flags;          oldflags = cg->flags;
6271          cg->treeContext.flags &= ~TCF_IN_FOR_INIT;          cg->flags &= ~TCF_IN_FOR_INIT;
6272          for (pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {          for (pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
6273              if (!js_EmitTree(cx, cg, pn3))              if (!js_EmitTree(cx, cg, pn3))
6274                  return JS_FALSE;                  return JS_FALSE;
6275          }          }
6276          cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;          cg->flags |= oldflags & TCF_IN_FOR_INIT;
6277          if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)          if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)
6278              return JS_FALSE;              return JS_FALSE;
6279    
# Line 5854  Line 6287 
6287    
6288        case TOK_LEXICALSCOPE:        case TOK_LEXICALSCOPE:
6289        {        {
6290          JSParsedObjectBox *pob;          JSObjectBox *objbox;
6291          uintN count;          uintN count;
6292    
6293          pob = pn->pn_pob;          objbox = pn->pn_objbox;
6294          js_PushBlockScope(&cg->treeContext, &stmtInfo, pob->object,          js_PushBlockScope(cg, &stmtInfo, objbox->object, CG_OFFSET(cg));
                           CG_OFFSET(cg));  
6295    
6296          /*          /*
6297           * If this lexical scope is not for a catch block, let block or let           * If this lexical scope is not for a catch block, let block or let
# Line 5870  Line 6302 
6302           * statements get braces by default from the decompiler.           * statements get braces by default from the decompiler.
6303           */           */
6304          noteIndex = -1;          noteIndex = -1;
6305          type = PN_TYPE(pn->pn_expr);          type = PN_TYPE(pn->expr());
6306          if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR &&          if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR &&
6307              (!(stmt = stmtInfo.down)              (!(stmt = stmtInfo.down)
6308               ? !(cg->treeContext.flags & TCF_IN_FUNCTION)               ? !(cg->flags & TCF_IN_FUNCTION)
6309               : stmt->type == STMT_BLOCK)) {               : stmt->type == STMT_BLOCK)) {
6310  #if defined DEBUG_brendanXXX || defined DEBUG_mrbkap  #if defined DEBUG_brendan || defined DEBUG_mrbkap
6311              /* There must be no source note already output for the next op. */              /* There must be no source note already output for the next op. */
6312              JS_ASSERT(CG_NOTE_COUNT(cg) == 0 ||              JS_ASSERT(CG_NOTE_COUNT(cg) == 0 ||
6313                        CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) ||                        CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) ||
# Line 5887  Line 6319 
6319          }          }
6320    
6321          JS_ASSERT(CG_OFFSET(cg) == top);          JS_ASSERT(CG_OFFSET(cg) == top);
6322          if (!EmitObjectOp(cx, pob, JSOP_ENTERBLOCK, cg))          if (!EmitEnterBlock(cx, pn, cg))
6323              return JS_FALSE;              return JS_FALSE;
6324    
6325          if (!js_EmitTree(cx, cg, pn->pn_expr))          if (!js_EmitTree(cx, cg, pn->pn_expr))
# Line 5906  Line 6338 
6338          }          }
6339    
6340          /* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */          /* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */
6341          count = OBJ_BLOCK_COUNT(cx, pob->object);          count = OBJ_BLOCK_COUNT(cx, objbox->object);
6342          EMIT_UINT16_IMM_OP(op, count);          EMIT_UINT16_IMM_OP(op, count);
6343    
6344          ok = js_PopStatementCG(cx, cg);          ok = js_PopStatementCG(cx, cg);
# Line 5952  Line 6384 
6384           */           */
6385          if (!js_EmitTree(cx, cg, pn->pn_kid))          if (!js_EmitTree(cx, cg, pn->pn_kid))
6386              return JS_FALSE;              return JS_FALSE;
6387          slot = cg->arrayCompDepth;          slot = AdjustBlockSlot(cx, cg, cg->arrayCompDepth);
         slot = AdjustBlockSlot(cx, cg, slot);  
6388          if (slot < 0)          if (slot < 0)
6389              return JS_FALSE;              return JS_FALSE;
6390          EMIT_UINT16_IMM_OP(PN_OP(pn), slot);          EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
# Line 5966  Line 6397 
6397        case TOK_ARRAYCOMP:        case TOK_ARRAYCOMP:
6398  #endif  #endif
6399          /*          /*
6400           * Emit code for [a, b, c] of the form:           * Emit code for [a, b, c] that is equivalent to constructing a new
6401             * array and in source order evaluating each element value and adding
6402             * it to the array, without invoking latent setters.  We use the
6403             * JSOP_NEWINIT and JSOP_INITELEM bytecodes to ignore setters and to
6404             * avoid dup'ing and popping the array as each element is added, as
6405             * JSOP_SETELEM/JSOP_SETPROP would do.
6406           *           *
6407           *   t = new Array; t[0] = a; t[1] = b; t[2] = c; t;           * If no sharp variable is defined, the initializer is not for an array
6408           *           * comprehension, the initializer is not overlarge, and the initializer
6409           * but use a stack slot for t and avoid dup'ing and popping it using           * is not in global code (whose stack growth cannot be precisely modeled
6410           * the JSOP_NEWINIT and JSOP_INITELEM bytecodes.           * due to the need to reserve space for global variables and regular
6411           *           * expressions), use JSOP_NEWARRAY to minimize opcodes and to create the
6412           * If no sharp variable is defined and the initialiser is not for an           * array using a fast, all-at-once process rather than a slow, element-
6413           * array comprehension, use JSOP_NEWARRAY.           * by-element process.
6414           */           */
         pn2 = pn->pn_head;  
         op = JSOP_NEWINIT;      // FIXME: 260106 patch disabled for now  
   
6415  #if JS_HAS_SHARP_VARS  #if JS_HAS_SHARP_VARS
6416          if (pn2 && pn2->pn_type == TOK_DEFSHARP)          sharpnum = -1;
6417              op = JSOP_NEWINIT;        do_emit_array:
6418  #endif  #endif
6419    
6420            op = (JS_LIKELY(pn->pn_count < JS_BIT(16)) && (cg->flags & TCF_IN_FUNCTION))
6421                 ? JSOP_NEWARRAY
6422                 : JSOP_NEWINIT;
6423    
6424  #if JS_HAS_GENERATORS  #if JS_HAS_GENERATORS
6425          if (pn->pn_type == TOK_ARRAYCOMP)          if (pn->pn_type == TOK_ARRAYCOMP)
6426              op = JSOP_NEWINIT;              op = JSOP_NEWINIT;
6427  #endif  #endif
6428    #if JS_HAS_SHARP_VARS
6429            JS_ASSERT_IF(sharpnum >= 0, cg->flags & TCF_HAS_SHARPS);
6430            if (cg->flags & TCF_HAS_SHARPS)
6431                op = JSOP_NEWINIT;
6432    #endif
6433    
6434          if (op == JSOP_NEWINIT &&          if (op == JSOP_NEWINIT) {
6435              js_Emit2(cx, cg, op, (jsbytecode) JSProto_Array) < 0) {              if (js_Emit2(cx, cg, op, (jsbytecode) JSProto_Array) < 0)
6436              return JS_FALSE;                  return JS_FALSE;
         }  
   
6437  #if JS_HAS_SHARP_VARS  #if JS_HAS_SHARP_VARS
6438          if (pn2 && pn2->pn_type == TOK_DEFSHARP) {              if (sharpnum >= 0)
6439              EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);                  EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) sharpnum);
6440              pn2 = pn2->pn_next;  # endif
6441          }          }
 #endif  
6442    
6443  #if JS_HAS_GENERATORS  #if JS_HAS_GENERATORS
6444          if (pn->pn_type == TOK_ARRAYCOMP) {          if (pn->pn_type == TOK_ARRAYCOMP) {
6445              uintN saveDepth;              uintN saveDepth;
6446    
6447              /*              /*
6448               * Pass the new array's stack index to the TOK_ARRAYPUSH case by               * Pass the new array's stack index to the TOK_ARRAYPUSH case via
6449               * storing it in pn->pn_extra, then simply traverse the TOK_FOR               * cg->arrayCompDepth, then simply traverse the TOK_FOR node and
6450               * node and its kids under pn2 to generate this comprehension.               * its kids under pn2 to generate this comprehension.
6451               */               */
6452              JS_ASSERT(cg->stackDepth > 0);              JS_ASSERT(cg->stackDepth > 0);
6453              saveDepth = cg->arrayCompDepth;              saveDepth = cg->arrayCompDepth;
6454              cg->arrayCompDepth = (uint32) (cg->stackDepth - 1);              cg->arrayCompDepth = (uint32) (cg->stackDepth - 1);
6455              if (!js_EmitTree(cx, cg, pn2))              if (!js_EmitTree(cx, cg, pn->pn_head))
6456                  return JS_FALSE;                  return JS_FALSE;
6457              cg->arrayCompDepth = saveDepth;              cg->arrayCompDepth = saveDepth;
6458    
# Line 6023  Line 6463 
6463          }          }
6464  #endif /* JS_HAS_GENERATORS */  #endif /* JS_HAS_GENERATORS */
6465    
6466            pn2 = pn->pn_head;
6467          for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {          for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
6468              if (op == JSOP_NEWINIT && !EmitNumberOp(cx, atomIndex, cg))              if (op == JSOP_NEWINIT && !EmitNumberOp(cx, atomIndex, cg))
6469                  return JS_FALSE;                  return JS_FALSE;
6470                if (pn2->pn_type == TOK_COMMA && pn2->pn_arity == PN_NULLARY) {
             if (pn2->pn_type == TOK_COMMA) {  
6471                  if (js_Emit1(cx, cg, JSOP_HOLE) < 0)                  if (js_Emit1(cx, cg, JSOP_HOLE) < 0)
6472                      return JS_FALSE;                      return JS_FALSE;
6473              } else {              } else {
6474                  if (!js_EmitTree(cx, cg, pn2))                  if (!js_EmitTree(cx, cg, pn2))
6475                      return JS_FALSE;                      return JS_FALSE;
6476              }              }
   
6477              if (op == JSOP_NEWINIT && js_Emit1(cx, cg, JSOP_INITELEM) < 0)              if (op == JSOP_NEWINIT && js_Emit1(cx, cg, JSOP_INITELEM) < 0)
6478                  return JS_FALSE;                  return JS_FALSE;
6479          }          }
6480            JS_ASSERT(atomIndex == pn->pn_count);
6481    
6482          if (pn->pn_extra & PNX_ENDCOMMA) {          if (pn->pn_xflags & PNX_ENDCOMMA) {
6483              /* Emit a source note so we know to decompile an extra comma. */              /* Emit a source note so we know to decompile an extra comma. */
6484              if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0)              if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0)
6485                  return JS_FALSE;                  return JS_FALSE;
6486          }          }
6487    
6488          if (op == JSOP_NEWARRAY) {          if (op == JSOP_NEWINIT) {
6489              JS_ASSERT(atomIndex == pn->pn_count);              /*
6490              off = js_EmitN(cx, cg, op, 3);               * Emit an op to finish the array and, secondarily, to aid in sharp
6491              if (off < 0)               * array cleanup (if JS_HAS_SHARP_VARS) and decompilation.
6492                  return JS_FALSE;               */
             pc = CG_CODE(cg, off);  
             SET_UINT24(pc, atomIndex);  
             UpdateDepth(cx, cg, off);  
         } else {  
             /* Emit an op for sharp array cleanup and decompilation. */  
6493              if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)              if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)
6494                  return JS_FALSE;                  return JS_FALSE;
6495                break;
6496          }          }
6497    
6498            JS_ASSERT(atomIndex < JS_BIT(16));
6499            EMIT_UINT16_IMM_OP(JSOP_NEWARRAY, atomIndex);
6500          break;          break;
6501    
6502        case TOK_RC:        case TOK_RC:
6503    #if JS_HAS_SHARP_VARS
6504            sharpnum = -1;
6505          do_emit_object:
6506    #endif
6507  #if JS_HAS_DESTRUCTURING_SHORTHAND  #if JS_HAS_DESTRUCTURING_SHORTHAND
6508          if (pn->pn_extra & PNX_SHORTHAND) {          if (pn->pn_xflags & PNX_DESTRUCT) {
6509              js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR,              js_ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR,
6510                                          JSMSG_BAD_OBJECT_INIT);                                          JSMSG_BAD_OBJECT_INIT);
6511              return JS_FALSE;              return JS_FALSE;
6512          }          }
6513  #endif  #endif
6514          /*          /*
6515           * Emit code for {p:a, '%q':b, 2:c} of the form:           * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
6516           *           * a new object and in source order evaluating each property value and
6517           *   t = new Object; t.p = a; t['%q'] = b; t[2] = c; t;           * adding the property to the object, without invoking latent setters.
6518           *           * We use the JSOP_NEWINIT and JSOP_INITELEM/JSOP_INITPROP bytecodes to
6519           * but use a stack slot for t and avoid dup'ing and popping it via           * ignore setters and to avoid dup'ing and popping the object as each
6520           * the JSOP_NEWINIT and JSOP_INITELEM/JSOP_INITPROP bytecodes.           * property is added, as JSOP_SETELEM/JSOP_SETPROP would do.
6521           */           */
6522          if (js_Emit2(cx, cg, JSOP_NEWINIT, (jsbytecode) JSProto_Object) < 0)          if (js_Emit2(cx, cg, JSOP_NEWINIT, (jsbytecode) JSProto_Object) < 0)
6523              return JS_FALSE;              return JS_FALSE;
6524    
         pn2 = pn->pn_head;  
6525  #if JS_HAS_SHARP_VARS  #if JS_HAS_SHARP_VARS
6526          if (pn2 && pn2->pn_type == TOK_DEFSHARP) {          if (sharpnum >= 0)
6527              EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid)pn2->pn_num);              EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) sharpnum);
             pn2 = pn2->pn_next;  
         }  
6528  #endif  #endif
6529    
6530          for (; pn2; pn2 = pn2->pn_next) {          for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
6531              /* Emit an index for t[2], else map an atom for t.p or t['%q']. */              /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
6532              pn3 = pn2->pn_left;              pn3 = pn2->pn_left;
6533              if (pn3->pn_type == TOK_NUMBER) {              if (pn3->pn_type == TOK_NUMBER) {
 #ifdef __GNUC__  
                 ale = NULL;     /* quell GCC overwarning */  
 #endif  
6534                  if (!EmitNumberOp(cx, pn3->pn_dval, cg))                  if (!EmitNumberOp(cx, pn3->pn_dval, cg))
6535                      return JS_FALSE;                      return JS_FALSE;
             } else {  
                 JS_ASSERT(pn3->pn_type == TOK_NAME ||  
                           pn3->pn_type == TOK_STRING);  
                 ale = js_IndexAtom(cx, pn3->pn_atom, &cg->atomList);  
                 if (!ale)  
                     return JS_FALSE;  
6536              }              }
6537    
6538              /* Emit code for the property initializer. */              /* Emit code for the property initializer. */
# Line 6122  Line 6553 
6553                  if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)                  if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
6554                      return JS_FALSE;                      return JS_FALSE;
6555              } else {              } else {
6556                    JS_ASSERT(pn3->pn_type == TOK_NAME ||
6557                              pn3->pn_type == TOK_STRING);
6558                    ale = cg->atomList.add(cg->compiler, pn3->pn_atom);
6559                    if (!ale)
6560                        return JS_FALSE;
6561                  EMIT_INDEX_OP(JSOP_INITPROP, ALE_INDEX(ale));                  EMIT_INDEX_OP(JSOP_INITPROP, ALE_INDEX(ale));
6562              }              }
6563          }          }
# Line 6133  Line 6569 
6569    
6570  #if JS_HAS_SHARP_VARS  #if JS_HAS_SHARP_VARS
6571        case TOK_DEFSHARP:        case TOK_DEFSHARP:
6572          if (!js_EmitTree(cx, cg, pn->pn_kid))          JS_ASSERT(cg->flags & TCF_HAS_SHARPS);
6573            sharpnum = pn->pn_num;
6574            pn = pn->pn_kid;
6575            if (pn->pn_type == TOK_RB)
6576                goto do_emit_array;
6577    # if JS_HAS_GENERATORS
6578            if (pn->pn_type == TOK_ARRAYCOMP)
6579                goto do_emit_array;
6580    # endif
6581            if (pn->pn_type == TOK_RC)
6582                goto do_emit_object;
6583    
6584            if (!js_EmitTree(cx, cg, pn))
6585              return JS_FALSE;              return JS_FALSE;
6586          EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) pn->pn_num);          EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) sharpnum);
6587          break;          break;
6588    
6589        case TOK_USESHARP:        case TOK_USESHARP:
6590            JS_ASSERT(cg->flags & TCF_HAS_SHARPS);
6591          EMIT_UINT16_IMM_OP(JSOP_USESHARP, (jsatomid) pn->pn_num);          EMIT_UINT16_IMM_OP(JSOP_USESHARP, (jsatomid) pn->pn_num);
6592          break;          break;
6593  #endif /* JS_HAS_SHARP_VARS */  #endif /* JS_HAS_SHARP_VARS */
6594    
6595        case TOK_RP:        case TOK_NAME:
       {  
         uintN oldflags;  
   
6596          /*          /*
6597           * The node for (e) has e as its kid, enabling users who want to nest           * Cope with a left-over function definition that was replaced by a use
6598           * assignment expressions in conditions to avoid the error correction           * of a later function definition of the same name. See FunctionDef and
6599           * done by Condition (from x = y to x == y) by double-parenthesizing.           * MakeDefIntoUse in jsparse.cpp.
6600           */           */
6601          oldflags = cg->treeContext.flags;          if (pn->pn_op == JSOP_NOP)
6602          cg->treeContext.flags &= ~TCF_IN_FOR_INIT;              return JS_TRUE;
         if (!js_EmitTree(cx, cg, pn->pn_kid))  
             return JS_FALSE;  
         cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;  
         break;  
       }  
   
       case TOK_NAME:  
6603          if (!EmitNameOp(cx, cg, pn, JS_FALSE))          if (!EmitNameOp(cx, cg, pn, JS_FALSE))
6604              return JS_FALSE;              return JS_FALSE;
6605          break;          break;
# Line 6189  Line 6628 
6628           * select JSOP_REGEXP.           * select JSOP_REGEXP.
6629           */           */
6630          JS_ASSERT(pn->pn_op == JSOP_REGEXP);          JS_ASSERT(pn->pn_op == JSOP_REGEXP);
6631          if (cg->treeContext.flags & TCF_COMPILE_N_GO) {          if (cg->flags & TCF_COMPILE_N_GO) {
6632              ok = EmitObjectOp(cx, pn->pn_pob, JSOP_OBJECT, cg);              ok = EmitObjectOp(cx, pn->pn_objbox, JSOP_OBJECT, cg);
6633          } else {          } else {
6634              ok = EmitIndexOp(cx, JSOP_REGEXP,              ok = EmitIndexOp(cx, JSOP_REGEXP,
6635                               IndexParsedObject(pn->pn_pob, &cg->regexpList),                               cg->regexpList.index(pn->pn_objbox),
6636                               cg);                               cg);
6637          }          }
6638          break;          break;
# Line 6217  Line 6656 
6656        case TOK_XMLELEM:        case TOK_XMLELEM:
6657        case TOK_XMLLIST:        case TOK_XMLLIST:
6658          if (pn->pn_op == JSOP_XMLOBJECT) {          if (pn->pn_op == JSOP_XMLOBJECT) {
6659              ok = EmitObjectOp(cx, pn->pn_pob, PN_OP(pn), cg);              ok = EmitObjectOp(cx, pn->pn_objbox, PN_OP(pn), cg);
6660              break;              break;
6661          }          }
6662    
6663          JS_ASSERT(pn->pn_type == TOK_XMLLIST || pn->pn_count != 0);          JS_ASSERT(PN_TYPE(pn) == TOK_XMLLIST || pn->pn_count != 0);
6664          switch (pn->pn_head ? pn->pn_head->pn_type : TOK_XMLLIST) {          switch (pn->pn_head ? PN_TYPE(pn->pn_head) : TOK_XMLLIST) {
6665            case TOK_XMLETAGO:            case TOK_XMLETAGO:
6666              JS_ASSERT(0);              JS_ASSERT(0);
6667              /* FALL THROUGH */              /* FALL THROUGH */
# Line 6245  Line 6684 
6684                  return JS_FALSE;                  return JS_FALSE;
6685          }          }
6686    
6687          if (pn->pn_extra & PNX_XMLROOT) {          if (pn->pn_xflags & PNX_XMLROOT) {
6688              if (pn->pn_count == 0) {              if (pn->pn_count == 0) {
6689                  JS_ASSERT(pn->pn_type == TOK_XMLLIST);                  JS_ASSERT(pn->pn_type == TOK_XMLLIST);
6690                  atom = cx->runtime->atomState.emptyAtom;                  atom = cx->runtime->atomState.emptyAtom;
6691                  ale = js_IndexAtom(cx, atom, &cg->atomList);                  ale = cg->atomList.add(cg->compiler, atom);
6692                  if (!ale)                  if (!ale)
6693                      return JS_FALSE;                      return JS_FALSE;
6694                  EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));                  EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
# Line 6265  Line 6704 
6704    
6705        case TOK_XMLPTAGC:        case TOK_XMLPTAGC:
6706          if (pn->pn_op == JSOP_XMLOBJECT) {          if (pn->pn_op == JSOP_XMLOBJECT) {
6707              ok = EmitObjectOp(cx, pn->pn_pob, PN_OP(pn), cg);              ok = EmitObjectOp(cx, pn->pn_objbox, PN_OP(pn), cg);
6708              break;              break;
6709          }          }
6710          /* FALL THROUGH */          /* FALL THROUGH */
# Line 6278  Line 6717 
6717          if (js_Emit1(cx, cg, JSOP_STARTXML) < 0)          if (js_Emit1(cx, cg, JSOP_STARTXML) < 0)
6718              return JS_FALSE;              return JS_FALSE;
6719    
6720          ale = js_IndexAtom(cx,          ale = cg->atomList.add(cg->compiler,
6721                             (pn->pn_type == TOK_XMLETAGO)                                 (pn->pn_type == TOK_XMLETAGO)
6722                             ? cx->runtime->atomState.etagoAtom                                 ? cx->runtime->atomState.etagoAtom
6723                             : cx->runtime->atomState.stagoAtom,                                 : cx->runtime->atomState.stagoAtom);
                            &cg->atomList);  
6724          if (!ale)          if (!ale)
6725              return JS_FALSE;              return JS_FALSE;
6726          EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));          EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
# Line 6313  Line 6751 
6751              }              }
6752          }          }
6753    
6754          ale = js_IndexAtom(cx,          ale = cg->atomList.add(cg->compiler,
6755                             (pn->pn_type == TOK_XMLPTAGC)                                 (pn->pn_type == TOK_XMLPTAGC)
6756                             ? cx->runtime->atomState.ptagcAtom                                 ? cx->runtime->atomState.ptagcAtom
6757                             : cx->runtime->atomState.tagcAtom,                                 : cx->runtime->atomState.tagcAtom);
                            &cg->atomList);  
6758          if (!ale)          if (!ale)
6759              return JS_FALSE;              return JS_FALSE;
6760          EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));          EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
6761          if (js_Emit1(cx, cg, JSOP_ADD) < 0)          if (js_Emit1(cx, cg, JSOP_ADD) < 0)
6762              return JS_FALSE;              return JS_FALSE;
6763    
6764          if ((pn->pn_extra & PNX_XMLROOT) && js_Emit1(cx, cg, PN_OP(pn)) < 0)          if ((pn->pn_xflags & PNX_XMLROOT) && js_Emit1(cx, cg, PN_OP(pn)) < 0)
6765              return JS_FALSE;              return JS_FALSE;
6766          break;          break;
6767        }        }
# Line 6333  Line 6770 
6770          if (pn->pn_arity == PN_LIST) {          if (pn->pn_arity == PN_LIST) {
6771              JS_ASSERT(pn->pn_count != 0);              JS_ASSERT(pn->pn_count != 0);
6772              for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {              for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
6773                    if (pn2->pn_type == TOK_LC &&
6774                        js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) {
6775                        return JS_FALSE;
6776                    }
6777                  if (!js_EmitTree(cx, cg, pn2))                  if (!js_EmitTree(cx, cg, pn2))
6778                      return JS_FALSE;                      return JS_FALSE;
6779                  if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)                  if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)
# Line 6341  Line 6782 
6782          } else {          } else {
6783              JS_ASSERT(pn->pn_arity == PN_NULLARY);         &nbs