LCOV - code coverage report
Current view: directory - js/src/frontend - Parser.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 3554 2823 79.4 %
Date: 2012-06-02 Functions: 140 138 98.6 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=99:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla Communicator client code, released
      18                 :  * March 31, 1998.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  * Netscape Communications Corporation.
      22                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : /*
      42                 :  * JS parser.
      43                 :  *
      44                 :  * This is a recursive-descent parser for the JavaScript language specified by
      45                 :  * "The JavaScript 1.5 Language Specification".  It uses lexical and semantic
      46                 :  * feedback to disambiguate non-LL(1) structures.  It generates trees of nodes
      47                 :  * induced by the recursive parsing (not precise syntax trees, see Parser.h).
      48                 :  * After tree construction, it rewrites trees to fold constants and evaluate
      49                 :  * compile-time expressions.  Finally, it calls js::frontend::EmitTree (see
      50                 :  * BytecodeEmitter.h) to generate bytecode.
      51                 :  *
      52                 :  * This parser attempts no error recovery.
      53                 :  */
      54                 : 
      55                 : #include "frontend/Parser.h"
      56                 : 
      57                 : #include <stdlib.h>
      58                 : #include <string.h>
      59                 : #include "jstypes.h"
      60                 : #include "jsutil.h"
      61                 : #include "jsapi.h"
      62                 : #include "jsarray.h"
      63                 : #include "jsatom.h"
      64                 : #include "jscntxt.h"
      65                 : #include "jsversion.h"
      66                 : #include "jsfun.h"
      67                 : #include "jsgc.h"
      68                 : #include "jsgcmark.h"
      69                 : #include "jsinterp.h"
      70                 : #include "jsiter.h"
      71                 : #include "jslock.h"
      72                 : #include "jsnum.h"
      73                 : #include "jsobj.h"
      74                 : #include "jsopcode.h"
      75                 : #include "jsscope.h"
      76                 : #include "jsscript.h"
      77                 : #include "jsstr.h"
      78                 : 
      79                 : #include "frontend/BytecodeCompiler.h"
      80                 : #include "frontend/BytecodeEmitter.h"
      81                 : #include "frontend/FoldConstants.h"
      82                 : #include "frontend/ParseMaps.h"
      83                 : #include "frontend/TokenStream.h"
      84                 : 
      85                 : #if JS_HAS_XML_SUPPORT
      86                 : #include "jsxml.h"
      87                 : #endif
      88                 : 
      89                 : #if JS_HAS_DESTRUCTURING
      90                 : #include "jsdhash.h"
      91                 : #endif
      92                 : 
      93                 : #include "jsatominlines.h"
      94                 : #include "jsscriptinlines.h"
      95                 : 
      96                 : #include "frontend/BytecodeEmitter-inl.h"
      97                 : #include "frontend/ParseMaps-inl.h"
      98                 : #include "frontend/ParseNode-inl.h"
      99                 : #include "vm/RegExpObject-inl.h"
     100                 : 
     101                 : using namespace js;
     102                 : using namespace js::gc;
     103                 : using namespace js::frontend;
     104                 : 
     105                 : /*
     106                 :  * Insist that the next token be of type tt, or report errno and return null.
     107                 :  * NB: this macro uses cx and ts from its lexical environment.
     108                 :  */
     109                 : #define MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, __flags)                                     \
     110                 :     JS_BEGIN_MACRO                                                                          \
     111                 :         if (tokenStream.getToken((__flags)) != tt) {                                        \
     112                 :             reportErrorNumber(NULL, JSREPORT_ERROR, errno);                                 \
     113                 :             return NULL;                                                                    \
     114                 :         }                                                                                   \
     115                 :     JS_END_MACRO
     116                 : #define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, 0)
     117                 : 
     118          134271 : Parser::Parser(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin,
     119                 :                StackFrame *cfp, bool foldConstants)
     120                 :   : AutoGCRooter(cx, PARSER),
     121                 :     context(cx),
     122                 :     tokenStream(cx, prin, originPrin),
     123                 :     principals(NULL),
     124                 :     originPrincipals(NULL),
     125                 :     callerFrame(cfp),
     126                 :     callerVarObj(cfp ? &cfp->varObj() : NULL),
     127                 :     allocator(cx),
     128                 :     functionCount(0),
     129                 :     traceListHead(NULL),
     130                 :     tc(NULL),
     131                 :     keepAtoms(cx->runtime),
     132          134271 :     foldConstants(foldConstants)
     133                 : {
     134          134271 :     cx->activeCompilations++;
     135          134271 :     PodArrayZero(tempFreeList);
     136          134271 :     setPrincipals(prin, originPrin);
     137          134271 :     JS_ASSERT_IF(cfp, cfp->isScriptFrame());
     138          134271 : }
     139                 : 
     140                 : bool
     141          134271 : Parser::init(const jschar *base, size_t length, const char *filename, unsigned lineno,
     142                 :              JSVersion version)
     143                 : {
     144          134271 :     JSContext *cx = context;
     145          134271 :     if (!cx->ensureParseMapPool())
     146               0 :         return false;
     147          134271 :     tempPoolMark = cx->tempLifoAlloc().mark();
     148          134271 :     if (!tokenStream.init(base, length, filename, lineno, version)) {
     149               0 :         cx->tempLifoAlloc().release(tempPoolMark);
     150               0 :         return false;
     151                 :     }
     152          134271 :     return true;
     153                 : }
     154                 : 
     155          268542 : Parser::~Parser()
     156                 : {
     157          134271 :     JSContext *cx = context;
     158          134271 :     if (principals)
     159           27337 :         JS_DropPrincipals(cx->runtime, principals);
     160          134271 :     if (originPrincipals)
     161             424 :         JS_DropPrincipals(cx->runtime, originPrincipals);
     162          134271 :     cx->tempLifoAlloc().release(tempPoolMark);
     163          134271 :     cx->activeCompilations--;
     164          134271 : }
     165                 : 
     166                 : void
     167          134271 : Parser::setPrincipals(JSPrincipals *prin, JSPrincipals *originPrin)
     168                 : {
     169          134271 :     JS_ASSERT(!principals && !originPrincipals);
     170          134271 :     principals = prin;
     171          134271 :     if (principals)
     172           27337 :         JS_HoldPrincipals(principals);
     173          134271 :     originPrincipals = originPrin;
     174          134271 :     if (originPrincipals)
     175             424 :         JS_HoldPrincipals(originPrincipals);
     176          134271 : }
     177                 : 
     178                 : ObjectBox *
     179          520767 : Parser::newObjectBox(JSObject *obj)
     180                 : {
     181                 :     /*
     182                 :      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
     183                 :      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
     184                 :      * arenas containing the entries must be alive until we are done with
     185                 :      * scanning, parsing and code generation for the whole script or top-level
     186                 :      * function.
     187                 :      */
     188          520767 :     ObjectBox *objbox = context->tempLifoAlloc().new_<ObjectBox>();
     189          520767 :     if (!objbox) {
     190               0 :         js_ReportOutOfMemory(context);
     191               0 :         return NULL;
     192                 :     }
     193          520767 :     objbox->traceLink = traceListHead;
     194          520767 :     traceListHead = objbox;
     195          520767 :     objbox->emitLink = NULL;
     196          520767 :     objbox->object = obj;
     197          520767 :     objbox->isFunctionBox = false;
     198          520767 :     return objbox;
     199                 : }
     200                 : 
     201                 : FunctionBox *
     202          980883 : Parser::newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc)
     203                 : {
     204          980883 :     JS_ASSERT(obj);
     205          980883 :     JS_ASSERT(obj->isFunction());
     206                 : 
     207                 :     /*
     208                 :      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
     209                 :      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
     210                 :      * arenas containing the entries must be alive until we are done with
     211                 :      * scanning, parsing and code generation for the whole script or top-level
     212                 :      * function.
     213                 :      */
     214          980883 :     FunctionBox *funbox = context->tempLifoAlloc().newPod<FunctionBox>();
     215          980883 :     if (!funbox) {
     216               0 :         js_ReportOutOfMemory(context);
     217               0 :         return NULL;
     218                 :     }
     219          980883 :     funbox->traceLink = traceListHead;
     220          980883 :     traceListHead = funbox;
     221          980883 :     funbox->emitLink = NULL;
     222          980883 :     funbox->object = obj;
     223          980883 :     funbox->isFunctionBox = true;
     224          980883 :     funbox->node = fn;
     225          980883 :     funbox->siblings = tc->functionList;
     226          980883 :     tc->functionList = funbox;
     227          980883 :     ++tc->parser->functionCount;
     228          980883 :     funbox->kids = NULL;
     229          980883 :     funbox->parent = tc->funbox;
     230          980883 :     funbox->methods = NULL;
     231          980883 :     new (&funbox->bindings) Bindings(context);
     232          980883 :     funbox->queued = false;
     233          980883 :     funbox->inLoop = false;
     234         1431458 :     for (StmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) {
     235          457448 :         if (STMT_IS_LOOP(stmt)) {
     236            6873 :             funbox->inLoop = true;
     237            6873 :             break;
     238                 :         }
     239                 :     }
     240          980883 :     funbox->level = tc->staticLevel;
     241          980883 :     funbox->tcflags = (TCF_IN_FUNCTION | (tc->flags & (TCF_COMPILE_N_GO | TCF_STRICT_MODE_CODE)));
     242          980883 :     if (tc->innermostWith)
     243             171 :         funbox->tcflags |= TCF_IN_WITH;
     244          980883 :     if (!tc->inFunction()) {
     245          714214 :         JSObject *scope = tc->scopeChain();
     246         2153276 :         while (scope) {
     247          724848 :             if (scope->isWith())
     248               0 :                 funbox->tcflags |= TCF_IN_WITH;
     249          724848 :             scope = scope->enclosingScope();
     250                 :         }
     251                 :     }
     252          980883 :     return funbox;
     253                 : }
     254                 : 
     255                 : void
     256               9 : Parser::trace(JSTracer *trc)
     257                 : {
     258               9 :     ObjectBox *objbox = traceListHead;
     259              18 :     while (objbox) {
     260               0 :         MarkObjectRoot(trc, &objbox->object, "parser.object");
     261               0 :         if (objbox->isFunctionBox)
     262               0 :             static_cast<FunctionBox *>(objbox)->bindings.trace(trc);
     263               0 :         objbox = objbox->traceLink;
     264                 :     }
     265                 : 
     266               9 :     for (TreeContext *tc = this->tc; tc; tc = tc->parent)
     267               0 :         tc->trace(trc);
     268               9 : }
     269                 : 
     270                 : static bool
     271           17276 : GenerateBlockIdForStmtNode(ParseNode *pn, TreeContext *tc)
     272                 : {
     273           17276 :     JS_ASSERT(tc->topStmt);
     274           17276 :     JS_ASSERT(STMT_MAYBE_SCOPE(tc->topStmt));
     275           17276 :     JS_ASSERT(pn->isKind(PNK_STATEMENTLIST) || pn->isKind(PNK_LEXICALSCOPE));
     276           17276 :     if (!GenerateBlockId(tc, tc->topStmt->blockid))
     277               0 :         return false;
     278           17276 :     pn->pn_blockid = tc->topStmt->blockid;
     279           17276 :     return true;
     280                 : }
     281                 : 
     282                 : /*
     283                 :  * Parse a top-level JS script.
     284                 :  */
     285                 : ParseNode *
     286            2278 : Parser::parse(JSObject *chain)
     287                 : {
     288                 :     /*
     289                 :      * Protect atoms from being collected by a GC activation, which might
     290                 :      * - nest on this thread due to out of memory (the so-called "last ditch"
     291                 :      *   GC attempted within js_NewGCThing), or
     292                 :      * - run for any reason on another thread if this thread is suspended on
     293                 :      *   an object lock before it finishes generating bytecode into a script
     294                 :      *   protected from the GC by a root or a stack frame reference.
     295                 :      */
     296            4556 :     TreeContext globaltc(this);
     297            2278 :     if (!globaltc.init(context))
     298               0 :         return NULL;
     299            2278 :     globaltc.setScopeChain(chain);
     300            2278 :     if (!GenerateBlockId(&globaltc, globaltc.bodyid))
     301               0 :         return NULL;
     302                 : 
     303            2278 :     ParseNode *pn = statements();
     304            2278 :     if (pn) {
     305            2278 :         if (!tokenStream.matchToken(TOK_EOF)) {
     306               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
     307               0 :             pn = NULL;
     308            2278 :         } else if (foldConstants) {
     309               0 :             if (!FoldConstants(context, pn, &globaltc))
     310               0 :                 pn = NULL;
     311                 :         }
     312                 :     }
     313            2278 :     return pn;
     314                 : }
     315                 : 
     316                 : JS_STATIC_ASSERT(UpvarCookie::FREE_LEVEL == JS_BITMASK(JSFB_LEVEL_BITS));
     317                 : 
     318                 : /*
     319                 :  * Insist on a final return before control flows out of pn.  Try to be a bit
     320                 :  * smart about loops: do {...; return e2;} while(0) at the end of a function
     321                 :  * that contains an early return e1 will get a strict warning.  Similarly for
     322                 :  * iloops: while (true){...} is treated as though ... returns.
     323                 :  */
     324                 : #define ENDS_IN_OTHER   0
     325                 : #define ENDS_IN_RETURN  1
     326                 : #define ENDS_IN_BREAK   2
     327                 : 
     328                 : static int
     329          179041 : HasFinalReturn(ParseNode *pn)
     330                 : {
     331                 :     ParseNode *pn2, *pn3;
     332                 :     unsigned rv, rv2, hasDefault;
     333                 : 
     334          179041 :     switch (pn->getKind()) {
     335                 :       case PNK_STATEMENTLIST:
     336           87190 :         if (!pn->pn_head)
     337               0 :             return ENDS_IN_OTHER;
     338           87190 :         return HasFinalReturn(pn->last());
     339                 : 
     340                 :       case PNK_IF:
     341             838 :         if (!pn->pn_kid3)
     342               9 :             return ENDS_IN_OTHER;
     343             829 :         return HasFinalReturn(pn->pn_kid2) & HasFinalReturn(pn->pn_kid3);
     344                 : 
     345                 :       case PNK_WHILE:
     346             361 :         pn2 = pn->pn_left;
     347             361 :         if (pn2->isKind(PNK_TRUE))
     348             361 :             return ENDS_IN_RETURN;
     349               0 :         if (pn2->isKind(PNK_NUMBER) && pn2->pn_dval)
     350               0 :             return ENDS_IN_RETURN;
     351               0 :         return ENDS_IN_OTHER;
     352                 : 
     353                 :       case PNK_DOWHILE:
     354               0 :         pn2 = pn->pn_right;
     355               0 :         if (pn2->isKind(PNK_FALSE))
     356               0 :             return HasFinalReturn(pn->pn_left);
     357               0 :         if (pn2->isKind(PNK_TRUE))
     358               0 :             return ENDS_IN_RETURN;
     359               0 :         if (pn2->isKind(PNK_NUMBER)) {
     360               0 :             if (pn2->pn_dval == 0)
     361               0 :                 return HasFinalReturn(pn->pn_left);
     362               0 :             return ENDS_IN_RETURN;
     363                 :         }
     364               0 :         return ENDS_IN_OTHER;
     365                 : 
     366                 :       case PNK_FOR:
     367             362 :         pn2 = pn->pn_left;
     368             362 :         if (pn2->isArity(PN_TERNARY) && !pn2->pn_kid2)
     369               0 :             return ENDS_IN_RETURN;
     370             362 :         return ENDS_IN_OTHER;
     371                 : 
     372                 :       case PNK_SWITCH:
     373             228 :         rv = ENDS_IN_RETURN;
     374             228 :         hasDefault = ENDS_IN_OTHER;
     375             228 :         pn2 = pn->pn_right;
     376             228 :         if (pn2->isKind(PNK_LEXICALSCOPE))
     377             113 :             pn2 = pn2->expr();
     378            1027 :         for (pn2 = pn2->pn_head; rv && pn2; pn2 = pn2->pn_next) {
     379             799 :             if (pn2->isKind(PNK_DEFAULT))
     380             228 :                 hasDefault = ENDS_IN_RETURN;
     381             799 :             pn3 = pn2->pn_right;
     382             799 :             JS_ASSERT(pn3->isKind(PNK_STATEMENTLIST));
     383             799 :             if (pn3->pn_head) {
     384             686 :                 rv2 = HasFinalReturn(pn3->last());
     385             686 :                 if (rv2 == ENDS_IN_OTHER && pn2->pn_next)
     386                 :                     /* Falling through to next case or default. */;
     387                 :                 else
     388             686 :                     rv &= rv2;
     389                 :             }
     390                 :         }
     391                 :         /* If a final switch has no default case, we judge it harshly. */
     392             228 :         rv &= hasDefault;
     393             228 :         return rv;
     394                 : 
     395                 :       case PNK_BREAK:
     396               0 :         return ENDS_IN_BREAK;
     397                 : 
     398                 :       case PNK_WITH:
     399               0 :         return HasFinalReturn(pn->pn_right);
     400                 : 
     401                 :       case PNK_RETURN:
     402           71277 :         return ENDS_IN_RETURN;
     403                 : 
     404                 :       case PNK_COLON:
     405                 :       case PNK_LEXICALSCOPE:
     406            2267 :         return HasFinalReturn(pn->expr());
     407                 : 
     408                 :       case PNK_THROW:
     409           11707 :         return ENDS_IN_RETURN;
     410                 : 
     411                 :       case PNK_TRY:
     412                 :         /* If we have a finally block that returns, we are done. */
     413            2253 :         if (pn->pn_kid3) {
     414             627 :             rv = HasFinalReturn(pn->pn_kid3);
     415             627 :             if (rv == ENDS_IN_RETURN)
     416               0 :                 return rv;
     417                 :         }
     418                 : 
     419                 :         /* Else check the try block and any and all catch statements. */
     420            2253 :         rv = HasFinalReturn(pn->pn_kid1);
     421            2253 :         if (pn->pn_kid2) {
     422            1626 :             JS_ASSERT(pn->pn_kid2->isArity(PN_LIST));
     423            3253 :             for (pn2 = pn->pn_kid2->pn_head; pn2; pn2 = pn2->pn_next)
     424            1627 :                 rv &= HasFinalReturn(pn2);
     425                 :         }
     426            2253 :         return rv;
     427                 : 
     428                 :       case PNK_CATCH:
     429                 :         /* Check this catch block's body. */
     430            1627 :         return HasFinalReturn(pn->pn_kid3);
     431                 : 
     432                 :       case PNK_LET:
     433                 :         /* Non-binary let statements are let declarations. */
     434             249 :         if (!pn->isArity(PN_BINARY))
     435               0 :             return ENDS_IN_OTHER;
     436             249 :         return HasFinalReturn(pn->pn_right);
     437                 : 
     438                 :       default:
     439             682 :         return ENDS_IN_OTHER;
     440                 :     }
     441                 : }
     442                 : 
     443                 : static JSBool
     444            1578 : ReportBadReturn(JSContext *cx, TreeContext *tc, ParseNode *pn, unsigned flags, unsigned errnum,
     445                 :                 unsigned anonerrnum)
     446                 : {
     447            3156 :     JSAutoByteString name;
     448            1578 :     if (tc->fun()->atom) {
     449            1167 :         if (!js_AtomToPrintableString(cx, tc->fun()->atom, &name))
     450               0 :             return false;
     451                 :     } else {
     452             411 :         errnum = anonerrnum;
     453                 :     }
     454            1578 :     return ReportCompileErrorNumber(cx, TS(tc->parser), pn, flags, errnum, name.ptr());
     455                 : }
     456                 : 
     457                 : static JSBool
     458           80857 : CheckFinalReturn(JSContext *cx, TreeContext *tc, ParseNode *pn)
     459                 : {
     460           80857 :     JS_ASSERT(tc->inFunction());
     461           80857 :     return HasFinalReturn(pn) == ENDS_IN_RETURN ||
     462                 :            ReportBadReturn(cx, tc, pn, JSREPORT_WARNING | JSREPORT_STRICT,
     463           80857 :                            JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE);
     464                 : }
     465                 : 
     466                 : /*
     467                 :  * Check that it is permitted to assign to lhs.  Strict mode code may not
     468                 :  * assign to 'eval' or 'arguments'.
     469                 :  */
     470                 : static bool
     471         2397526 : CheckStrictAssignment(JSContext *cx, TreeContext *tc, ParseNode *lhs)
     472                 : {
     473         2397526 :     if (tc->needStrictChecks() && lhs->isKind(PNK_NAME)) {
     474          276517 :         JSAtom *atom = lhs->pn_atom;
     475          276517 :         JSAtomState *atomState = &cx->runtime->atomState;
     476          276517 :         if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) {
     477               0 :             JSAutoByteString name;
     478               0 :             if (!js_AtomToPrintableString(cx, atom, &name) ||
     479                 :                 !ReportStrictModeError(cx, TS(tc->parser), tc, lhs, JSMSG_DEPRECATED_ASSIGN,
     480               0 :                                        name.ptr())) {
     481               0 :                 return false;
     482                 :             }
     483                 :         }
     484                 :     }
     485         2397526 :     return true;
     486                 : }
     487                 : 
     488                 : /*
     489                 :  * Check that it is permitted to introduce a binding for atom.  Strict mode
     490                 :  * forbids introducing new definitions for 'eval', 'arguments', or for any
     491                 :  * strict mode reserved keyword.  Use pn for reporting error locations, or use
     492                 :  * tc's token stream if pn is NULL.
     493                 :  */
     494                 : bool
     495         2365488 : CheckStrictBinding(JSContext *cx, TreeContext *tc, PropertyName *name, ParseNode *pn)
     496                 : {
     497         2365488 :     if (!tc->needStrictChecks())
     498         1191050 :         return true;
     499                 : 
     500         1174438 :     JSAtomState *atomState = &cx->runtime->atomState;
     501         2348876 :     if (name == atomState->evalAtom ||
     502                 :         name == atomState->argumentsAtom ||
     503         1174438 :         FindKeyword(name->charsZ(), name->length()))
     504                 :     {
     505               0 :         JSAutoByteString bytes;
     506               0 :         if (!js_AtomToPrintableString(cx, name, &bytes))
     507               0 :             return false;
     508               0 :         return ReportStrictModeError(cx, TS(tc->parser), tc, pn, JSMSG_BAD_BINDING, bytes.ptr());
     509                 :     }
     510                 : 
     511         1174438 :     return true;
     512                 : }
     513                 : 
     514                 : static bool
     515              14 : ReportBadParameter(JSContext *cx, TreeContext *tc, JSAtom *name, unsigned errorNumber)
     516                 : {
     517              14 :     Definition *dn = tc->decls.lookupFirst(name);
     518              28 :     JSAutoByteString bytes;
     519              14 :     return js_AtomToPrintableString(cx, name, &bytes) &&
     520              14 :            ReportStrictModeError(cx, TS(tc->parser), tc, dn, errorNumber, bytes.ptr());
     521                 : }
     522                 : 
     523                 : /*
     524                 :  * In strict mode code, all parameter names must be distinct, must not be
     525                 :  * strict mode reserved keywords, and must not be 'eval' or 'arguments'.  We
     526                 :  * must perform these checks here, and not eagerly during parsing, because a
     527                 :  * function's body may turn on strict mode for the function head.
     528                 :  */
     529                 : bool
     530          990766 : js::CheckStrictParameters(JSContext *cx, TreeContext *tc)
     531                 : {
     532          990766 :     JS_ASSERT(tc->inFunction());
     533                 : 
     534          990766 :     if (!tc->needStrictChecks() || tc->bindings.countArgs() == 0)
     535          570740 :         return true;
     536                 : 
     537          420026 :     JSAtom *argumentsAtom = cx->runtime->atomState.argumentsAtom;
     538          420026 :     JSAtom *evalAtom = cx->runtime->atomState.evalAtom;
     539                 : 
     540                 :     /* name => whether we've warned about the name already */
     541          840052 :     HashMap<JSAtom *, bool> parameters(cx);
     542          420026 :     if (!parameters.init(tc->bindings.countArgs()))
     543               0 :         return false;
     544                 : 
     545                 :     /* Start with lastVariable(), not lastArgument(), for destructuring. */
     546         1487691 :     for (Shape::Range r = tc->bindings.lastVariable(); !r.empty(); r.popFront()) {
     547         1067665 :         jsid id = r.front().propid();
     548         1067665 :         if (!JSID_IS_ATOM(id))
     549             351 :             continue;
     550                 : 
     551         1067314 :         JSAtom *name = JSID_TO_ATOM(id);
     552                 : 
     553         1067314 :         if (name == argumentsAtom || name == evalAtom) {
     554              14 :             if (!ReportBadParameter(cx, tc, name, JSMSG_BAD_BINDING))
     555               0 :                 return false;
     556                 :         }
     557                 : 
     558         1067314 :         if (tc->inStrictMode() && FindKeyword(name->charsZ(), name->length())) {
     559                 :             /*
     560                 :              * JSOPTION_STRICT is supposed to warn about future keywords, too,
     561                 :              * but we took care of that in the scanner.
     562                 :              */
     563               0 :             JS_ALWAYS_TRUE(!ReportBadParameter(cx, tc, name, JSMSG_RESERVED_ID));
     564               0 :             return false;
     565                 :         }
     566                 : 
     567                 :         /*
     568                 :          * Check for a duplicate parameter: warn or report an error exactly
     569                 :          * once for each duplicated parameter.
     570                 :          */
     571         1067314 :         if (HashMap<JSAtom *, bool>::AddPtr p = parameters.lookupForAdd(name)) {
     572               0 :             if (!p->value && !ReportBadParameter(cx, tc, name, JSMSG_DUPLICATE_FORMAL))
     573               0 :                 return false;
     574               0 :             p->value = true;
     575                 :         } else {
     576         1067314 :             if (!parameters.add(p, name, false))
     577               0 :                 return false;
     578                 :         }
     579                 :     }
     580                 : 
     581          420026 :     return true;
     582                 : }
     583                 : 
     584                 : ParseNode *
     585          991083 : Parser::functionBody(FunctionBodyType type)
     586                 : {
     587          991083 :     JS_ASSERT(tc->inFunction());
     588                 : 
     589                 :     StmtInfo stmtInfo;
     590          991083 :     PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);
     591          991083 :     stmtInfo.flags = SIF_BODY_BLOCK;
     592                 : 
     593          991083 :     unsigned oldflags = tc->flags;
     594          991083 :     tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID);
     595                 : 
     596                 :     ParseNode *pn;
     597          991083 :     if (type == StatementListBody) {
     598          962272 :         pn = statements();
     599                 :     } else {
     600           28811 :         JS_ASSERT(type == ExpressionBody);
     601                 :         JS_ASSERT(JS_HAS_EXPR_CLOSURES);
     602           28811 :         pn = UnaryNode::create(PNK_RETURN, tc);
     603           28811 :         if (pn) {
     604           28811 :             pn->pn_kid = assignExpr();
     605           28811 :             if (!pn->pn_kid) {
     606               0 :                 pn = NULL;
     607                 :             } else {
     608           28811 :                 if (tc->flags & TCF_FUN_IS_GENERATOR) {
     609                 :                     ReportBadReturn(context, tc, pn, JSREPORT_ERROR,
     610                 :                                     JSMSG_BAD_GENERATOR_RETURN,
     611               0 :                                     JSMSG_BAD_ANON_GENERATOR_RETURN);
     612               0 :                     pn = NULL;
     613                 :                 } else {
     614           28811 :                     pn->setOp(JSOP_RETURN);
     615           28811 :                     pn->pn_pos.end = pn->pn_kid->pn_pos.end;
     616                 :                 }
     617                 :             }
     618                 :         }
     619                 :     }
     620                 : 
     621          991083 :     if (pn) {
     622          990766 :         JS_ASSERT(!(tc->topStmt->flags & SIF_SCOPE));
     623          990766 :         PopStatementTC(tc);
     624                 : 
     625                 :         /* Check for falling off the end of a function that returns a value. */
     626         1071623 :         if (context->hasStrictOption() && (tc->flags & TCF_RETURN_EXPR) &&
     627           80857 :             !CheckFinalReturn(context, tc, pn)) {
     628               0 :             pn = NULL;
     629                 :         }
     630                 :     }
     631                 : 
     632          991083 :     tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
     633          991083 :     return pn;
     634                 : }
     635                 : 
     636                 : /* Create a placeholder Definition node for |atom|. */
     637                 : static Definition *
     638         2822117 : MakePlaceholder(ParseNode *pn, TreeContext *tc)
     639                 : {
     640         2822117 :     Definition *dn = (Definition *) NameNode::create(PNK_NAME, pn->pn_atom, tc);
     641         2822117 :     if (!dn)
     642               0 :         return NULL;
     643                 : 
     644         2822117 :     dn->setOp(JSOP_NOP);
     645         2822117 :     dn->setDefn(true);
     646         2822117 :     dn->pn_dflags |= PND_PLACEHOLDER;
     647         2822117 :     return dn;
     648                 : }
     649                 : 
     650                 : static bool
     651         3312322 : Define(ParseNode *pn, JSAtom *atom, TreeContext *tc, bool let = false)
     652                 : {
     653         3312322 :     JS_ASSERT(!pn->isUsed());
     654         3312322 :     JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
     655                 : 
     656         3312322 :     bool foundLexdep = false;
     657         3312322 :     Definition *dn = NULL;
     658                 : 
     659         3312322 :     if (let)
     660          751004 :         dn = tc->decls.lookupFirst(atom);
     661                 : 
     662         3312322 :     if (!dn) {
     663         3306558 :         dn = tc->lexdeps.lookupDefn(atom);
     664         3306558 :         foundLexdep = !!dn;
     665                 :     }
     666                 : 
     667         3312322 :     if (dn && dn != pn) {
     668            9099 :         ParseNode **pnup = &dn->dn_uses;
     669                 :         ParseNode *pnu;
     670            9099 :         unsigned start = let ? pn->pn_blockid : tc->bodyid;
     671                 : 
     672           20329 :         while ((pnu = *pnup) != NULL && pnu->pn_blockid >= start) {
     673            2131 :             JS_ASSERT(pnu->isUsed());
     674            2131 :             pnu->pn_lexdef = (Definition *) pn;
     675            2131 :             pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
     676            2131 :             pnup = &pnu->pn_link;
     677                 :         }
     678                 : 
     679            9099 :         if (pnu != dn->dn_uses) {
     680            1963 :             *pnup = pn->dn_uses;
     681            1963 :             pn->dn_uses = dn->dn_uses;
     682            1963 :             dn->dn_uses = pnu;
     683                 : 
     684            1963 :             if ((!pnu || pnu->pn_blockid < tc->bodyid) && foundLexdep)
     685            1963 :                 tc->lexdeps->remove(atom);
     686                 :         }
     687                 : 
     688            9099 :         pn->pn_dflags |= dn->pn_dflags & PND_CLOSED;
     689                 :     }
     690                 : 
     691         3312322 :     Definition *toAdd = (Definition *) pn;
     692         3312322 :     bool ok = let ? tc->decls.addShadow(atom, toAdd) : tc->decls.addUnique(atom, toAdd);
     693         3312322 :     if (!ok)
     694               0 :         return false;
     695         3312322 :     pn->setDefn(true);
     696         3312322 :     pn->pn_dflags &= ~PND_PLACEHOLDER;
     697         3312322 :     if (!tc->parent)
     698          739808 :         pn->pn_dflags |= PND_TOPLEVEL;
     699         3312322 :     return true;
     700                 : }
     701                 : 
     702                 : static void
     703             211 : ForgetUse(ParseNode *pn)
     704                 : {
     705             211 :     if (!pn->isUsed()) {
     706               0 :         JS_ASSERT(!pn->isDefn());
     707               0 :         return;
     708                 :     }
     709                 : 
     710             211 :     ParseNode **pnup = &pn->lexdef()->dn_uses;
     711                 :     ParseNode *pnu;
     712             422 :     while ((pnu = *pnup) != pn)
     713               0 :         pnup = &pnu->pn_link;
     714             211 :     *pnup = pn->pn_link;
     715             211 :     pn->setUsed(false);
     716                 : }
     717                 : 
     718                 : static ParseNode *
     719            7511 : MakeAssignment(ParseNode *pn, ParseNode *rhs, TreeContext *tc)
     720                 : {
     721            7511 :     ParseNode *lhs = tc->parser->cloneNode(*pn);
     722            7511 :     if (!lhs)
     723               0 :         return NULL;
     724                 : 
     725            7511 :     if (pn->isUsed()) {
     726            7511 :         Definition *dn = pn->pn_lexdef;
     727            7511 :         ParseNode **pnup = &dn->dn_uses;
     728                 : 
     729           15466 :         while (*pnup != pn)
     730             444 :             pnup = &(*pnup)->pn_link;
     731            7511 :         *pnup = lhs;
     732            7511 :         lhs->pn_link = pn->pn_link;
     733            7511 :         pn->pn_link = NULL;
     734                 :     }
     735                 : 
     736            7511 :     pn->setKind(PNK_ASSIGN);
     737            7511 :     pn->setOp(JSOP_NOP);
     738            7511 :     pn->setArity(PN_BINARY);
     739            7511 :     pn->setInParens(false);
     740            7511 :     pn->setUsed(false);
     741            7511 :     pn->setDefn(false);
     742            7511 :     pn->pn_left = lhs;
     743            7511 :     pn->pn_right = rhs;
     744            7511 :     return lhs;
     745                 : }
     746                 : 
     747                 : static ParseNode *
     748              68 : MakeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom, TreeContext *tc)
     749                 : {
     750                 :     /*
     751                 :      * If dn is arg, or in [var, const, let] and has an initializer, then we
     752                 :      * must rewrite it to be an assignment node, whose freshly allocated
     753                 :      * left-hand side becomes a use of pn.
     754                 :      */
     755              68 :     if (dn->isBindingForm()) {
     756              27 :         ParseNode *rhs = dn->expr();
     757              27 :         if (rhs) {
     758               0 :             ParseNode *lhs = MakeAssignment(dn, rhs, tc);
     759               0 :             if (!lhs)
     760               0 :                 return NULL;
     761                 :             //pn->dn_uses = lhs;
     762               0 :             dn = (Definition *) lhs;
     763                 :         }
     764                 : 
     765              27 :         dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME);
     766              41 :     } else if (dn->kind() == Definition::FUNCTION) {
     767              23 :         JS_ASSERT(dn->isOp(JSOP_NOP));
     768              23 :         tc->parser->prepareNodeForMutation(dn);
     769              23 :         dn->setKind(PNK_NAME);
     770              23 :         dn->setArity(PN_NAME);
     771              23 :         dn->pn_atom = atom;
     772                 :     }
     773                 : 
     774                 :     /* Now make dn no longer a definition, rather a use of pn. */
     775              68 :     JS_ASSERT(dn->isKind(PNK_NAME));
     776              68 :     JS_ASSERT(dn->isArity(PN_NAME));
     777              68 :     JS_ASSERT(dn->pn_atom == atom);
     778                 : 
     779             112 :     for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
     780              44 :         JS_ASSERT(pnu->isUsed());
     781              44 :         JS_ASSERT(!pnu->isDefn());
     782              44 :         pnu->pn_lexdef = (Definition *) pn;
     783              44 :         pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
     784                 :     }
     785              68 :     pn->pn_dflags |= dn->pn_dflags & PND_USE2DEF_FLAGS;
     786              68 :     pn->dn_uses = dn;
     787                 : 
     788              68 :     dn->setDefn(false);
     789              68 :     dn->setUsed(true);
     790              68 :     dn->pn_lexdef = (Definition *) pn;
     791              68 :     dn->pn_cookie.makeFree();
     792              68 :     dn->pn_dflags &= ~PND_BOUND;
     793              68 :     return dn;
     794                 : }
     795                 : 
     796                 : bool
     797         1208434 : js::DefineArg(ParseNode *pn, JSAtom *atom, unsigned i, TreeContext *tc)
     798                 : {
     799                 :     /* Flag tc so we don't have to lookup arguments on every use. */
     800         1208434 :     if (atom == tc->parser->context->runtime->atomState.argumentsAtom)
     801              14 :         tc->flags |= TCF_FUN_PARAM_ARGUMENTS;
     802                 : 
     803                 :     /*
     804                 :      * Make an argument definition node, distinguished by being in tc->decls
     805                 :      * but having PNK_NAME kind and JSOP_NOP op. Insert it in a PNK_ARGSBODY
     806                 :      * list node returned via pn->pn_body.
     807                 :      */
     808         1208434 :     ParseNode *argpn = NameNode::create(PNK_NAME, atom, tc);
     809         1208434 :     if (!argpn)
     810               0 :         return false;
     811         1208434 :     JS_ASSERT(argpn->isKind(PNK_NAME) && argpn->isOp(JSOP_NOP));
     812                 : 
     813                 :     /* Arguments are initialized by definition. */
     814         1208434 :     argpn->pn_dflags |= PND_INITIALIZED;
     815         1208434 :     if (!Define(argpn, atom, tc))
     816               0 :         return false;
     817                 : 
     818         1208434 :     ParseNode *argsbody = pn->pn_body;
     819         1208434 :     if (!argsbody) {
     820          648287 :         argsbody = ListNode::create(PNK_ARGSBODY, tc);
     821          648287 :         if (!argsbody)
     822               0 :             return false;
     823          648287 :         argsbody->setOp(JSOP_NOP);
     824          648287 :         argsbody->makeEmpty();
     825          648287 :         pn->pn_body = argsbody;
     826                 :     }
     827         1208434 :     argsbody->append(argpn);
     828                 : 
     829         1208434 :     argpn->setOp(JSOP_GETARG);
     830         1208434 :     argpn->pn_cookie.set(tc->staticLevel, i);
     831         1208434 :     argpn->pn_dflags |= PND_BOUND;
     832         1208434 :     return true;
     833                 : }
     834                 : 
     835                 : /*
     836                 :  * Parameter block types for the several Binder functions.  We use a common
     837                 :  * helper function signature in order to share code among destructuring and
     838                 :  * simple variable declaration parsers.  In the destructuring case, the binder
     839                 :  * function is called indirectly from the variable declaration parser by way
     840                 :  * of CheckDestructuring and its friends.
     841                 :  */
     842                 : typedef JSBool
     843                 : (*Binder)(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc);
     844                 : 
     845                 : static JSBool
     846                 : BindLet(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc);
     847                 : 
     848                 : static JSBool
     849                 : BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc);
     850                 : 
     851                 : struct BindData {
     852         1555494 :     BindData() : fresh(true) {}
     853                 : 
     854                 :     ParseNode       *pn;        /* name node for definition processing and
     855                 :                                    error source coordinates */
     856                 :     JSOp            op;         /* prolog bytecode or nop */
     857                 :     Binder          binder;     /* binder, discriminates u */
     858                 :     union {
     859                 :         struct {
     860                 :             VarContext varContext;
     861                 :             StaticBlockObject *blockObj;
     862                 :             unsigned   overflow;
     863                 :         } let;
     864                 :     };
     865                 :     bool fresh;
     866                 : 
     867          522313 :     void initLet(VarContext varContext, StaticBlockObject &blockObj, unsigned overflow) {
     868          522313 :         this->pn = NULL;
     869          522313 :         this->op = JSOP_NOP;
     870          522313 :         this->binder = BindLet;
     871          522313 :         this->let.varContext = varContext;
     872          522313 :         this->let.blockObj = &blockObj;
     873          522313 :         this->let.overflow = overflow;
     874          522313 :     }
     875                 : 
     876         1031625 :     void initVarOrConst(JSOp op) {
     877         1031625 :         this->op = op;
     878         1031625 :         this->binder = BindVarOrConst;
     879         1031625 :     }
     880                 : };
     881                 : 
     882                 : static bool
     883          814062 : BindLocalVariable(JSContext *cx, TreeContext *tc, ParseNode *pn, BindingKind kind)
     884                 : {
     885          814062 :     JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
     886                 : 
     887                 :     /* 'arguments' can be bound as a local only via a destructuring formal parameter. */
     888          814062 :     JS_ASSERT_IF(pn->pn_atom == cx->runtime->atomState.argumentsAtom, kind == VARIABLE);
     889                 : 
     890          814062 :     unsigned index = tc->bindings.countVars();
     891          814062 :     if (!tc->bindings.add(cx, pn->pn_atom, kind))
     892               0 :         return false;
     893                 : 
     894          814062 :     pn->pn_cookie.set(tc->staticLevel, index);
     895          814062 :     pn->pn_dflags |= PND_BOUND;
     896          814062 :     return true;
     897                 : }
     898                 : 
     899                 : #if JS_HAS_DESTRUCTURING
     900                 : static JSBool
     901            5083 : BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc)
     902                 : {
     903                 :     /* Flag tc so we don't have to lookup arguments on every use. */
     904            5083 :     if (atom == tc->parser->context->runtime->atomState.argumentsAtom)
     905               0 :         tc->flags |= TCF_FUN_PARAM_ARGUMENTS;
     906                 : 
     907            5083 :     JS_ASSERT(tc->inFunction());
     908                 : 
     909                 :     /*
     910                 :      * NB: Check tc->decls rather than tc->bindings, because destructuring
     911                 :      *     bindings aren't added to tc->bindings until after all arguments have
     912                 :      *     been parsed.
     913                 :      */
     914            5083 :     if (tc->decls.lookupFirst(atom)) {
     915                 :         ReportCompileErrorNumber(cx, TS(tc->parser), NULL, JSREPORT_ERROR,
     916               0 :                                  JSMSG_DESTRUCT_DUP_ARG);
     917               0 :         return JS_FALSE;
     918                 :     }
     919                 : 
     920            5083 :     ParseNode *pn = data->pn;
     921                 : 
     922                 :     /*
     923                 :      * Distinguish destructured-to binding nodes as vars, not args, by setting
     924                 :      * pn_op to JSOP_SETLOCAL. Parser::functionDef checks for this pn_op value
     925                 :      * when processing the destructuring-assignment AST prelude induced by such
     926                 :      * destructuring args in Parser::functionArguments.
     927                 :      *
     928                 :      * We must set the PND_BOUND flag too to prevent pn_op from being reset to
     929                 :      * JSOP_SETNAME by BindDestructuringVar. The only field not initialized is
     930                 :      * pn_cookie; it gets set in functionDef in the first "if (prelude)" block.
     931                 :      * We have to wait to set the cookie until we can call JSFunction::addLocal
     932                 :      * with kind = JSLOCAL_VAR, after all JSLOCAL_ARG locals have been added.
     933                 :      *
     934                 :      * Thus a destructuring formal parameter binds an ARG (as in arguments[i]
     935                 :      * element) with a null atom name for the object or array passed in to be
     936                 :      * destructured, and zero or more VARs (as in named local variables) for
     937                 :      * the destructured-to identifiers in the property value positions within
     938                 :      * the object or array destructuring pattern, and all ARGs for the formal
     939                 :      * parameter list bound as locals before any VAR for a destructured name.
     940                 :      */
     941            5083 :     pn->setOp(JSOP_SETLOCAL);
     942            5083 :     pn->pn_dflags |= PND_BOUND;
     943                 : 
     944            5083 :     return Define(pn, atom, tc);
     945                 : }
     946                 : #endif /* JS_HAS_DESTRUCTURING */
     947                 : 
     948                 : JSFunction *
     949          980883 : Parser::newFunction(TreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind)
     950                 : {
     951          980883 :     JS_ASSERT_IF(kind == Statement, atom != NULL);
     952                 : 
     953                 :     /*
     954                 :      * Find the global compilation context in order to pre-set the newborn
     955                 :      * function's parent slot to tc->scopeChain. If the global context is a
     956                 :      * compile-and-go one, we leave the pre-set parent intact; otherwise we
     957                 :      * clear parent and proto.
     958                 :      */
     959         2340850 :     while (tc->parent)
     960          379084 :         tc = tc->parent;
     961                 : 
     962         1961766 :     RootedVarObject parent(context);
     963          980883 :     parent = tc->inFunction() ? NULL : tc->scopeChain();
     964                 : 
     965                 :     JSFunction *fun =
     966                 :         js_NewFunction(context, NULL, NULL, 0,
     967                 :                        JSFUN_INTERPRETED | (kind == Expression ? JSFUN_LAMBDA : 0),
     968          980883 :                        parent, atom);
     969          980883 :     if (fun && !tc->compileAndGo()) {
     970          865568 :         if (!fun->clearParent(context))
     971               0 :             return NULL;
     972          865568 :         if (!fun->clearType(context))
     973               0 :             return NULL;
     974          865568 :         fun->setEnvironment(NULL);
     975                 :     }
     976          980883 :     return fun;
     977                 : }
     978                 : 
     979                 : static JSBool
     980         8525889 : MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts)
     981                 : {
     982         8525889 :     TokenKind tt = ts->peekTokenSameLine(TSF_OPERAND);
     983         8525889 :     if (tt == TOK_ERROR)
     984               0 :         return JS_FALSE;
     985         8525889 :     if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
     986                 :         /* Advance the scanner for proper error location reporting. */
     987              21 :         ts->getToken(TSF_OPERAND);
     988              21 :         ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_SEMI_BEFORE_STMNT);
     989              21 :         return JS_FALSE;
     990                 :     }
     991         8525868 :     (void) ts->matchToken(TOK_SEMI);
     992         8525868 :     return JS_TRUE;
     993                 : }
     994                 : 
     995                 : static FunctionBox *
     996          980883 : EnterFunction(ParseNode *fn, TreeContext *funtc, JSAtom *funAtom = NULL,
     997                 :               FunctionSyntaxKind kind = Expression)
     998                 : {
     999          980883 :     TreeContext *tc = funtc->parent;
    1000          980883 :     JSFunction *fun = tc->parser->newFunction(tc, funAtom, kind);
    1001          980883 :     if (!fun)
    1002               0 :         return NULL;
    1003                 : 
    1004                 :     /* Create box for fun->object early to protect against last-ditch GC. */
    1005          980883 :     FunctionBox *funbox = tc->parser->newFunctionBox(fun, fn, tc);
    1006          980883 :     if (!funbox)
    1007               0 :         return NULL;
    1008                 : 
    1009                 :     /* Initialize non-default members of funtc. */
    1010          980883 :     funtc->flags |= funbox->tcflags;
    1011          980883 :     funtc->blockidGen = tc->blockidGen;
    1012          980883 :     if (!GenerateBlockId(funtc, funtc->bodyid))
    1013               0 :         return NULL;
    1014          980883 :     funtc->setFunction(fun);
    1015          980883 :     funtc->funbox = funbox;
    1016          980883 :     if (!SetStaticLevel(funtc, tc->staticLevel + 1))
    1017               0 :         return NULL;
    1018                 : 
    1019          980883 :     return funbox;
    1020                 : }
    1021                 : 
    1022                 : static bool
    1023           11238 : DeoptimizeUsesWithin(Definition *dn, const TokenPos &pos)
    1024                 : {
    1025           11238 :     unsigned ndeoptimized = 0;
    1026                 : 
    1027          119816 :     for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
    1028          108578 :         JS_ASSERT(pnu->isUsed());
    1029          108578 :         JS_ASSERT(!pnu->isDefn());
    1030          108578 :         if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end) {
    1031          108164 :             pnu->pn_dflags |= PND_DEOPTIMIZED;
    1032          108164 :             ++ndeoptimized;
    1033                 :         }
    1034                 :     }
    1035                 : 
    1036           11238 :     return ndeoptimized != 0;
    1037                 : }
    1038                 : 
    1039                 : static bool
    1040          980874 : LeaveFunction(ParseNode *fn, TreeContext *funtc, PropertyName *funName = NULL,
    1041                 :               FunctionSyntaxKind kind = Expression)
    1042                 : {
    1043          980874 :     TreeContext *tc = funtc->parent;
    1044          980874 :     tc->blockidGen = funtc->blockidGen;
    1045                 : 
    1046          980874 :     FunctionBox *funbox = fn->pn_funbox;
    1047          980874 :     funbox->tcflags |= funtc->flags & (TCF_FUN_FLAGS | TCF_COMPILE_N_GO | TCF_RETURN_EXPR);
    1048                 : 
    1049          980874 :     fn->pn_dflags |= PND_INITIALIZED;
    1050          980874 :     if (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)
    1051          968310 :         fn->pn_dflags |= PND_BLOCKCHILD;
    1052                 : 
    1053                 :     /*
    1054                 :      * Propagate unresolved lexical names up to tc->lexdeps, and save a copy
    1055                 :      * of funtc->lexdeps in a TOK_UPVARS node wrapping the function's formal
    1056                 :      * params and body. We do this only if there are lexical dependencies not
    1057                 :      * satisfied by the function's declarations, to avoid penalizing functions
    1058                 :      * that use only their arguments and other local bindings.
    1059                 :      */
    1060          980874 :     if (funtc->lexdeps->count()) {
    1061          811849 :         int foundCallee = 0;
    1062                 : 
    1063         3236811 :         for (AtomDefnRange r = funtc->lexdeps->all(); !r.empty(); r.popFront()) {
    1064         2424962 :             JSAtom *atom = r.front().key();
    1065         2424962 :             Definition *dn = r.front().value();
    1066         2424962 :             JS_ASSERT(dn->isPlaceholder());
    1067                 : 
    1068         2424962 :             if (atom == funName && kind == Expression) {
    1069            1588 :                 dn->setOp(JSOP_CALLEE);
    1070            1588 :                 dn->pn_cookie.set(funtc->staticLevel, UpvarCookie::CALLEE_SLOT);
    1071            1588 :                 dn->pn_dflags |= PND_BOUND;
    1072                 : 
    1073                 :                 /*
    1074                 :                  * If this named function expression uses its own name other
    1075                 :                  * than to call itself, flag this function specially.
    1076                 :                  */
    1077            1588 :                 if (dn->isFunArg())
    1078            1250 :                     funbox->tcflags |= TCF_FUN_USES_OWN_NAME;
    1079            1588 :                 foundCallee = 1;
    1080            1588 :                 continue;
    1081                 :             }
    1082                 : 
    1083         4540150 :             if (!(funbox->tcflags & TCF_FUN_SETS_OUTER_NAME) &&
    1084         2116776 :                 dn->isAssigned()) {
    1085                 :                 /*
    1086                 :                  * Make sure we do not fail to set TCF_FUN_SETS_OUTER_NAME if
    1087                 :                  * any use of dn in funtc assigns. See NoteLValue for the easy
    1088                 :                  * backward-reference case; this is the hard forward-reference
    1089                 :                  * case where we pay a higher price.
    1090                 :                  */
    1091            6737 :                 for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
    1092            6737 :                     if (pnu->isAssigned() && pnu->pn_blockid >= funtc->bodyid) {
    1093            6655 :                         funbox->tcflags |= TCF_FUN_SETS_OUTER_NAME;
    1094            6655 :                         break;
    1095                 :                     }
    1096                 :                 }
    1097                 :             }
    1098                 : 
    1099         2423374 :             Definition *outer_dn = tc->decls.lookupFirst(atom);
    1100                 : 
    1101                 :             /*
    1102                 :              * Make sure to deoptimize lexical dependencies that are polluted
    1103                 :              * by eval or with, to safely bind globals (see bug 561923).
    1104                 :              */
    1105         2423428 :             if (funtc->callsEval() ||
    1106                 :                 (outer_dn && tc->innermostWith &&
    1107              54 :                  outer_dn->pn_pos < tc->innermostWith->pn_pos)) {
    1108           10338 :                 DeoptimizeUsesWithin(dn, fn->pn_pos);
    1109                 :             }
    1110                 : 
    1111         2423374 :             if (!outer_dn) {
    1112         1310746 :                 AtomDefnAddPtr p = tc->lexdeps->lookupForAdd(atom);
    1113         1310746 :                 if (p) {
    1114          785047 :                     outer_dn = p.value();
    1115                 :                 } else {
    1116                 :                     /*
    1117                 :                      * Create a new placeholder for our outer lexdep. We could
    1118                 :                      * simply re-use the inner placeholder, but that introduces
    1119                 :                      * subtleties in the case where we find a later definition
    1120                 :                      * that captures an existing lexdep. For example:
    1121                 :                      *
    1122                 :                      *   function f() { function g() { x; } let x; }
    1123                 :                      *
    1124                 :                      * Here, g's TOK_UPVARS node lists the placeholder for x,
    1125                 :                      * which must be captured by the 'let' declaration later,
    1126                 :                      * since 'let's are hoisted.  Taking g's placeholder as our
    1127                 :                      * own would work fine. But consider:
    1128                 :                      *
    1129                 :                      *   function f() { x; { function g() { x; } let x; } }
    1130                 :                      *
    1131                 :                      * Here, the 'let' must not capture all the uses of f's
    1132                 :                      * lexdep entry for x, but it must capture the x node
    1133                 :                      * referred to from g's TOK_UPVARS node.  Always turning
    1134                 :                      * inherited lexdeps into uses of a new outer definition
    1135                 :                      * allows us to handle both these cases in a natural way.
    1136                 :                      */
    1137          525699 :                     outer_dn = MakePlaceholder(dn, tc);
    1138          525699 :                     if (!outer_dn || !tc->lexdeps->add(p, atom, outer_dn))
    1139               0 :                         return false;
    1140                 :                 }
    1141                 :             }
    1142                 : 
    1143                 :             /*
    1144                 :              * Insert dn's uses list at the front of outer_dn's list.
    1145                 :              *
    1146                 :              * Without loss of generality or correctness, we allow a dn to
    1147                 :              * be in inner and outer lexdeps, since the purpose of lexdeps
    1148                 :              * is one-pass coordination of name use and definition across
    1149                 :              * functions, and if different dn's are used we'll merge lists
    1150                 :              * when leaving the inner function.
    1151                 :              *
    1152                 :              * The dn == outer_dn case arises with generator expressions
    1153                 :              * (see CompExprTransplanter::transplant, the PN_FUNC/PN_NAME
    1154                 :              * case), and nowhere else, currently.
    1155                 :              */
    1156         2423374 :             if (dn != outer_dn) {
    1157         2423374 :                 ParseNode **pnup = &dn->dn_uses;
    1158                 :                 ParseNode *pnu;
    1159                 : 
    1160        10907406 :                 while ((pnu = *pnup) != NULL) {
    1161         6060658 :                     pnu->pn_lexdef = outer_dn;
    1162         6060658 :                     pnup = &pnu->pn_link;
    1163                 :                 }
    1164                 : 
    1165                 :                 /*
    1166                 :                  * Make dn be a use that redirects to outer_dn, because we
    1167                 :                  * can't replace dn with outer_dn in all the pn_namesets in
    1168                 :                  * the AST where it may be. Instead we make it forward to
    1169                 :                  * outer_dn. See Definition::resolve.
    1170                 :                  */
    1171         2423374 :                 *pnup = outer_dn->dn_uses;
    1172         2423374 :                 outer_dn->dn_uses = dn;
    1173         2423374 :                 outer_dn->pn_dflags |= dn->pn_dflags & ~PND_PLACEHOLDER;
    1174         2423374 :                 dn->setDefn(false);
    1175         2423374 :                 dn->setUsed(true);
    1176         2423374 :                 dn->pn_lexdef = outer_dn;
    1177                 :             }
    1178                 : 
    1179                 :             /* Mark the outer dn as escaping. */
    1180         2423374 :             outer_dn->pn_dflags |= PND_CLOSED;
    1181                 :         }
    1182                 : 
    1183          811849 :         if (funtc->lexdeps->count() - foundCallee != 0) {
    1184          811750 :             ParseNode *body = fn->pn_body;
    1185                 : 
    1186          811750 :             fn->pn_body = NameSetNode::create(PNK_UPVARS, tc);
    1187          811750 :             if (!fn->pn_body)
    1188               0 :                 return false;
    1189                 : 
    1190          811750 :             fn->pn_body->pn_pos = body->pn_pos;
    1191          811750 :             if (foundCallee)
    1192            1489 :                 funtc->lexdeps->remove(funName);
    1193                 :             /* Transfer ownership of the lexdep map to the parse node. */
    1194          811750 :             fn->pn_body->pn_names = funtc->lexdeps;
    1195          811750 :             funtc->lexdeps.clearMap();
    1196          811750 :             fn->pn_body->pn_tree = body;
    1197                 :         } else {
    1198              99 :             funtc->lexdeps.releaseMap(funtc->parser->context);
    1199                 :         }
    1200                 : 
    1201                 :     }
    1202                 : 
    1203                 :     /*
    1204                 :      * Check whether any parameters have been assigned within this function.
    1205                 :      * In strict mode parameters do not alias arguments[i], and to make the
    1206                 :      * arguments object reflect initial parameter values prior to any mutation
    1207                 :      * we create it eagerly whenever parameters are (or might, in the case of
    1208                 :      * calls to eval) be assigned.
    1209                 :      */
    1210          980874 :     if (funtc->inStrictMode() && funbox->object->toFunction()->nargs > 0) {
    1211          263673 :         AtomDeclsIter iter(&funtc->decls);
    1212                 :         Definition *dn;
    1213                 : 
    1214          263673 :         while ((dn = iter()) != NULL) {
    1215          633142 :             if (dn->kind() == Definition::ARG && dn->isAssigned()) {
    1216            6681 :                 funbox->tcflags |= TCF_FUN_MUTATES_PARAMETER;
    1217            6681 :                 break;
    1218                 :             }
    1219                 :         }
    1220                 :     }
    1221                 : 
    1222          980874 :     funbox->bindings.transfer(funtc->parser->context, &funtc->bindings);
    1223                 : 
    1224          980874 :     return true;
    1225                 : }
    1226                 : 
    1227                 : static bool
    1228                 : DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name);
    1229                 : 
    1230                 : /*
    1231                 :  * FIXME? this Parser method was factored from Parser::functionDef with minimal
    1232                 :  * change, hence the funtc ref param and funbox. It probably should match
    1233                 :  * functionBody, etc., and use tc and tc->funbox instead of taking explicit
    1234                 :  * parameters.
    1235                 :  */
    1236                 : bool
    1237          980670 : Parser::functionArguments(TreeContext &funtc, FunctionBox *funbox, ParseNode **listp)
    1238                 : {
    1239          980670 :     if (tokenStream.getToken() != TOK_LP) {
    1240               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_BEFORE_FORMAL);
    1241               0 :         return false;
    1242                 :     }
    1243                 : 
    1244          980670 :     if (!tokenStream.matchToken(TOK_RP)) {
    1245                 : #if JS_HAS_DESTRUCTURING
    1246          645055 :         JSAtom *duplicatedArg = NULL;
    1247          645055 :         bool destructuringArg = false;
    1248          645055 :         ParseNode *list = NULL;
    1249                 : #endif
    1250                 : 
    1251         1205257 :         do {
    1252         1205257 :             switch (TokenKind tt = tokenStream.getToken()) {
    1253                 : #if JS_HAS_DESTRUCTURING
    1254                 :               case TOK_LB:
    1255                 :               case TOK_LC:
    1256                 :               {
    1257                 :                 /* See comment below in the TOK_NAME case. */
    1258            1556 :                 if (duplicatedArg)
    1259               0 :                     goto report_dup_and_destructuring;
    1260            1556 :                 destructuringArg = true;
    1261                 : 
    1262                 :                 /*
    1263                 :                  * A destructuring formal parameter turns into one or more
    1264                 :                  * local variables initialized from properties of a single
    1265                 :                  * anonymous positional parameter, so here we must tweak our
    1266                 :                  * binder and its data.
    1267                 :                  */
    1268            1556 :                 BindData data;
    1269            1556 :                 data.pn = NULL;
    1270            1556 :                 data.op = JSOP_DEFVAR;
    1271            1556 :                 data.binder = BindDestructuringArg;
    1272            1556 :                 ParseNode *lhs = destructuringExpr(&data, tt);
    1273            1556 :                 if (!lhs)
    1274               0 :                     return false;
    1275                 : 
    1276                 :                 /*
    1277                 :                  * Adjust fun->nargs to count the single anonymous positional
    1278                 :                  * parameter that is to be destructured.
    1279                 :                  */
    1280                 :                 uint16_t slot;
    1281            1556 :                 if (!funtc.bindings.addDestructuring(context, &slot))
    1282               0 :                     return false;
    1283                 : 
    1284                 :                 /*
    1285                 :                  * Synthesize a destructuring assignment from the single
    1286                 :                  * anonymous positional parameter into the destructuring
    1287                 :                  * left-hand-side expression and accumulate it in list.
    1288                 :                  */
    1289                 :                 ParseNode *rhs =
    1290            1556 :                     NameNode::create(PNK_NAME, context->runtime->atomState.emptyAtom, &funtc);
    1291            1556 :                 if (!rhs)
    1292               0 :                     return false;
    1293            1556 :                 rhs->setOp(JSOP_GETARG);
    1294            1556 :                 rhs->pn_cookie.set(funtc.staticLevel, slot);
    1295            1556 :                 rhs->pn_dflags |= PND_BOUND;
    1296                 : 
    1297            1556 :                 ParseNode *item = new_<BinaryNode>(PNK_ASSIGN, JSOP_NOP, lhs->pn_pos, lhs, rhs);
    1298            1556 :                 if (!item)
    1299               0 :                     return false;
    1300            1556 :                 if (!list) {
    1301            1520 :                     list = ListNode::create(PNK_VAR, &funtc);
    1302            1520 :                     if (!list)
    1303               0 :                         return false;
    1304            1520 :                     list->makeEmpty();
    1305            1520 :                     *listp = list;
    1306                 :                 }
    1307            1556 :                 list->append(item);
    1308            1556 :                 break;
    1309                 :               }
    1310                 : #endif /* JS_HAS_DESTRUCTURING */
    1311                 : 
    1312                 :               case TOK_NAME:
    1313                 :               {
    1314         1203701 :                 PropertyName *name = tokenStream.currentToken().name();
    1315                 : 
    1316                 : #ifdef JS_HAS_DESTRUCTURING
    1317                 :                 /*
    1318                 :                  * ECMA-262 requires us to support duplicate parameter names,
    1319                 :                  * but if the parameter list includes destructuring, we
    1320                 :                  * consider the code to have "opted in" to higher standards and
    1321                 :                  * forbid duplicates. We may see a destructuring parameter
    1322                 :                  * later, so always note duplicates now.
    1323                 :                  *
    1324                 :                  * Duplicates are warned about (strict option) or cause errors
    1325                 :                  * (strict mode code), but we do those tests in one place
    1326                 :                  * below, after having parsed the body in case it begins with a
    1327                 :                  * "use strict"; directive.
    1328                 :                  *
    1329                 :                  * NB: Check funtc.decls rather than funtc.bindings, because
    1330                 :                  *     destructuring bindings aren't added to funtc.bindings
    1331                 :                  *     until after all arguments have been parsed.
    1332                 :                  */
    1333         1203701 :                 if (funtc.decls.lookupFirst(name)) {
    1334              18 :                     funtc.bindings.noteDup();
    1335              18 :                     duplicatedArg = name;
    1336              18 :                     if (destructuringArg)
    1337               0 :                         goto report_dup_and_destructuring;
    1338                 :                 }
    1339                 : #endif
    1340                 : 
    1341                 :                 uint16_t slot;
    1342         1203701 :                 if (!funtc.bindings.addArgument(context, name, &slot))
    1343               0 :                     return false;
    1344         1203701 :                 if (!DefineArg(funbox->node, name, slot, &funtc))
    1345               0 :                     return false;
    1346         1203701 :                 break;
    1347                 :               }
    1348                 : 
    1349                 :               default:
    1350               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_MISSING_FORMAL);
    1351                 :                 /* FALL THROUGH */
    1352                 :               case TOK_ERROR:
    1353               0 :                 return false;
    1354                 : 
    1355                 : #if JS_HAS_DESTRUCTURING
    1356                 :               report_dup_and_destructuring:
    1357               0 :                 Definition *dn = funtc.decls.lookupFirst(duplicatedArg);
    1358               0 :                 reportErrorNumber(dn, JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG);
    1359               0 :                 return false;
    1360                 : #endif
    1361                 :             }
    1362         1205257 :         } while (tokenStream.matchToken(TOK_COMMA));
    1363                 : 
    1364          645055 :         if (tokenStream.getToken() != TOK_RP) {
    1365               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_AFTER_FORMAL);
    1366               0 :             return false;
    1367                 :         }
    1368                 :     }
    1369                 : 
    1370          980670 :     return true;
    1371                 : }
    1372                 : 
    1373                 : ParseNode *
    1374          980670 : Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind kind)
    1375                 : {
    1376          980670 :     JS_ASSERT_IF(kind == Statement, funName);
    1377                 : 
    1378                 :     /* Make a TOK_FUNCTION node. */
    1379          980670 :     ParseNode *pn = FunctionNode::create(PNK_FUNCTION, tc);
    1380          980670 :     if (!pn)
    1381               0 :         return NULL;
    1382          980670 :     pn->pn_body = NULL;
    1383          980670 :     pn->pn_cookie.makeFree();
    1384                 : 
    1385                 :     /*
    1386                 :      * If this is a function expression, mark this function as escaping (as a
    1387                 :      * "funarg") unless it is immediately applied (we clear PND_FUNARG if so --
    1388                 :      * see memberExpr).
    1389                 :      *
    1390                 :      * Treat function sub-statements (those not at body level of a function or
    1391                 :      * program) as escaping funargs, since we can't statically analyze their
    1392                 :      * definitions and uses.
    1393                 :      */
    1394          980670 :     bool bodyLevel = tc->atBodyLevel();
    1395          980670 :     pn->pn_dflags = (kind == Expression || !bodyLevel) ? PND_FUNARG : 0;
    1396                 : 
    1397                 :     /*
    1398                 :      * Record names for function statements in tc->decls so we know when to
    1399                 :      * avoid optimizing variable references that might name a function.
    1400                 :      */
    1401          980670 :     if (kind == Statement) {
    1402          229247 :         if (Definition *dn = tc->decls.lookupFirst(funName)) {
    1403              77 :             Definition::Kind dn_kind = dn->kind();
    1404                 : 
    1405              77 :             JS_ASSERT(!dn->isUsed());
    1406              77 :             JS_ASSERT(dn->isDefn());
    1407                 : 
    1408              77 :             if (context->hasStrictOption() || dn_kind == Definition::CONST) {
    1409              10 :                 JSAutoByteString name;
    1410              10 :                 if (!js_AtomToPrintableString(context, funName, &name) ||
    1411                 :                     !reportErrorNumber(NULL,
    1412                 :                                        (dn_kind != Definition::CONST)
    1413                 :                                        ? JSREPORT_WARNING | JSREPORT_STRICT
    1414                 :                                        : JSREPORT_ERROR,
    1415                 :                                        JSMSG_REDECLARED_VAR,
    1416                 :                                        Definition::kindString(dn_kind),
    1417               5 :                                        name.ptr())) {
    1418               0 :                     return NULL;
    1419                 :                 }
    1420                 :             }
    1421                 : 
    1422              77 :             if (bodyLevel) {
    1423              68 :                 tc->decls.updateFirst(funName, (Definition *) pn);
    1424              68 :                 pn->setDefn(true);
    1425              68 :                 pn->dn_uses = dn; /* dn->dn_uses is now pn_link */
    1426                 : 
    1427              68 :                 if (!MakeDefIntoUse(dn, pn, funName, tc))
    1428               0 :                     return NULL;
    1429                 :             }
    1430          229170 :         } else if (bodyLevel) {
    1431                 :             /*
    1432                 :              * If this function was used before it was defined, claim the
    1433                 :              * pre-created definition node for this function that primaryExpr
    1434                 :              * put in tc->lexdeps on first forward reference, and recycle pn.
    1435                 :              */
    1436                 : 
    1437          226536 :             if (Definition *fn = tc->lexdeps.lookupDefn(funName)) {
    1438           42701 :                 JS_ASSERT(fn->isDefn());
    1439           42701 :                 fn->setKind(PNK_FUNCTION);
    1440           42701 :                 fn->setArity(PN_FUNC);
    1441           42701 :                 fn->pn_pos.begin = pn->pn_pos.begin;
    1442                 : 
    1443                 :                 /*
    1444                 :                  * Set fn->pn_pos.end too, in case of error before we parse the
    1445                 :                  * closing brace.  See bug 640075.
    1446                 :                  */
    1447           42701 :                 fn->pn_pos.end = pn->pn_pos.end;
    1448                 : 
    1449           42701 :                 fn->pn_body = NULL;
    1450           42701 :                 fn->pn_cookie.makeFree();
    1451                 : 
    1452           42701 :                 tc->lexdeps->remove(funName);
    1453           42701 :                 freeTree(pn);
    1454           42701 :                 pn = fn;
    1455                 :             }
    1456                 : 
    1457          226536 :             if (!Define(pn, funName, tc))
    1458               0 :                 return NULL;
    1459                 :         }
    1460                 : 
    1461                 :         /*
    1462                 :          * A function directly inside another's body needs only a local
    1463                 :          * variable to bind its name to its value, and not an activation object
    1464                 :          * property (it might also need the activation property, if the outer
    1465                 :          * function contains with statements, e.g., but the stack slot wins
    1466                 :          * when BytecodeEmitter.cpp's BindNameToSlot can optimize a JSOP_NAME
    1467                 :          * into a JSOP_GETLOCAL bytecode).
    1468                 :          */
    1469          229247 :         if (bodyLevel && tc->inFunction()) {
    1470                 :             /*
    1471                 :              * Define a local in the outer function so that BindNameToSlot
    1472                 :              * can properly optimize accesses. Note that we need a local
    1473                 :              * variable, not an argument, for the function statement. Thus
    1474                 :              * we add a variable even if a parameter with the given name
    1475                 :              * already exists.
    1476                 :              */
    1477                 :             unsigned index;
    1478           41008 :             switch (tc->bindings.lookup(context, funName, &index)) {
    1479                 :               case NONE:
    1480                 :               case ARGUMENT:
    1481           41008 :                 index = tc->bindings.countVars();
    1482           41008 :                 if (!tc->bindings.addVariable(context, funName))
    1483               0 :                     return NULL;
    1484                 :                 /* FALL THROUGH */
    1485                 : 
    1486                 :               case VARIABLE:
    1487           41008 :                 pn->pn_cookie.set(tc->staticLevel, index);
    1488           41008 :                 pn->pn_dflags |= PND_BOUND;
    1489           41008 :                 break;
    1490                 : 
    1491                 :               default:;
    1492                 :             }
    1493                 :         }
    1494                 :     }
    1495                 : 
    1496          980670 :     TreeContext *outertc = tc;
    1497                 : 
    1498                 :     /* Initialize early for possible flags mutation via destructuringExpr. */
    1499         1961340 :     TreeContext funtc(tc->parser);
    1500          980670 :     if (!funtc.init(context))
    1501               0 :         return NULL;
    1502                 : 
    1503          980670 :     FunctionBox *funbox = EnterFunction(pn, &funtc, funName, kind);
    1504          980670 :     if (!funbox)
    1505               0 :         return NULL;
    1506                 : 
    1507          980670 :     JSFunction *fun = funbox->function();
    1508                 : 
    1509                 :     /* Now parse formal argument list and compute fun->nargs. */
    1510          980670 :     ParseNode *prelude = NULL;
    1511          980670 :     if (!functionArguments(funtc, funbox, &prelude))
    1512               0 :         return NULL;
    1513                 : 
    1514          980670 :     fun->setArgCount(funtc.bindings.countArgs());
    1515                 : 
    1516                 : #if JS_HAS_DESTRUCTURING
    1517                 :     /*
    1518                 :      * If there were destructuring formal parameters, bind the destructured-to
    1519                 :      * local variables now that we've parsed all the regular and destructuring
    1520                 :      * formal parameters. Because js::Bindings::add must be called first for
    1521                 :      * all ARGUMENTs, then all VARIABLEs and CONSTANTs, and finally all UPVARs,
    1522                 :      * we can't bind vars induced by formal parameter destructuring until after
    1523                 :      * Parser::functionArguments has returned.
    1524                 :      */
    1525          980670 :     if (prelude) {
    1526            1520 :         AtomDeclsIter iter(&funtc.decls);
    1527                 : 
    1528           11742 :         while (Definition *apn = iter()) {
    1529                 :             /* Filter based on pn_op -- see BindDestructuringArg, above. */
    1530            5111 :             if (!apn->isOp(JSOP_SETLOCAL))
    1531              28 :                 continue;
    1532                 : 
    1533            5083 :             if (!BindLocalVariable(context, &funtc, apn, VARIABLE))
    1534               0 :                 return NULL;
    1535                 :         }
    1536                 :     }
    1537                 : #endif
    1538                 : 
    1539          980670 :     if (type == Getter && fun->nargs > 0) {
    1540                 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ACCESSOR_WRONG_ARGS,
    1541               0 :                           "getter", "no", "s");
    1542               0 :         return NULL;
    1543                 :     }
    1544          980670 :     if (type == Setter && fun->nargs != 1) {
    1545                 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ACCESSOR_WRONG_ARGS,
    1546               0 :                           "setter", "one", "");
    1547               0 :         return NULL;
    1548                 :     }
    1549                 : 
    1550          980670 :     FunctionBodyType bodyType = StatementListBody;
    1551                 : #if JS_HAS_EXPR_CLOSURES
    1552          980670 :     if (tokenStream.getToken(TSF_OPERAND) != TOK_LC) {
    1553           28811 :         tokenStream.ungetToken();
    1554           28811 :         fun->flags |= JSFUN_EXPR_CLOSURE;
    1555           28811 :         bodyType = ExpressionBody;
    1556                 :     }
    1557                 : #else
    1558                 :     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY);
    1559                 : #endif
    1560                 : 
    1561          980670 :     ParseNode *body = functionBody(bodyType);
    1562          980670 :     if (!body)
    1563               9 :         return NULL;
    1564                 : 
    1565          980661 :     if (funName && !CheckStrictBinding(context, &funtc, funName, pn))
    1566               0 :         return NULL;
    1567                 : 
    1568          980661 :     if (!CheckStrictParameters(context, &funtc))
    1569               0 :         return NULL;
    1570                 : 
    1571                 : #if JS_HAS_EXPR_CLOSURES
    1572          980661 :     if (bodyType == StatementListBody)
    1573          951850 :         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
    1574           28811 :     else if (kind == Statement && !MatchOrInsertSemicolon(context, &tokenStream))
    1575               0 :         return NULL;
    1576                 : #else
    1577                 :     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
    1578                 : #endif
    1579          980661 :     pn->pn_pos.end = tokenStream.currentToken().pos.end;
    1580                 : 
    1581                 :     /*
    1582                 :      * Fruit of the poisonous tree: if a closure calls eval, we consider the
    1583                 :      * parent to call eval. We need this for two reasons: (1) the Jaegermonkey
    1584                 :      * optimizations really need to know if eval is called transitively, and
    1585                 :      * (2) in strict mode, eval called transitively requires eager argument
    1586                 :      * creation in strict mode parent functions.
    1587                 :      *
    1588                 :      * For the latter, we really only need to propagate callsEval if both
    1589                 :      * functions are strict mode, but we don't lose much by always propagating.
    1590                 :      * The only optimization we lose this way is in the case where a function
    1591                 :      * is strict, does not mutate arguments, does not call eval directly, but
    1592                 :      * calls eval transitively.
    1593                 :      */
    1594          980661 :     if (funtc.callsEval())
    1595            4458 :         outertc->noteCallsEval();
    1596                 : 
    1597                 : #if JS_HAS_DESTRUCTURING
    1598                 :     /*
    1599                 :      * If there were destructuring formal parameters, prepend the initializing
    1600                 :      * comma expression that we synthesized to body. If the body is a return
    1601                 :      * node, we must make a special PNK_SEQ node, to prepend the destructuring
    1602                 :      * code without bracing the decompilation of the function body.
    1603                 :      */
    1604          980661 :     if (prelude) {
    1605            1520 :         if (!body->isArity(PN_LIST)) {
    1606                 :             ParseNode *block;
    1607                 : 
    1608             898 :             block = ListNode::create(PNK_SEQ, outertc);
    1609             898 :             if (!block)
    1610               0 :                 return NULL;
    1611             898 :             block->pn_pos = body->pn_pos;
    1612             898 :             block->initList(body);
    1613                 : 
    1614             898 :             body = block;
    1615                 :         }
    1616                 : 
    1617            1520 :         ParseNode *item = UnaryNode::create(PNK_SEMI, outertc);
    1618            1520 :         if (!item)
    1619               0 :             return NULL;
    1620                 : 
    1621            1520 :         item->pn_pos.begin = item->pn_pos.end = body->pn_pos.begin;
    1622            1520 :         item->pn_kid = prelude;
    1623            1520 :         item->pn_next = body->pn_head;
    1624            1520 :         body->pn_head = item;
    1625            1520 :         if (body->pn_tail == &body->pn_head)
    1626              27 :             body->pn_tail = &item->pn_next;
    1627            1520 :         ++body->pn_count;
    1628            1520 :         body->pn_xflags |= PNX_DESTRUCT;
    1629                 :     }
    1630                 : #endif
    1631                 : 
    1632                 :     /*
    1633                 :      * If we collected flags that indicate nested heavyweight functions, or
    1634                 :      * this function contains heavyweight-making statements (with statement,
    1635                 :      * visible eval call, or assignment to 'arguments'), flag the function as
    1636                 :      * heavyweight (requiring a call object per invocation).
    1637                 :      */
    1638          980661 :     if (funtc.flags & TCF_FUN_HEAVYWEIGHT) {
    1639            8471 :         fun->flags |= JSFUN_HEAVYWEIGHT;
    1640            8471 :         outertc->flags |= TCF_FUN_HEAVYWEIGHT;
    1641                 :     } else {
    1642                 :         /*
    1643                 :          * If this function is not at body level of a program or function (i.e.
    1644                 :          * it is a function statement that is not a direct child of a program
    1645                 :          * or function), then our enclosing function, if any, must be
    1646                 :          * heavyweight.
    1647                 :          */
    1648          972190 :         if (!bodyLevel && kind == Statement)
    1649            2643 :             outertc->flags |= TCF_FUN_HEAVYWEIGHT;
    1650                 :     }
    1651                 : 
    1652          980661 :     JSOp op = JSOP_NOP;
    1653          980661 :     if (kind == Expression) {
    1654          751414 :         op = JSOP_LAMBDA;
    1655                 :     } else {
    1656          229247 :         if (!bodyLevel) {
    1657                 :             /*
    1658                 :              * Extension: in non-strict mode code, a function statement not at
    1659                 :              * the top level of a function body or whole program, e.g., in a
    1660                 :              * compound statement such as the "then" part of an "if" statement,
    1661                 :              * binds a closure only if control reaches that sub-statement.
    1662                 :              */
    1663            2643 :             JS_ASSERT(!outertc->inStrictMode());
    1664            2643 :             op = JSOP_DEFFUN;
    1665            2643 :             outertc->noteMightAliasLocals();
    1666                 :         }
    1667                 :     }
    1668                 : 
    1669          980661 :     funbox->kids = funtc.functionList;
    1670                 : 
    1671          980661 :     pn->pn_funbox = funbox;
    1672          980661 :     pn->setOp(op);
    1673          980661 :     if (pn->pn_body) {
    1674          643563 :         pn->pn_body->append(body);
    1675          643563 :         pn->pn_body->pn_pos = body->pn_pos;
    1676                 :     } else {
    1677          337098 :         pn->pn_body = body;
    1678                 :     }
    1679                 : 
    1680          980661 :     if (!outertc->inFunction() && bodyLevel && kind == Statement && outertc->compiling()) {
    1681          185596 :         JS_ASSERT(pn->pn_cookie.isFree());
    1682          185596 :         if (!DefineGlobal(pn, outertc->asBytecodeEmitter(), funName))
    1683               0 :             return NULL;
    1684                 :     }
    1685                 : 
    1686          980661 :     pn->pn_blockid = outertc->blockid();
    1687                 : 
    1688          980661 :     if (!LeaveFunction(pn, &funtc, funName, kind))
    1689               0 :         return NULL;
    1690                 : 
    1691                 :     /* If the surrounding function is not strict code, reset the lexer. */
    1692          980661 :     if (!outertc->inStrictMode())
    1693          619248 :         tokenStream.setStrictMode(false);
    1694                 : 
    1695          980661 :     return pn;
    1696                 : }
    1697                 : 
    1698                 : ParseNode *
    1699          229256 : Parser::functionStmt()
    1700                 : {
    1701          229256 :     PropertyName *name = NULL;
    1702          229256 :     if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME) {
    1703          229247 :         name = tokenStream.currentToken().name();
    1704                 :     } else {
    1705                 :         /* Unnamed function expressions are forbidden in statement context. */
    1706               9 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_UNNAMED_FUNCTION_STMT);
    1707               9 :         return NULL;
    1708                 :     }
    1709                 : 
    1710                 :     /* We forbid function statements in strict mode code. */
    1711          231890 :     if (!tc->atBodyLevel() && tc->inStrictMode()) {
    1712               0 :         reportErrorNumber(NULL, JSREPORT_STRICT_MODE_ERROR, JSMSG_STRICT_FUNCTION_STATEMENT);
    1713               0 :         return NULL;
    1714                 :     }
    1715                 : 
    1716          229247 :     return functionDef(name, Normal, Statement);
    1717                 : }
    1718                 : 
    1719                 : ParseNode *
    1720          683826 : Parser::functionExpr()
    1721                 : {
    1722          683826 :     PropertyName *name = NULL;
    1723          683826 :     if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME)
    1724          254465 :         name = tokenStream.currentToken().name();
    1725                 :     else
    1726          429361 :         tokenStream.ungetToken();
    1727          683826 :     return functionDef(name, Normal, Expression);
    1728                 : }
    1729                 : 
    1730                 : /*
    1731                 :  * Recognize Directive Prologue members and directives. Assuming |pn| is a
    1732                 :  * candidate for membership in a directive prologue, recognize directives and
    1733                 :  * set |tc|'s flags accordingly. If |pn| is indeed part of a prologue, set its
    1734                 :  * |pn_prologue| flag.
    1735                 :  *
    1736                 :  * Note that the following is a strict mode function:
    1737                 :  *
    1738                 :  * function foo() {
    1739                 :  *   "blah" // inserted semi colon
    1740                 :  *        "blurgh"
    1741                 :  *   "use\x20loose"
    1742                 :  *   "use strict"
    1743                 :  * }
    1744                 :  *
    1745                 :  * That is, even though "use\x20loose" can never be a directive, now or in the
    1746                 :  * future (because of the hex escape), the Directive Prologue extends through it
    1747                 :  * to the "use strict" statement, which is indeed a directive.
    1748                 :  */
    1749                 : bool
    1750         1025473 : Parser::recognizeDirectivePrologue(ParseNode *pn, bool *isDirectivePrologueMember)
    1751                 : {
    1752         1025473 :     *isDirectivePrologueMember = pn->isStringExprStatement();
    1753         1025473 :     if (!*isDirectivePrologueMember)
    1754         1022375 :         return true;
    1755                 : 
    1756            3098 :     ParseNode *kid = pn->pn_kid;
    1757            3098 :     if (kid->isEscapeFreeStringLiteral()) {
    1758                 :         /*
    1759                 :          * Mark this statement as being a possibly legitimate part of a
    1760                 :          * directive prologue, so the byte code emitter won't warn about it
    1761                 :          * being useless code. (We mustn't just omit the statement entirely yet,
    1762                 :          * as it could be producing the value of an eval or JSScript execution.)
    1763                 :          *
    1764                 :          * Note that even if the string isn't one we recognize as a directive,
    1765                 :          * the emitter still shouldn't flag it as useless, as it could become a
    1766                 :          * directive in the future. We don't want to interfere with people
    1767                 :          * taking advantage of directive-prologue-enabled features that appear
    1768                 :          * in other browsers first.
    1769                 :          */
    1770            3098 :         pn->pn_prologue = true;
    1771                 : 
    1772            3098 :         JSAtom *directive = kid->pn_atom;
    1773            3098 :         if (directive == context->runtime->atomState.useStrictAtom) {
    1774                 :             /*
    1775                 :              * Unfortunately, Directive Prologue members in general may contain
    1776                 :              * escapes, even while "use strict" directives may not.  Therefore
    1777                 :              * we must check whether an octal character escape has been seen in
    1778                 :              * any previous directives whenever we encounter a "use strict"
    1779                 :              * directive, so that the octal escape is properly treated as a
    1780                 :              * syntax error.  An example of this case:
    1781                 :              *
    1782                 :              *   function error()
    1783                 :              *   {
    1784                 :              *     "\145"; // octal escape
    1785                 :              *     "use strict"; // retroactively makes "\145" a syntax error
    1786                 :              *   }
    1787                 :              */
    1788            2949 :             if (tokenStream.hasOctalCharacterEscape()) {
    1789               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_DEPRECATED_OCTAL);
    1790               0 :                 return false;
    1791                 :             }
    1792                 : 
    1793            2949 :             tc->flags |= TCF_STRICT_MODE_CODE;
    1794            2949 :             tokenStream.setStrictMode();
    1795                 :         }
    1796                 :     }
    1797            3098 :     return true;
    1798                 : }
    1799                 : 
    1800                 : /*
    1801                 :  * Parse the statements in a block, creating a TOK_LC node that lists the
    1802                 :  * statements' trees.  If called from block-parsing code, the caller must
    1803                 :  * match { before and } after.
    1804                 :  */
    1805                 : ParseNode *
    1806         2323080 : Parser::statements()
    1807                 : {
    1808         2323080 :     JS_CHECK_RECURSION(context, return NULL);
    1809                 : 
    1810         2323080 :     ParseNode *pn = ListNode::create(PNK_STATEMENTLIST, tc);
    1811         2323080 :     if (!pn)
    1812               0 :         return NULL;
    1813         2323080 :     pn->makeEmpty();
    1814         2323080 :     pn->pn_blockid = tc->blockid();
    1815         2323080 :     ParseNode *saveBlock = tc->blockNode;
    1816         2323080 :     tc->blockNode = pn;
    1817                 : 
    1818         2323080 :     bool inDirectivePrologue = tc->atBodyLevel();
    1819         2323080 :     tokenStream.setOctalCharacterEscape(false);
    1820         8459436 :     for (;;) {
    1821        10782516 :         TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
    1822        10782516 :         if (tt <= TOK_EOF || tt == TOK_RC) {
    1823         2322709 :             if (tt == TOK_ERROR) {
    1824               0 :                 if (tokenStream.isEOF())
    1825               0 :                     tokenStream.setUnexpectedEOF();
    1826               0 :                 return NULL;
    1827                 :             }
    1828                 :             break;
    1829                 :         }
    1830         8459807 :         ParseNode *next = statement();
    1831         8459807 :         if (!next) {
    1832             371 :             if (tokenStream.isEOF())
    1833              11 :                 tokenStream.setUnexpectedEOF();
    1834             371 :             return NULL;
    1835                 :         }
    1836                 : 
    1837         8459436 :         if (inDirectivePrologue && !recognizeDirectivePrologue(next, &inDirectivePrologue))
    1838               0 :             return NULL;
    1839                 : 
    1840         8459436 :         if (next->isKind(PNK_FUNCTION)) {
    1841                 :             /*
    1842                 :              * PNX_FUNCDEFS notifies the emitter that the block contains body-
    1843                 :              * level function definitions that should be processed before the
    1844                 :              * rest of nodes.
    1845                 :              *
    1846                 :              * TCF_HAS_FUNCTION_STMT is for the TOK_LC case in Statement. It
    1847                 :              * is relevant only for function definitions not at body-level,
    1848                 :              * which we call function statements.
    1849                 :              */
    1850           43590 :             if (tc->atBodyLevel()) {
    1851           41008 :                 pn->pn_xflags |= PNX_FUNCDEFS;
    1852                 :             } else {
    1853            2582 :                 tc->flags |= TCF_HAS_FUNCTION_STMT;
    1854                 :                 /* Function statements extend the Call object at runtime. */
    1855            2582 :                 tc->noteHasExtensibleScope();
    1856                 :             }
    1857                 :         }
    1858         8459436 :         pn->append(next);
    1859                 :     }
    1860                 : 
    1861                 :     /*
    1862                 :      * Handle the case where there was a let declaration under this block.  If
    1863                 :      * it replaced tc->blockNode with a new block node then we must refresh pn
    1864                 :      * and then restore tc->blockNode.
    1865                 :      */
    1866         2322709 :     if (tc->blockNode != pn)
    1867          129018 :         pn = tc->blockNode;
    1868         2322709 :     tc->blockNode = saveBlock;
    1869                 : 
    1870         2322709 :     pn->pn_pos.end = tokenStream.currentToken().pos.end;
    1871         2322709 :     JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
    1872         2322709 :     return pn;
    1873                 : }
    1874                 : 
    1875                 : ParseNode *
    1876         1001884 : Parser::condition()
    1877                 : {
    1878         1001884 :     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
    1879         1001884 :     ParseNode *pn = parenExpr();
    1880         1001884 :     if (!pn)
    1881               0 :         return NULL;
    1882         1001884 :     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
    1883                 : 
    1884                 :     /* Check for (a = b) and warn about possible (a == b) mistype. */
    1885         1001884 :     JS_ASSERT_IF(pn->isKind(PNK_ASSIGN), pn->isOp(JSOP_NOP));
    1886         1020907 :     if (pn->isKind(PNK_ASSIGN) &&
    1887           10326 :         !pn->isInParens() &&
    1888            8697 :         !reportErrorNumber(NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_EQUAL_AS_ASSIGN))
    1889                 :     {
    1890               0 :         return NULL;
    1891                 :     }
    1892         1001884 :     return pn;
    1893                 : }
    1894                 : 
    1895                 : static bool
    1896           91703 : MatchLabel(JSContext *cx, TokenStream *ts, PropertyName **label)
    1897                 : {
    1898           91703 :     TokenKind tt = ts->peekTokenSameLine(TSF_OPERAND);
    1899           91703 :     if (tt == TOK_ERROR)
    1900               0 :         return false;
    1901           91703 :     if (tt == TOK_NAME) {
    1902             154 :         (void) ts->getToken();
    1903             154 :         *label = ts->currentToken().name();
    1904                 :     } else {
    1905           91549 :         *label = NULL;
    1906                 :     }
    1907           91703 :     return true;
    1908                 : }
    1909                 : 
    1910                 : static bool
    1911             189 : ReportRedeclaration(JSContext *cx, TreeContext *tc, ParseNode *pn, bool isConst, JSAtom *atom)
    1912                 : {
    1913             378 :     JSAutoByteString name;
    1914             189 :     if (js_AtomToPrintableString(cx, atom, &name)) {
    1915                 :         ReportCompileErrorNumber(cx, TS(tc->parser), pn,
    1916                 :                                  JSREPORT_ERROR, JSMSG_REDECLARED_VAR,
    1917                 :                                  isConst ? "const" : "variable",
    1918             189 :                                  name.ptr());
    1919                 :     }
    1920             189 :     return false;
    1921                 : }
    1922                 : 
    1923                 : /*
    1924                 :  * Define a let-variable in a block, let-expression, or comprehension scope. tc
    1925                 :  * must already be in such a scope.
    1926                 :  *
    1927                 :  * Throw a SyntaxError if 'atom' is an invalid name. Otherwise create a
    1928                 :  * property for the new variable on the block object, tc->blockChain;
    1929                 :  * populate data->pn->pn_{op,cookie,defn,dflags}; and stash a pointer to
    1930                 :  * data->pn in a slot of the block object.
    1931                 :  */
    1932                 : static JSBool
    1933          751526 : BindLet(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc)
    1934                 : {
    1935          751526 :     ParseNode *pn = data->pn;
    1936          751526 :     if (!CheckStrictBinding(cx, tc, atom->asPropertyName(), pn))
    1937               0 :         return false;
    1938                 : 
    1939          751526 :     StaticBlockObject &blockObj = *data->let.blockObj;
    1940          751526 :     unsigned blockCount = blockObj.slotCount();
    1941          751526 :     if (blockCount == JS_BIT(16)) {
    1942                 :         ReportCompileErrorNumber(cx, TS(tc->parser), pn,
    1943               0 :                                  JSREPORT_ERROR, data->let.overflow);
    1944               0 :         return false;
    1945                 :     }
    1946                 : 
    1947                 :     /*
    1948                 :      * For bindings that are hoisted to the beginning of the block/function,
    1949                 :      * Define() right now. For the rest, delay Define() until PushLetScope.
    1950                 :      */
    1951          751526 :     if (data->let.varContext == HoistVars) {
    1952          522626 :         JS_ASSERT(!tc->atBodyLevel());
    1953          522626 :         Definition *dn = tc->decls.lookupFirst(atom);
    1954          522626 :         if (dn && dn->pn_blockid == tc->blockid())
    1955              18 :             return ReportRedeclaration(cx, tc, pn, dn->isConst(), atom);
    1956          522608 :         if (!Define(pn, atom, tc, true))
    1957               0 :             return false;
    1958                 :     }
    1959                 : 
    1960                 :     /*
    1961                 :      * Assign block-local index to pn->pn_cookie right away, encoding it as an
    1962                 :      * upvar cookie whose skip tells the current static level. The emitter will
    1963                 :      * adjust the node's slot based on its stack depth model -- and, for global
    1964                 :      * and eval code, js::frontend::CompileScript will adjust the slot
    1965                 :      * again to include script->nfixed.
    1966                 :      */
    1967          751508 :     pn->setOp(JSOP_GETLOCAL);
    1968          751508 :     pn->pn_cookie.set(tc->staticLevel, uint16_t(blockCount));
    1969          751508 :     pn->pn_dflags |= PND_LET | PND_BOUND;
    1970                 : 
    1971                 :     /*
    1972                 :      * Define the let binding's property before storing pn in the the binding's
    1973                 :      * slot indexed by blockCount off the class-reserved slot base.
    1974                 :      */
    1975                 :     bool redeclared;
    1976          751508 :     jsid id = ATOM_TO_JSID(atom);
    1977          751508 :     const Shape *shape = blockObj.addVar(cx, id, blockCount, &redeclared);
    1978          751508 :     if (!shape) {
    1979             171 :         if (redeclared)
    1980             171 :             ReportRedeclaration(cx, tc, pn, false, atom);
    1981             171 :         return false;
    1982                 :     }
    1983                 : 
    1984                 :     /* Store pn in the static block object. */
    1985          751337 :     blockObj.setDefinitionParseNode(blockCount, reinterpret_cast<Definition *>(pn));
    1986          751337 :     return true;
    1987                 : }
    1988                 : 
    1989                 : template <class Op>
    1990                 : static inline bool
    1991          527073 : ForEachLetDef(TreeContext *tc, StaticBlockObject &blockObj, Op op)
    1992                 : {
    1993         1514906 :     for (Shape::Range r = blockObj.lastProperty()->all(); !r.empty(); r.popFront()) {
    1994          987833 :         const Shape &shape = r.front();
    1995                 : 
    1996                 :         /* Beware the destructuring dummy slots. */
    1997          987833 :         if (JSID_IS_INT(shape.propid()))
    1998            8469 :             continue;
    1999                 : 
    2000          979364 :         if (!op(tc, blockObj, shape, JSID_TO_ATOM(shape.propid())))
    2001               0 :             return false;
    2002                 :     }
    2003          527073 :     return true;
    2004                 : }
    2005                 : 
    2006                 : struct RemoveDecl {
    2007          750968 :     bool operator()(TreeContext *tc, StaticBlockObject &, const Shape &, JSAtom *atom) {
    2008          750968 :         tc->decls.remove(atom);
    2009          750968 :         return true;
    2010                 :     }
    2011                 : };
    2012                 : 
    2013                 : static void
    2014         2563556 : PopStatement(TreeContext *tc)
    2015                 : {
    2016         2563556 :     if (tc->topStmt->flags & SIF_SCOPE) {
    2017          448923 :         StaticBlockObject &blockObj = *tc->topStmt->blockObj;
    2018          448923 :         JS_ASSERT(!blockObj.inDictionaryMode());
    2019          448923 :         ForEachLetDef(tc, blockObj, RemoveDecl());
    2020                 :     }
    2021         2563556 :     PopStatementTC(tc);
    2022         2563556 : }
    2023                 : 
    2024                 : static inline bool
    2025               9 : OuterLet(TreeContext *tc, StmtInfo *stmt, JSAtom *atom)
    2026                 : {
    2027              18 :     while (stmt->downScope) {
    2028               0 :         stmt = LexicalLookup(tc, atom, NULL, stmt->downScope);
    2029               0 :         if (!stmt)
    2030               0 :             return false;
    2031               0 :         if (stmt->type == STMT_BLOCK)
    2032               0 :             return true;
    2033                 :     }
    2034               9 :     return false;
    2035                 : }
    2036                 : 
    2037                 : /*
    2038                 :  * If we are generating global or eval-called-from-global code, bind a "gvar"
    2039                 :  * here, as soon as possible. The JSOP_GETGVAR, etc., ops speed up interpreted
    2040                 :  * global variable access by memoizing name-to-slot mappings during execution
    2041                 :  * of the script prolog (via JSOP_DEFVAR/JSOP_DEFCONST). If the memoization
    2042                 :  * can't be done due to a pre-existing property of the same name as the var or
    2043                 :  * const but incompatible attributes/getter/setter/etc, these ops devolve to
    2044                 :  * JSOP_NAME, etc.
    2045                 :  *
    2046                 :  * For now, don't try to lookup eval frame variables at compile time. This is
    2047                 :  * sub-optimal: we could handle eval-called-from-global-code gvars since eval
    2048                 :  * gets its own script and frame. The eval-from-function-code case is harder,
    2049                 :  * since functions do not atomize gvars and then reserve their atom indexes as
    2050                 :  * stack frame slots.
    2051                 :  */
    2052                 : static bool
    2053          347098 : DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name)
    2054                 : {
    2055          347098 :     GlobalScope *globalScope = bce->globalScope;
    2056          347098 :     JSObject *globalObj = globalScope->globalObj;
    2057                 : 
    2058          347098 :     if (!bce->compileAndGo() || !globalObj || bce->compilingForEval())
    2059          278929 :         return true;
    2060                 : 
    2061           68169 :     AtomIndexAddPtr p = globalScope->names.lookupForAdd(name);
    2062           68169 :     if (!p) {
    2063           68124 :         JSContext *cx = bce->parser->context;
    2064                 : 
    2065                 :         JSObject *holder;
    2066                 :         JSProperty *prop;
    2067           68124 :         if (!globalObj->lookupProperty(cx, name, &holder, &prop))
    2068               0 :             return false;
    2069                 : 
    2070           68124 :         FunctionBox *funbox = pn->isKind(PNK_FUNCTION) ? pn->pn_funbox : NULL;
    2071                 : 
    2072           68124 :         GlobalScope::GlobalDef def;
    2073           68124 :         if (prop) {
    2074                 :             /*
    2075                 :              * A few cases where we don't bother aggressively caching:
    2076                 :              *   1) Function value changes.
    2077                 :              *   2) Configurable properties.
    2078                 :              *   3) Properties without slots, or with getters/setters.
    2079                 :              */
    2080             222 :             const Shape *shape = (const Shape *)prop;
    2081             459 :             if (funbox ||
    2082                 :                 globalObj != holder ||
    2083             120 :                 shape->configurable() ||
    2084              39 :                 !shape->hasSlot() ||
    2085              39 :                 !shape->hasDefaultGetterOrIsMethod() ||
    2086              39 :                 !shape->hasDefaultSetter()) {
    2087             183 :                 return true;
    2088                 :             }
    2089                 : 
    2090              39 :             def = GlobalScope::GlobalDef(shape->slot());
    2091                 :         } else {
    2092           67902 :             def = GlobalScope::GlobalDef(name, funbox);
    2093                 :         }
    2094                 : 
    2095           67941 :         if (!globalScope->defs.append(def))
    2096               0 :             return false;
    2097                 : 
    2098           67941 :         jsatomid index = globalScope->names.count();
    2099           67941 :         if (!globalScope->names.add(p, name, index))
    2100               0 :             return false;
    2101                 : 
    2102           67941 :         JS_ASSERT(index == globalScope->defs.length() - 1);
    2103                 :     } else {
    2104                 :         /*
    2105                 :          * Functions can be redeclared, and the last one takes effect. Check
    2106                 :          * for this and make sure to rewrite the definition.
    2107                 :          *
    2108                 :          * Note: This could overwrite an existing variable declaration, for
    2109                 :          * example:
    2110                 :          *   var c = []
    2111                 :          *   function c() { }
    2112                 :          *
    2113                 :          * This rewrite is allowed because the function will be statically
    2114                 :          * hoisted to the top of the script, and the |c = []| will just
    2115                 :          * overwrite it at runtime.
    2116                 :          */
    2117              45 :         if (pn->isKind(PNK_FUNCTION)) {
    2118              45 :             JS_ASSERT(pn->isArity(PN_FUNC));
    2119              45 :             jsatomid index = p.value();
    2120              45 :             globalScope->defs[index].funbox = pn->pn_funbox;
    2121                 :         }
    2122                 :     }
    2123                 : 
    2124           67986 :     pn->pn_dflags |= PND_GVAR;
    2125                 : 
    2126           67986 :     return true;
    2127                 : }
    2128                 : 
    2129                 : static bool
    2130          312259 : BindTopLevelVar(JSContext *cx, BindData *data, ParseNode *pn, TreeContext *tc)
    2131                 : {
    2132          312259 :     JS_ASSERT(pn->isOp(JSOP_NAME));
    2133          312259 :     JS_ASSERT(!tc->inFunction());
    2134                 : 
    2135                 :     /* There's no need to optimize bindings if we're not compiling code. */
    2136          312259 :     if (!tc->compiling())
    2137               9 :         return true;
    2138                 : 
    2139                 :     /*
    2140                 :      * Bindings at top level in eval code aren't like bindings at top level in
    2141                 :      * regular code, and we must handle them specially.
    2142                 :      */
    2143          312250 :     if (tc->parser->callerFrame) {
    2144                 :         /*
    2145                 :          * If the eval code is not strict mode code, such bindings are created
    2146                 :          * from scratch in the the caller's environment (if the eval is direct)
    2147                 :          * or in the global environment (if the eval is indirect) -- and they
    2148                 :          * can be deleted.  Therefore we can't bind early.
    2149                 :          */
    2150             675 :         if (!tc->inStrictMode())
    2151             531 :             return true;
    2152                 : 
    2153                 :         /*
    2154                 :          * But if the eval code is strict mode code, bindings are added to a
    2155                 :          * new environment specifically for that eval code's compilation, and
    2156                 :          * they can't be deleted.  Thus strict mode eval code does not affect
    2157                 :          * the caller's environment, and we can bind such names early.  (But
    2158                 :          * note: strict mode eval code can still affect the global environment
    2159                 :          * by performing an indirect eval of non-strict mode code.)
    2160                 :          *
    2161                 :          * However, optimizing such bindings requires either precarious
    2162                 :          * type-punning or, ideally, a new kind of Call object specifically for
    2163                 :          * strict mode eval frames.  Further, strict mode eval is not (yet)
    2164                 :          * common.  So for now (until we rewrite the scope chain to not use
    2165                 :          * objects?) just disable optimizations for top-level names in eval
    2166                 :          * code.
    2167                 :          */
    2168             144 :         return true;
    2169                 :     }
    2170                 : 
    2171          311575 :     if (pn->pn_dflags & PND_CONST)
    2172          150073 :         return true;
    2173                 : 
    2174                 :     /*
    2175                 :      * If this is a global variable, we're compile-and-go, and a global object
    2176                 :      * is present, try to bake in either an already available slot or a
    2177                 :      * predicted slot that will be defined after compiling is completed.
    2178                 :      */
    2179          161502 :     return DefineGlobal(pn, tc->asBytecodeEmitter(), pn->pn_atom->asPropertyName());
    2180                 : }
    2181                 : 
    2182                 : static bool
    2183          809006 : BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, TreeContext *tc)
    2184                 : {
    2185          809006 :     JS_ASSERT(tc->inFunction());
    2186                 : 
    2187          809006 :     ParseNode *pn = data->pn;
    2188          809006 :     JSAtom *name = pn->pn_atom;
    2189                 : 
    2190                 :     /*
    2191                 :      * Don't create a local variable with the name 'arguments', per ECMA-262.
    2192                 :      * Instead, 'var arguments' always restates that predefined binding of the
    2193                 :      * lexical environment for function activations. Assignments to arguments
    2194                 :      * must be handled specially -- see NoteLValue.
    2195                 :      */
    2196          809006 :     if (name == cx->runtime->atomState.argumentsAtom) {
    2197              27 :         pn->setOp(JSOP_ARGUMENTS);
    2198              27 :         pn->pn_dflags |= PND_BOUND;
    2199              27 :         return true;
    2200                 :     }
    2201                 : 
    2202          808979 :     BindingKind kind = tc->bindings.lookup(cx, name, NULL);
    2203          808979 :     if (kind == NONE) {
    2204                 :         /*
    2205                 :          * Property not found in current variable scope: we have not seen this
    2206                 :          * variable before, so bind a new local variable for it. Any locals
    2207                 :          * declared in a with statement body are handled at runtime, by script
    2208                 :          * prolog JSOP_DEFVAR opcodes generated for global and heavyweight-
    2209                 :          * function-local vars.
    2210                 :          */
    2211          808979 :         kind = (data->op == JSOP_DEFCONST) ? CONSTANT : VARIABLE;
    2212                 : 
    2213          808979 :         if (!BindLocalVariable(cx, tc, pn, kind))
    2214               0 :             return false;
    2215          808979 :         pn->setOp(JSOP_GETLOCAL);
    2216          808979 :         return true;
    2217                 :     }
    2218                 : 
    2219               0 :     if (kind == ARGUMENT) {
    2220               0 :         JS_ASSERT(tc->inFunction());
    2221               0 :         JS_ASSERT(!mdl.empty() && mdl.front()->kind() == Definition::ARG);
    2222                 :     } else {
    2223               0 :         JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
    2224                 :     }
    2225                 : 
    2226               0 :     return true;
    2227                 : }
    2228                 : 
    2229                 : static JSBool
    2230         1130250 : BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc)
    2231                 : {
    2232         1130250 :     ParseNode *pn = data->pn;
    2233                 : 
    2234                 :     /* Default best op for pn is JSOP_NAME; we'll try to improve below. */
    2235         1130250 :     pn->setOp(JSOP_NAME);
    2236                 : 
    2237         1130250 :     if (!CheckStrictBinding(cx, tc, atom->asPropertyName(), pn))
    2238               0 :         return false;
    2239                 : 
    2240         1130250 :     StmtInfo *stmt = LexicalLookup(tc, atom, NULL);
    2241                 : 
    2242         1130250 :     if (stmt && stmt->type == STMT_WITH) {
    2243              81 :         data->fresh = false;
    2244              81 :         pn->pn_dflags |= PND_DEOPTIMIZED;
    2245              81 :         tc->noteMightAliasLocals();
    2246              81 :         return true;
    2247                 :     }
    2248                 : 
    2249         1130169 :     MultiDeclRange mdl = tc->decls.lookupMulti(atom);
    2250         1130169 :     JSOp op = data->op;
    2251                 : 
    2252         1130169 :     if (stmt || !mdl.empty()) {
    2253            8904 :         Definition *dn = mdl.empty() ? NULL : mdl.front();
    2254            8904 :         Definition::Kind dn_kind = dn ? dn->kind() : Definition::VAR;
    2255                 : 
    2256            8904 :         if (dn_kind == Definition::ARG) {
    2257            1512 :             JSAutoByteString name;
    2258             756 :             if (!js_AtomToPrintableString(cx, atom, &name))
    2259               0 :                 return JS_FALSE;
    2260                 : 
    2261             756 :             if (op == JSOP_DEFCONST) {
    2262                 :                 ReportCompileErrorNumber(cx, TS(tc->parser), pn,
    2263                 :                                          JSREPORT_ERROR, JSMSG_REDECLARED_PARAM,
    2264               0 :                                          name.ptr());
    2265               0 :                 return JS_FALSE;
    2266                 :             }
    2267             756 :             if (!ReportCompileErrorNumber(cx, TS(tc->parser), pn,
    2268                 :                                           JSREPORT_WARNING | JSREPORT_STRICT,
    2269             756 :                                           JSMSG_VAR_HIDES_ARG, name.ptr())) {
    2270               0 :                 return JS_FALSE;
    2271                 :             }
    2272                 :         } else {
    2273                 :             bool error = (op == JSOP_DEFCONST ||
    2274                 :                           dn_kind == Definition::CONST ||
    2275                 :                           (dn_kind == Definition::LET &&
    2276            8148 :                            (stmt->type != STMT_CATCH || OuterLet(tc, stmt, atom))));
    2277                 : 
    2278            8148 :             if (cx->hasStrictOption()
    2279                 :                 ? op != JSOP_DEFVAR || dn_kind != Definition::VAR
    2280                 :                 : error) {
    2281               0 :                 JSAutoByteString name;
    2282               0 :                 if (!js_AtomToPrintableString(cx, atom, &name) ||
    2283                 :                     !ReportCompileErrorNumber(cx, TS(tc->parser), pn,
    2284               0 :                                               !error
    2285                 :                                               ? JSREPORT_WARNING | JSREPORT_STRICT
    2286                 :                                               : JSREPORT_ERROR,
    2287                 :                                               JSMSG_REDECLARED_VAR,
    2288                 :                                               Definition::kindString(dn_kind),
    2289               0 :                                               name.ptr())) {
    2290               0 :                     return JS_FALSE;
    2291                 :                 }
    2292                 :             }
    2293                 :         }
    2294                 :     }
    2295                 : 
    2296         1130169 :     if (mdl.empty()) {
    2297         1121265 :         if (!Define(pn, atom, tc))
    2298               0 :             return JS_FALSE;
    2299                 :     } else {
    2300                 :         /*
    2301                 :          * A var declaration never recreates an existing binding, it restates
    2302                 :          * it and possibly reinitializes its value. Beware that if pn becomes a
    2303                 :          * use of |mdl.defn()|, and if we have an initializer for this var or
    2304                 :          * const (typically a const would ;-), then pn must be rewritten into a
    2305                 :          * PNK_ASSIGN node. See js::Parser::variables, further below.
    2306                 :          *
    2307                 :          * A case such as let (x = 1) { var x = 2; print(x); } is even harder.
    2308                 :          * There the x definition is hoisted but the x = 2 assignment mutates
    2309                 :          * the block-local binding of x.
    2310                 :          */
    2311            8904 :         Definition *dn = mdl.front();
    2312                 : 
    2313            8904 :         data->fresh = false;
    2314                 : 
    2315            8904 :         if (!pn->isUsed()) {
    2316                 :             /* Make pnu be a fresh name node that uses dn. */
    2317            8904 :             ParseNode *pnu = pn;
    2318                 : 
    2319            8904 :             if (pn->isDefn()) {
    2320               0 :                 pnu = NameNode::create(PNK_NAME, atom, tc);
    2321               0 :                 if (!pnu)
    2322               0 :                     return JS_FALSE;
    2323                 :             }
    2324                 : 
    2325            8904 :             LinkUseToDef(pnu, dn, tc);
    2326            8904 :             pnu->setOp(JSOP_NAME);
    2327                 :         }
    2328                 : 
    2329                 :         /* Find the first non-let binding of this atom. */
    2330           17808 :         while (dn->kind() == Definition::LET) {
    2331               9 :             mdl.popFront();
    2332               9 :             if (mdl.empty())
    2333               9 :                 break;
    2334               0 :             dn = mdl.front();
    2335                 :         }
    2336                 : 
    2337            8904 :         if (dn) {
    2338               0 :             JS_ASSERT_IF(data->op == JSOP_DEFCONST,
    2339            8904 :                          dn->kind() == Definition::CONST);
    2340            8904 :             return JS_TRUE;
    2341                 :         }
    2342                 : 
    2343                 :         /*
    2344                 :          * A var or const that is shadowed by one or more let bindings of the
    2345                 :          * same name, but that has not been declared until this point, must be
    2346                 :          * hoisted above the let bindings.
    2347                 :          */
    2348               0 :         if (!pn->isDefn()) {
    2349               0 :             if (tc->lexdeps->lookup(atom)) {
    2350               0 :                 tc->lexdeps->remove(atom);
    2351                 :             } else {
    2352               0 :                 ParseNode *pn2 = NameNode::create(PNK_NAME, atom, tc);
    2353               0 :                 if (!pn2)
    2354               0 :                     return JS_FALSE;
    2355                 : 
    2356                 :                 /* The token stream may be past the location for pn. */
    2357               0 :                 pn2->pn_pos = pn->pn_pos;
    2358               0 :                 pn = pn2;
    2359                 :             }
    2360               0 :             pn->setOp(JSOP_NAME);
    2361                 :         }
    2362                 : 
    2363               0 :         if (!tc->decls.addHoist(atom, (Definition *) pn))
    2364               0 :             return JS_FALSE;
    2365               0 :         pn->setDefn(true);
    2366               0 :         pn->pn_dflags &= ~PND_PLACEHOLDER;
    2367                 :     }
    2368                 : 
    2369         1121265 :     if (data->op == JSOP_DEFCONST)
    2370          168768 :         pn->pn_dflags |= PND_CONST;
    2371                 : 
    2372         1121265 :     if (tc->inFunction())
    2373          809006 :         return BindFunctionLocal(cx, data, mdl, tc);
    2374                 : 
    2375          312259 :     return BindTopLevelVar(cx, data, pn, tc);
    2376                 : }
    2377                 : 
    2378                 : static bool
    2379              27 : MakeSetCall(JSContext *cx, ParseNode *pn, TreeContext *tc, unsigned msg)
    2380                 : {
    2381              27 :     JS_ASSERT(pn->isArity(PN_LIST));
    2382              27 :     JS_ASSERT(pn->isOp(JSOP_CALL) || pn->isOp(JSOP_EVAL) ||
    2383              27 :               pn->isOp(JSOP_FUNCALL) || pn->isOp(JSOP_FUNAPPLY));
    2384              27 :     if (!ReportStrictModeError(cx, TS(tc->parser), tc, pn, msg))
    2385               0 :         return false;
    2386                 : 
    2387              27 :     ParseNode *pn2 = pn->pn_head;
    2388              27 :     if (pn2->isKind(PNK_FUNCTION) && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) {
    2389               0 :         ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR, msg);
    2390               0 :         return false;
    2391                 :     }
    2392              27 :     pn->pn_xflags |= PNX_SETCALL;
    2393              27 :     return true;
    2394                 : }
    2395                 : 
    2396                 : static void
    2397         2073061 : NoteLValue(JSContext *cx, ParseNode *pn, TreeContext *tc, unsigned dflag = PND_ASSIGNED)
    2398                 : {
    2399         2073061 :     if (pn->isUsed()) {
    2400          805392 :         Definition *dn = pn->pn_lexdef;
    2401                 : 
    2402                 :         /*
    2403                 :          * Save the win of PND_INITIALIZED if we can prove 'var x;' and 'x = y'
    2404                 :          * occur as direct kids of the same block with no forward refs to x.
    2405                 :          */
    2406          958911 :         if (!(dn->pn_dflags & (PND_INITIALIZED | PND_CONST | PND_PLACEHOLDER)) &&
    2407           94619 :             dn->isBlockChild() &&
    2408           54153 :             pn->isBlockChild() &&
    2409                 :             dn->pn_blockid == pn->pn_blockid &&
    2410            4747 :             dn->pn_pos.end <= pn->pn_pos.begin &&
    2411                 :             dn->dn_uses == pn) {
    2412            4729 :             dflag = PND_INITIALIZED;
    2413                 :         }
    2414                 : 
    2415          805392 :         dn->pn_dflags |= dflag;
    2416                 : 
    2417          805392 :         if (dn->pn_cookie.isFree() || dn->frameLevel() < tc->staticLevel)
    2418          163117 :             tc->flags |= TCF_FUN_SETS_OUTER_NAME;
    2419                 :     }
    2420                 : 
    2421         2073061 :     pn->pn_dflags |= dflag;
    2422                 : 
    2423                 :     /*
    2424                 :      * Both arguments and the enclosing function's name are immutable bindings
    2425                 :      * in ES5, so assignments to them must do nothing or throw a TypeError
    2426                 :      * depending on code strictness.  Assignment to arguments is a syntax error
    2427                 :      * in strict mode and thus cannot happen.  Outside strict mode, we optimize
    2428                 :      * away assignment to the function name.  For assignment to function name
    2429                 :      * to fail in strict mode, we must have a binding for it in the scope
    2430                 :      * chain; we ensure this happens by making such functions heavyweight.
    2431                 :      */
    2432         2073061 :     JSAtom *lname = pn->pn_atom;
    2433         2073061 :     if (lname == cx->runtime->atomState.argumentsAtom) {
    2434              63 :         tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
    2435              63 :         tc->countArgumentsUse(pn);
    2436         2072998 :     } else if (tc->inFunction() && lname == tc->fun()->atom) {
    2437             208 :         tc->flags |= TCF_FUN_HEAVYWEIGHT;
    2438                 :     }
    2439         2073061 : }
    2440                 : 
    2441                 : #if JS_HAS_DESTRUCTURING
    2442                 : 
    2443                 : static JSBool
    2444           28473 : BindDestructuringVar(JSContext *cx, BindData *data, ParseNode *pn, TreeContext *tc)
    2445                 : {
    2446                 :     JSAtom *atom;
    2447                 : 
    2448                 :     /*
    2449                 :      * Destructuring is a form of assignment, so just as for an initialized
    2450                 :      * simple variable, we must check for assignment to 'arguments' and flag
    2451                 :      * the enclosing function (if any) as heavyweight.
    2452                 :      */
    2453           28473 :     JS_ASSERT(pn->isKind(PNK_NAME));
    2454           28473 :     atom = pn->pn_atom;
    2455           28473 :     if (atom == cx->runtime->atomState.argumentsAtom)
    2456               0 :         tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
    2457                 : 
    2458           28473 :     data->pn = pn;
    2459           28473 :     if (!data->binder(cx, data, atom, tc))
    2460             135 :         return JS_FALSE;
    2461                 : 
    2462                 :     /*
    2463                 :      * Select the appropriate name-setting opcode, respecting eager selection
    2464                 :      * done by the data->binder function.
    2465                 :      */
    2466           28338 :     if (pn->pn_dflags & PND_BOUND) {
    2467           27562 :         JS_ASSERT(!(pn->pn_dflags & PND_GVAR));
    2468           27562 :         pn->setOp(pn->isOp(JSOP_ARGUMENTS) ? JSOP_SETNAME : JSOP_SETLOCAL);
    2469                 :     } else {
    2470             776 :         pn->setOp((data->op == JSOP_DEFCONST) ? JSOP_SETCONST : JSOP_SETNAME);
    2471                 :     }
    2472                 : 
    2473           28338 :     if (data->op == JSOP_DEFCONST)
    2474              13 :         pn->pn_dflags |= PND_CONST;
    2475                 : 
    2476           28338 :     NoteLValue(cx, pn, tc, PND_INITIALIZED);
    2477           28338 :     return JS_TRUE;
    2478                 : }
    2479                 : 
    2480                 : /*
    2481                 :  * Here, we are destructuring {... P: Q, ...} = R, where P is any id, Q is any
    2482                 :  * LHS expression except a destructuring initialiser, and R is on the stack.
    2483                 :  * Because R is already evaluated, the usual LHS-specialized bytecodes won't
    2484                 :  * work.  After pushing R[P] we need to evaluate Q's "reference base" QB and
    2485                 :  * then push its property name QN.  At this point the stack looks like
    2486                 :  *
    2487                 :  *   [... R, R[P], QB, QN]
    2488                 :  *
    2489                 :  * We need to set QB[QN] = R[P].  This is a job for JSOP_ENUMELEM, which takes
    2490                 :  * its operands with left-hand side above right-hand side:
    2491                 :  *
    2492                 :  *   [rval, lval, xval]
    2493                 :  *
    2494                 :  * and pops all three values, setting lval[xval] = rval.  But we cannot select
    2495                 :  * JSOP_ENUMELEM yet, because the LHS may turn out to be an arg or local var,
    2496                 :  * which can be optimized further.  So we select JSOP_SETNAME.
    2497                 :  */
    2498                 : static JSBool
    2499            4636 : BindDestructuringLHS(JSContext *cx, ParseNode *pn, TreeContext *tc)
    2500                 : {
    2501            4636 :     switch (pn->getKind()) {
    2502                 :       case PNK_NAME:
    2503            4510 :         NoteLValue(cx, pn, tc);
    2504                 :         /* FALL THROUGH */
    2505                 : 
    2506                 :       case PNK_DOT:
    2507                 :       case PNK_LB:
    2508                 :         /*
    2509                 :          * We may be called on a name node that has already been specialized,
    2510                 :          * in the very weird and ECMA-262-required "for (var [x] = i in o) ..."
    2511                 :          * case. See bug 558633.
    2512                 :          */
    2513            4636 :         if (!(js_CodeSpec[pn->getOp()].format & JOF_SET))
    2514            4636 :             pn->setOp(JSOP_SETNAME);
    2515            4636 :         break;
    2516                 : 
    2517                 :       case PNK_LP:
    2518               0 :         if (!MakeSetCall(cx, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS))
    2519               0 :             return JS_FALSE;
    2520               0 :         break;
    2521                 : 
    2522                 : #if JS_HAS_XML_SUPPORT
    2523                 :       case PNK_XMLUNARY:
    2524               0 :         JS_ASSERT(pn->isOp(JSOP_XMLNAME));
    2525               0 :         pn->setOp(JSOP_BINDXMLNAME);
    2526               0 :         break;
    2527                 : #endif
    2528                 : 
    2529                 :       default:
    2530                 :         ReportCompileErrorNumber(cx, TS(tc->parser), pn,
    2531               0 :                                  JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS);
    2532               0 :         return JS_FALSE;
    2533                 :     }
    2534                 : 
    2535            4636 :     return JS_TRUE;
    2536                 : }
    2537                 : 
    2538                 : /*
    2539                 :  * Destructuring patterns can appear in two kinds of contexts:
    2540                 :  *
    2541                 :  * - assignment-like: assignment expressions and |for| loop heads.  In
    2542                 :  *   these cases, the patterns' property value positions can be
    2543                 :  *   arbitrary lvalue expressions; the destructuring is just a fancy
    2544                 :  *   assignment.
    2545                 :  *
    2546                 :  * - declaration-like: |var| and |let| declarations, functions' formal
    2547                 :  *   parameter lists, |catch| clauses, and comprehension tails.  In
    2548                 :  *   these cases, the patterns' property value positions must be
    2549                 :  *   simple names; the destructuring defines them as new variables.
    2550                 :  *
    2551                 :  * In both cases, other code parses the pattern as an arbitrary
    2552                 :  * primaryExpr, and then, here in CheckDestructuring, verify that the
    2553                 :  * tree is a valid destructuring expression.
    2554                 :  *
    2555                 :  * In assignment-like contexts, we parse the pattern with the
    2556                 :  * TCF_DECL_DESTRUCTURING flag clear, so the lvalue expressions in the
    2557                 :  * pattern are parsed normally.  primaryExpr links variable references
    2558                 :  * into the appropriate use chains; creates placeholder definitions;
    2559                 :  * and so on.  CheckDestructuring is called with |data| NULL (since we
    2560                 :  * won't be binding any new names), and we specialize lvalues as
    2561                 :  * appropriate.
    2562                 :  *
    2563                 :  * In declaration-like contexts, the normal variable reference
    2564                 :  * processing would just be an obstruction, because we're going to
    2565                 :  * define the names that appear in the property value positions as new
    2566                 :  * variables anyway.  In this case, we parse the pattern with
    2567                 :  * TCF_DECL_DESTRUCTURING set, which directs primaryExpr to leave
    2568                 :  * whatever name nodes it creates unconnected.  Then, here in
    2569                 :  * CheckDestructuring, we require the pattern's property value
    2570                 :  * positions to be simple names, and define them as appropriate to the
    2571                 :  * context.  For these calls, |data| points to the right sort of
    2572                 :  * BindData.
    2573                 :  *
    2574                 :  * See also UndominateInitializers, immediately below. If you change
    2575                 :  * either of these functions, you might have to change the other to
    2576                 :  * match.
    2577                 :  *
    2578                 :  * The 'toplevel' is a private detail of the recursive strategy used by
    2579                 :  * CheckDestructuring and callers should use the default value.
    2580                 :  */
    2581                 : static bool
    2582           25438 : CheckDestructuring(JSContext *cx, BindData *data, ParseNode *left, TreeContext *tc,
    2583                 :                    bool toplevel = true)
    2584                 : {
    2585                 :     bool ok;
    2586                 : 
    2587           25438 :     if (left->isKind(PNK_ARRAYCOMP)) {
    2588                 :         ReportCompileErrorNumber(cx, TS(tc->parser), left, JSREPORT_ERROR,
    2589               0 :                                  JSMSG_ARRAY_COMP_LEFTSIDE);
    2590               0 :         return false;
    2591                 :     }
    2592                 : 
    2593           25438 :     StaticBlockObject *blockObj = data && data->binder == BindLet ? data->let.blockObj : NULL;
    2594           25438 :     uint32_t blockCountBefore = blockObj ? blockObj->slotCount() : 0;
    2595                 : 
    2596           25438 :     if (left->isKind(PNK_RB)) {
    2597           59729 :         for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
    2598                 :             /* Nullary comma is an elision; binary comma is an expression.*/
    2599           36289 :             if (!pn->isArrayHole()) {
    2600           35247 :                 if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC)) {
    2601            3903 :                     ok = CheckDestructuring(cx, data, pn, tc, false);
    2602                 :                 } else {
    2603           31344 :                     if (data) {
    2604           26852 :                         if (!pn->isKind(PNK_NAME)) {
    2605                 :                             ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR,
    2606               0 :                                                      JSMSG_NO_VARIABLE_NAME);
    2607               0 :                             return false;
    2608                 :                         }
    2609           26852 :                         ok = BindDestructuringVar(cx, data, pn, tc);
    2610                 :                     } else {
    2611            4492 :                         ok = BindDestructuringLHS(cx, pn, tc);
    2612                 :                     }
    2613                 :                 }
    2614           35247 :                 if (!ok)
    2615             189 :                     return false;
    2616                 :             }
    2617                 :         }
    2618                 :     } else {
    2619            1809 :         JS_ASSERT(left->isKind(PNK_RC));
    2620            4474 :         for (ParseNode *pair = left->pn_head; pair; pair = pair->pn_next) {
    2621            2728 :             JS_ASSERT(pair->isKind(PNK_COLON));
    2622            2728 :             ParseNode *pn = pair->pn_right;
    2623                 : 
    2624            2728 :             if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC)) {
    2625             936 :                 ok = CheckDestructuring(cx, data, pn, tc, false);
    2626            1792 :             } else if (data) {
    2627            1648 :                 if (!pn->isKind(PNK_NAME)) {
    2628                 :                     ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR,
    2629              27 :                                              JSMSG_NO_VARIABLE_NAME);
    2630              27 :                     return false;
    2631                 :                 }
    2632            1621 :                 ok = BindDestructuringVar(cx, data, pn, tc);
    2633                 :             } else {
    2634             144 :                 ok = BindDestructuringLHS(cx, pn, tc);
    2635                 :             }
    2636            2701 :             if (!ok)
    2637              36 :                 return false;
    2638                 :         }
    2639                 :     }
    2640                 : 
    2641                 :     /*
    2642                 :      * The catch/finally handler implementation in the interpreter assumes
    2643                 :      * that any operation that introduces a new scope (like a "let" or "with"
    2644                 :      * block) increases the stack depth. This way, it is possible to restore
    2645                 :      * the scope chain based on stack depth of the handler alone. "let" with
    2646                 :      * an empty destructuring pattern like in
    2647                 :      *
    2648                 :      *   let [] = 1;
    2649                 :      *
    2650                 :      * would violate this assumption as the there would be no let locals to
    2651                 :      * store on the stack.
    2652                 :      *
    2653                 :      * Furthermore, the decompiler needs an abstract stack location to store
    2654                 :      * the decompilation of each let block/expr initializer. E.g., given:
    2655                 :      *
    2656                 :      *   let (x = 1, [[]] = b, y = 3, {a:[]} = c) { ... }
    2657                 :      *
    2658                 :      * four slots are needed.
    2659                 :      *
    2660                 :      * To satisfy both constraints, we push a dummy slot (and add a
    2661                 :      * corresponding dummy property to the block object) for each initializer
    2662                 :      * that doesn't introduce at least one binding.
    2663                 :      */
    2664           25186 :     if (toplevel && blockObj && blockCountBefore == blockObj->slotCount()) {
    2665                 :         bool redeclared;
    2666            4428 :         if (!blockObj->addVar(cx, INT_TO_JSID(blockCountBefore), blockCountBefore, &redeclared))
    2667               0 :             return false;
    2668            4428 :         JS_ASSERT(!redeclared);
    2669            4428 :         JS_ASSERT(blockObj->slotCount() == blockCountBefore + 1);
    2670                 :     }
    2671                 : 
    2672           25186 :     return true;
    2673                 : }
    2674                 : 
    2675                 : /*
    2676                 :  * Extend the pn_pos.end source coordinate of each name in a destructuring
    2677                 :  * binding such as
    2678                 :  *
    2679                 :  *   var [x, y] = [function () y, 42];
    2680                 :  *
    2681                 :  * to cover the entire initializer, so that the initialized bindings do not
    2682                 :  * appear to dominate any closures in the initializer. See bug 496134.
    2683                 :  *
    2684                 :  * The quick-and-dirty dominance computation in Parser::setFunctionKinds is not
    2685                 :  * very precise. With one-pass SSA construction from structured source code
    2686                 :  * (see "Single-Pass Generation of Static Single Assignment Form for Structured
    2687                 :  * Languages", Brandis and Mössenböck), we could do much better.
    2688                 :  *
    2689                 :  * See CheckDestructuring, immediately above. If you change either of these
    2690                 :  * functions, you might have to change the other to match.
    2691                 :  */
    2692                 : static void
    2693           17713 : UndominateInitializers(ParseNode *left, const TokenPtr &end, TreeContext *tc)
    2694                 : {
    2695           17713 :     if (left->isKind(PNK_RB)) {
    2696           36654 :         for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
    2697                 :             /* Nullary comma is an elision; binary comma is an expression.*/
    2698           20397 :             if (!pn->isKind(PNK_COMMA) || !pn->isArity(PN_NULLARY)) {
    2699           19366 :                 if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC))
    2700            3642 :                     UndominateInitializers(pn, end, tc);
    2701                 :                 else
    2702           15724 :                     pn->pn_pos.end = end;
    2703                 :             }
    2704                 :         }
    2705                 :     } else {
    2706            1456 :         JS_ASSERT(left->isKind(PNK_RC));
    2707                 : 
    2708            3622 :         for (ParseNode *pair = left->pn_head; pair; pair = pair->pn_next) {
    2709            2166 :             JS_ASSERT(pair->isKind(PNK_COLON));
    2710            2166 :             ParseNode *pn = pair->pn_right;
    2711            2166 :             if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC))
    2712             918 :                 UndominateInitializers(pn, end, tc);
    2713                 :             else
    2714            1248 :                 pn->pn_pos.end = end;
    2715                 :         }
    2716                 :     }
    2717           17713 : }
    2718                 : 
    2719                 : ParseNode *
    2720            1556 : Parser::destructuringExpr(BindData *data, TokenKind tt)
    2721                 : {
    2722            1556 :     JS_ASSERT(tokenStream.isCurrentTokenType(tt));
    2723                 : 
    2724            1556 :     tc->flags |= TCF_DECL_DESTRUCTURING;
    2725            1556 :     ParseNode *pn = primaryExpr(tt, JS_FALSE);
    2726            1556 :     tc->flags &= ~TCF_DECL_DESTRUCTURING;
    2727            1556 :     if (!pn)
    2728               0 :         return NULL;
    2729            1556 :     if (!CheckDestructuring(context, data, pn, tc))
    2730               0 :         return NULL;
    2731            1556 :     return pn;
    2732                 : }
    2733                 : 
    2734                 : #endif /* JS_HAS_DESTRUCTURING */
    2735                 : 
    2736                 : ParseNode *
    2737          637930 : Parser::returnOrYield(bool useAssignExpr)
    2738                 : {
    2739          637930 :     TokenKind tt = tokenStream.currentToken().type;
    2740          637930 :     if (!tc->inFunction()) {
    2741                 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN_OR_YIELD,
    2742               0 :                           (tt == TOK_RETURN) ? js_return_str : js_yield_str);
    2743               0 :         return NULL;
    2744                 :     }
    2745                 : 
    2746          637930 :     ParseNode *pn = UnaryNode::create((tt == TOK_RETURN) ? PNK_RETURN : PNK_YIELD, tc);
    2747          637930 :     if (!pn)
    2748               0 :         return NULL;
    2749                 : 
    2750                 : #if JS_HAS_GENERATORS
    2751          637930 :     if (tt == TOK_YIELD) {
    2752                 :         /*
    2753                 :          * If we're within parens, we won't know if this is a generator expression until we see
    2754                 :          * a |for| token, so we have to delay flagging the current function.
    2755                 :          */
    2756            4206 :         if (tc->parenDepth == 0) {
    2757            4206 :             tc->flags |= TCF_FUN_IS_GENERATOR;
    2758                 :         } else {
    2759               0 :             tc->yieldCount++;
    2760               0 :             tc->yieldNode = pn;
    2761                 :         }
    2762                 :     }
    2763                 : #endif
    2764                 : 
    2765                 :     /* This is ugly, but we don't want to require a semicolon. */
    2766          637930 :     TokenKind tt2 = tokenStream.peekTokenSameLine(TSF_OPERAND);
    2767          637930 :     if (tt2 == TOK_ERROR)
    2768               0 :         return NULL;
    2769                 : 
    2770          637930 :     if (tt2 != TOK_EOF && tt2 != TOK_EOL && tt2 != TOK_SEMI && tt2 != TOK_RC
    2771                 : #if JS_HAS_GENERATORS
    2772                 :         && (tt != TOK_YIELD ||
    2773                 :             (tt2 != tt && tt2 != TOK_RB && tt2 != TOK_RP &&
    2774                 :              tt2 != TOK_COLON && tt2 != TOK_COMMA))
    2775                 : #endif
    2776                 :         )
    2777                 :     {
    2778          525101 :         ParseNode *pn2 = useAssignExpr ? assignExpr() : expr();
    2779          525101 :         if (!pn2)
    2780               0 :             return NULL;
    2781                 : #if JS_HAS_GENERATORS
    2782          525101 :         if (tt == TOK_RETURN)
    2783                 : #endif
    2784          521676 :             tc->flags |= TCF_RETURN_EXPR;
    2785          525101 :         pn->pn_pos.end = pn2->pn_pos.end;
    2786          525101 :         pn->pn_kid = pn2;
    2787                 :     } else {
    2788                 : #if JS_HAS_GENERATORS
    2789          112829 :         if (tt == TOK_RETURN)
    2790                 : #endif
    2791          112048 :             tc->flags |= TCF_RETURN_VOID;
    2792                 :     }
    2793                 : 
    2794          637930 :     if ((~tc->flags & (TCF_RETURN_EXPR | TCF_FUN_IS_GENERATOR)) == 0) {
    2795                 :         /* As in Python (see PEP-255), disallow return v; in generators. */
    2796                 :         ReportBadReturn(context, tc, pn, JSREPORT_ERROR,
    2797                 :                         JSMSG_BAD_GENERATOR_RETURN,
    2798               0 :                         JSMSG_BAD_ANON_GENERATOR_RETURN);
    2799               0 :         return NULL;
    2800                 :     }
    2801                 : 
    2802          639082 :     if (context->hasStrictOption() &&
    2803                 :         (~tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == 0 &&
    2804                 :         !ReportBadReturn(context, tc, pn, JSREPORT_WARNING | JSREPORT_STRICT,
    2805                 :                          JSMSG_NO_RETURN_VALUE,
    2806            1152 :                          JSMSG_ANON_NO_RETURN_VALUE)) {
    2807               0 :         return NULL;
    2808                 :     }
    2809                 : 
    2810          637930 :     return pn;
    2811                 : }
    2812                 : 
    2813                 : static ParseNode *
    2814          316510 : PushLexicalScope(JSContext *cx, TreeContext *tc, StaticBlockObject &obj, StmtInfo *stmt)
    2815                 : {
    2816          316510 :     ParseNode *pn = LexicalScopeNode::create(PNK_LEXICALSCOPE, tc);
    2817          316510 :     if (!pn)
    2818               0 :         return NULL;
    2819                 : 
    2820          316510 :     ObjectBox *blockbox = tc->parser->newObjectBox(&obj);
    2821          316510 :     if (!blockbox)
    2822               0 :         return NULL;
    2823                 : 
    2824          316510 :     PushBlockScope(tc, stmt, obj, -1);
    2825          316510 :     pn->setOp(JSOP_LEAVEBLOCK);
    2826          316510 :     pn->pn_objbox = blockbox;
    2827          316510 :     pn->pn_cookie.makeFree();
    2828          316510 :     pn->pn_dflags = 0;
    2829          316510 :     if (!GenerateBlockId(tc, stmt->blockid))
    2830               0 :         return NULL;
    2831          316510 :     pn->pn_blockid = stmt->blockid;
    2832          316510 :     return pn;
    2833                 : }
    2834                 : 
    2835                 : static ParseNode *
    2836          238360 : PushLexicalScope(JSContext *cx, TreeContext *tc, StmtInfo *stmt)
    2837                 : {
    2838          238360 :     StaticBlockObject *blockObj = StaticBlockObject::create(cx);
    2839          238360 :     if (!blockObj)
    2840               0 :         return NULL;
    2841                 : 
    2842          238360 :     return PushLexicalScope(cx, tc, *blockObj, stmt);
    2843                 : }
    2844                 : 
    2845                 : #if JS_HAS_BLOCK_SCOPE
    2846                 : 
    2847                 : struct AddDecl
    2848                 : {
    2849                 :     uint32_t blockid;
    2850                 : 
    2851           78150 :     AddDecl(uint32_t blockid) : blockid(blockid) {}
    2852                 : 
    2853          228396 :     bool operator()(TreeContext *tc, StaticBlockObject &blockObj, const Shape &shape, JSAtom *atom)
    2854                 :     {
    2855          228396 :         ParseNode *def = (ParseNode *) blockObj.getSlot(shape.slot()).toPrivate();
    2856          228396 :         def->pn_blockid = blockid;
    2857          228396 :         return Define(def, atom, tc, true);
    2858                 :     }
    2859                 : };
    2860                 : 
    2861                 : static ParseNode *
    2862           78150 : PushLetScope(JSContext *cx, TreeContext *tc, StaticBlockObject &blockObj, StmtInfo *stmt)
    2863                 : {
    2864           78150 :     ParseNode *pn = PushLexicalScope(cx, tc, blockObj, stmt);
    2865           78150 :     if (!pn)
    2866               0 :         return NULL;
    2867                 : 
    2868                 :     /* Tell codegen to emit JSOP_ENTERLETx (not JSOP_ENTERBLOCK). */
    2869           78150 :     pn->pn_dflags |= PND_LET;
    2870                 : 
    2871                 :     /* Populate the new scope with decls found in the head with updated blockid. */
    2872           78150 :     if (!ForEachLetDef(tc, blockObj, AddDecl(stmt->blockid)))
    2873               0 :         return NULL;
    2874                 : 
    2875           78150 :     return pn;
    2876                 : }
    2877                 : 
    2878                 : /*
    2879                 :  * Parse a let block statement or let expression (determined by 'letContext').
    2880                 :  * In both cases, bindings are not hoisted to the top of the enclosing block
    2881                 :  * and thus must be carefully injected between variables() and the let body.
    2882                 :  */
    2883                 : ParseNode *
    2884           15206 : Parser::letBlock(LetContext letContext)
    2885                 : {
    2886           15206 :     JS_ASSERT(tokenStream.currentToken().type == TOK_LET);
    2887                 : 
    2888           15206 :     ParseNode *pnlet = BinaryNode::create(PNK_LET, tc);
    2889           15206 :     if (!pnlet)
    2890               0 :         return NULL;
    2891                 : 
    2892           15206 :     StaticBlockObject *blockObj = StaticBlockObject::create(context);
    2893           15206 :     if (!blockObj)
    2894               0 :         return NULL;
    2895                 : 
    2896           15206 :     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_LET);
    2897                 : 
    2898           15206 :     ParseNode *vars = variables(PNK_LET, blockObj, DontHoistVars);
    2899           15206 :     if (!vars)
    2900             108 :         return NULL;
    2901                 : 
    2902           15098 :     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET);
    2903                 : 
    2904                 :     StmtInfo stmtInfo;
    2905           15080 :     ParseNode *block = PushLetScope(context, tc, *blockObj, &stmtInfo);
    2906           15080 :     if (!block)
    2907               0 :         return NULL;
    2908                 : 
    2909           15080 :     pnlet->pn_left = vars;
    2910           15080 :     pnlet->pn_right = block;
    2911                 : 
    2912                 :     ParseNode *ret;
    2913           15080 :     if (letContext == LetStatement && !tokenStream.matchToken(TOK_LC, TSF_OPERAND)) {
    2914                 :         /*
    2915                 :          * Strict mode eliminates a grammar ambiguity with unparenthesized
    2916                 :          * LetExpressions in an ExpressionStatement. If followed immediately
    2917                 :          * by an arguments list, it's ambiguous whether the let expression
    2918                 :          * is the callee or the call is inside the let expression body.
    2919                 :          *
    2920                 :          * See bug 569464.
    2921                 :          */
    2922             234 :         if (!ReportStrictModeError(context, &tokenStream, tc, pnlet,
    2923             234 :                                    JSMSG_STRICT_CODE_LET_EXPR_STMT)) {
    2924               0 :             return NULL;
    2925                 :         }
    2926                 : 
    2927                 :         /*
    2928                 :          * If this is really an expression in let statement guise, then we
    2929                 :          * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop
    2930                 :          * the return value of the expression.
    2931                 :          */
    2932             234 :         ParseNode *semi = UnaryNode::create(PNK_SEMI, tc);
    2933             234 :         if (!semi)
    2934               0 :             return NULL;
    2935                 : 
    2936             234 :         semi->pn_kid = pnlet;
    2937                 : 
    2938             234 :         letContext = LetExpresion;
    2939             234 :         ret = semi;
    2940                 :     } else {
    2941           14846 :         ret = pnlet;
    2942                 :     }
    2943                 : 
    2944           15080 :     if (letContext == LetStatement) {
    2945           12939 :         JS_ASSERT(block->getOp() == JSOP_LEAVEBLOCK);
    2946           12939 :         block->pn_expr = statements();
    2947           12939 :         if (!block->pn_expr)
    2948              18 :             return NULL;
    2949           12921 :         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
    2950                 :     } else {
    2951            2141 :         JS_ASSERT(letContext == LetExpresion);
    2952            2141 :         block->setOp(JSOP_LEAVEBLOCKEXPR);
    2953            2141 :         block->pn_expr = assignExpr();
    2954            2141 :         if (!block->pn_expr)
    2955               0 :             return NULL;
    2956                 :     }
    2957                 : 
    2958           15062 :     PopStatement(tc);
    2959           15062 :     return ret;
    2960                 : }
    2961                 : 
    2962                 : #endif /* JS_HAS_BLOCK_SCOPE */
    2963                 : 
    2964                 : static bool
    2965         1120302 : PushBlocklikeStatement(StmtInfo *stmt, StmtType type, TreeContext *tc)
    2966                 : {
    2967         1120302 :     PushStatement(tc, stmt, type, -1);
    2968         1120302 :     return GenerateBlockId(tc, stmt->blockid);
    2969                 : }
    2970                 : 
    2971                 : static ParseNode *
    2972         1858467 : NewBindingNode(JSAtom *atom, TreeContext *tc, StaticBlockObject *blockObj = NULL,
    2973                 :                VarContext varContext = HoistVars)
    2974                 : {
    2975                 :     /*
    2976                 :      * If this name is being injected into an existing block/function, see if
    2977                 :      * it has already been declared or if it resolves an outstanding lexdep.
    2978                 :      * Otherwise, this is a let block/expr that introduces a new scope and thus
    2979                 :      * shadows existing decls and doesn't resolve existing lexdeps. Duplicate
    2980                 :      * names are caught by BindLet.
    2981                 :      */
    2982         1858467 :     if (!blockObj || varContext == HoistVars) {
    2983         1636333 :         ParseNode *pn = tc->decls.lookupFirst(atom);
    2984         1636333 :         AtomDefnPtr removal;
    2985         1636333 :         if (pn) {
    2986           11930 :             JS_ASSERT(!pn->isPlaceholder());
    2987                 :         } else {
    2988         1624403 :             removal = tc->lexdeps->lookup(atom);
    2989         1624403 :             pn = removal ? removal.value() : NULL;
    2990         1624403 :             JS_ASSERT_IF(pn, pn->isPlaceholder());
    2991                 :         }
    2992                 : 
    2993         1636333 :         if (pn) {
    2994           33811 :             JS_ASSERT(pn->isDefn());
    2995                 : 
    2996                 :             /*
    2997                 :              * A let binding at top level becomes a var before we get here, so if
    2998                 :              * pn and tc have the same blockid then that id must not be the bodyid.
    2999                 :              * If pn is a forward placeholder definition from the same or a higher
    3000                 :              * block then we claim it.
    3001                 :              */
    3002            2807 :             JS_ASSERT_IF(blockObj && pn->pn_blockid == tc->blockid(),
    3003           36618 :                          pn->pn_blockid != tc->bodyid);
    3004                 : 
    3005           33811 :             if (pn->isPlaceholder() && pn->pn_blockid >= tc->blockid()) {
    3006           19517 :                 pn->pn_blockid = tc->blockid();
    3007           19517 :                 tc->lexdeps->remove(removal);
    3008           19517 :                 return pn;
    3009                 :             }
    3010                 :         }
    3011                 :     }
    3012                 : 
    3013                 :     /* Make a new node for this declarator name (or destructuring pattern). */
    3014         1838950 :     JS_ASSERT(tc->parser->tokenStream.currentToken().type == TOK_NAME);
    3015         1838950 :     ParseNode *pn = NameNode::create(PNK_NAME, atom, tc);
    3016         1838950 :     if (!pn)
    3017               0 :         return NULL;
    3018                 : 
    3019         1838950 :     if (atom == tc->parser->context->runtime->atomState.argumentsAtom)
    3020              36 :         tc->countArgumentsUse(pn);
    3021                 : 
    3022         1838950 :     return pn;
    3023                 : }
    3024                 : 
    3025                 : ParseNode *
    3026           17276 : Parser::switchStatement()
    3027                 : {
    3028           17276 :     JS_ASSERT(tc->parser->tokenStream.currentToken().type == TOK_SWITCH);
    3029           17276 :     ParseNode *pn = BinaryNode::create(PNK_SWITCH, tc);
    3030           17276 :     if (!pn)
    3031               0 :         return NULL;
    3032           17276 :     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);
    3033                 : 
    3034                 :     /* pn1 points to the switch's discriminant. */
    3035           17276 :     ParseNode *pn1 = parenExpr();
    3036           17276 :     if (!pn1)
    3037               0 :         return NULL;
    3038                 : 
    3039           17276 :     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH);
    3040           17276 :     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
    3041                 : 
    3042                 :     /*
    3043                 :      * NB: we must push stmtInfo before calling GenerateBlockIdForStmtNode
    3044                 :      * because that function states tc->topStmt->blockid.
    3045                 :      */
    3046                 :     StmtInfo stmtInfo;
    3047           17276 :     PushStatement(tc, &stmtInfo, STMT_SWITCH, -1);
    3048                 : 
    3049                 :     /* pn2 is a list of case nodes. The default case has pn_left == NULL */
    3050           17276 :     ParseNode *pn2 = ListNode::create(PNK_STATEMENTLIST, tc);
    3051           17276 :     if (!pn2)
    3052               0 :         return NULL;
    3053           17276 :     pn2->makeEmpty();
    3054           17276 :     if (!GenerateBlockIdForStmtNode(pn2, tc))
    3055               0 :         return NULL;
    3056           17276 :     ParseNode *saveBlock = tc->blockNode;
    3057           17276 :     tc->blockNode = pn2;
    3058                 : 
    3059           17276 :     bool seenDefault = false;
    3060                 :     TokenKind tt;
    3061          119195 :     while ((tt = tokenStream.getToken()) != TOK_RC) {
    3062                 :         ParseNode *pn3;
    3063           84652 :         switch (tt) {
    3064                 :           case TOK_DEFAULT:
    3065            9549 :             if (seenDefault) {
    3066               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_DEFAULTS);
    3067               0 :                 return NULL;
    3068                 :             }
    3069            9549 :             seenDefault = true;
    3070            9549 :             pn3 = BinaryNode::create(PNK_DEFAULT, tc);
    3071            9549 :             if (!pn3)
    3072               0 :                 return NULL;
    3073            9549 :             break;
    3074                 : 
    3075                 :           case TOK_CASE:
    3076                 :           {
    3077           75103 :             pn3 = BinaryNode::create(PNK_CASE, tc);
    3078           75103 :             if (!pn3)
    3079               0 :                 return NULL;
    3080           75103 :             pn3->pn_left = expr();
    3081           75103 :             if (!pn3->pn_left)
    3082               0 :                 return NULL;
    3083           75103 :             break;
    3084                 :           }
    3085                 : 
    3086                 :           case TOK_ERROR:
    3087               0 :             return NULL;
    3088                 : 
    3089                 :           default:
    3090               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_SWITCH);
    3091               0 :             return NULL;
    3092                 :         }
    3093                 : 
    3094           84652 :         pn2->append(pn3);
    3095           84652 :         if (pn2->pn_count == JS_BIT(16)) {
    3096               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_CASES);
    3097               0 :             return NULL;
    3098                 :         }
    3099                 : 
    3100           84652 :         MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
    3101                 : 
    3102           84652 :         ParseNode *pn4 = ListNode::create(PNK_STATEMENTLIST, tc);
    3103           84652 :         if (!pn4)
    3104               0 :             return NULL;
    3105           84652 :         pn4->makeEmpty();
    3106          546585 :         while ((tt = tokenStream.peekToken(TSF_OPERAND)) != TOK_RC &&
    3107                 :                tt != TOK_CASE && tt != TOK_DEFAULT) {
    3108          377290 :             if (tt == TOK_ERROR)
    3109               0 :                 return NULL;
    3110          377290 :             ParseNode *pn5 = statement();
    3111          377290 :             if (!pn5)
    3112               9 :                 return NULL;
    3113          377281 :             pn4->pn_pos.end = pn5->pn_pos.end;
    3114          377281 :             pn4->append(pn5);
    3115                 :         }
    3116                 : 
    3117                 :         /* Fix the PN_LIST so it doesn't begin at the TOK_COLON. */
    3118           84643 :         if (pn4->pn_head)
    3119           70130 :             pn4->pn_pos.begin = pn4->pn_head->pn_pos.begin;
    3120           84643 :         pn3->pn_pos.end = pn4->pn_pos.end;
    3121           84643 :         pn3->pn_right = pn4;
    3122                 :     }
    3123                 : 
    3124                 :     /*
    3125                 :      * Handle the case where there was a let declaration in any case in
    3126                 :      * the switch body, but not within an inner block.  If it replaced
    3127                 :      * tc->blockNode with a new block node then we must refresh pn2 and
    3128                 :      * then restore tc->blockNode.
    3129                 :      */
    3130           17267 :     if (tc->blockNode != pn2)
    3131            3557 :         pn2 = tc->blockNode;
    3132           17267 :     tc->blockNode = saveBlock;
    3133           17267 :     PopStatement(tc);
    3134                 : 
    3135           17267 :     pn->pn_pos.end = pn2->pn_pos.end = tokenStream.currentToken().pos.end;
    3136           17267 :     pn->pn_left = pn1;
    3137           17267 :     pn->pn_right = pn2;
    3138           17267 :     return pn;
    3139                 : }
    3140                 : 
    3141                 : bool
    3142          124228 : Parser::matchInOrOf(bool *isForOfp)
    3143                 : {
    3144          124228 :     if (tokenStream.matchToken(TOK_IN)) {
    3145           56445 :         *isForOfp = false;
    3146           56445 :         return true;
    3147                 :     }
    3148           67783 :     if (tokenStream.matchToken(TOK_NAME)) {
    3149            1017 :         if (tokenStream.currentToken().name() == context->runtime->atomState.ofAtom) {
    3150            1017 :             *isForOfp = true;
    3151            1017 :             return true;
    3152                 :         }
    3153               0 :         tokenStream.ungetToken();
    3154                 :     }
    3155           66766 :     return false;
    3156                 : }
    3157                 : 
    3158                 : ParseNode *
    3159          109996 : Parser::forStatement()
    3160                 : {
    3161          109996 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
    3162                 : 
    3163                 :     /* A FOR node is binary, left is loop control and right is the body. */
    3164          109996 :     ParseNode *pn = BinaryNode::create(PNK_FOR, tc);
    3165          109996 :     if (!pn)
    3166               0 :         return NULL;
    3167                 : 
    3168                 :     StmtInfo forStmt;
    3169          109996 :     PushStatement(tc, &forStmt, STMT_FOR_LOOP, -1);
    3170                 : 
    3171          109996 :     pn->setOp(JSOP_ITER);
    3172          109996 :     pn->pn_iflags = 0;
    3173          109996 :     if (tokenStream.matchToken(TOK_NAME)) {
    3174           13723 :         if (tokenStream.currentToken().name() == context->runtime->atomState.eachAtom)
    3175           13723 :             pn->pn_iflags = JSITER_FOREACH;
    3176                 :         else
    3177               0 :             tokenStream.ungetToken();
    3178                 :     }
    3179                 : 
    3180          109996 :     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
    3181                 : 
    3182                 :     /*
    3183                 :      * True if we have 'for (var/let/const ...)', except in the oddball case
    3184                 :      * where 'let' begins a let-expression in 'for (let (...) ...)'.
    3185                 :      */
    3186          109996 :     bool forDecl = false;
    3187                 : 
    3188                 :     /* Non-null when forDecl is true for a 'for (let ...)' statement. */
    3189          109996 :     StaticBlockObject *blockObj = NULL;
    3190                 : 
    3191                 :     /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
    3192                 :     ParseNode *pn1;
    3193                 : 
    3194                 :     {
    3195          109996 :         TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
    3196          109996 :         if (tt == TOK_SEMI) {
    3197            1343 :             if (pn->pn_iflags & JSITER_FOREACH) {
    3198               0 :                 reportErrorNumber(pn, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
    3199               0 :                 return NULL;
    3200                 :             }
    3201                 : 
    3202            1343 :             pn1 = NULL;
    3203                 :         } else {
    3204                 :             /*
    3205                 :              * Set pn1 to a var list or an initializing expression.
    3206                 :              *
    3207                 :              * Set the TCF_IN_FOR_INIT flag during parsing of the first clause
    3208                 :              * of the for statement.  This flag will be used by the RelExpr
    3209                 :              * production; if it is set, then the 'in' keyword will not be
    3210                 :              * recognized as an operator, leaving it available to be parsed as
    3211                 :              * part of a for/in loop.
    3212                 :              *
    3213                 :              * A side effect of this restriction is that (unparenthesized)
    3214                 :              * expressions involving an 'in' operator are illegal in the init
    3215                 :              * clause of an ordinary for loop.
    3216                 :              */
    3217          108653 :             tc->flags |= TCF_IN_FOR_INIT;
    3218          108653 :             if (tt == TOK_VAR || tt == TOK_CONST) {
    3219           39459 :                 forDecl = true;
    3220           39459 :                 tokenStream.consumeKnownToken(tt);
    3221           39459 :                 pn1 = variables(tt == TOK_VAR ? PNK_VAR : PNK_CONST);
    3222                 :             }
    3223                 : #if JS_HAS_BLOCK_SCOPE
    3224           69194 :             else if (tt == TOK_LET) {
    3225           63241 :                 (void) tokenStream.getToken();
    3226           63241 :                 if (tokenStream.peekToken() == TOK_LP) {
    3227              81 :                     pn1 = letBlock(LetExpresion);
    3228                 :                 } else {
    3229           63160 :                     forDecl = true;
    3230           63160 :                     blockObj = StaticBlockObject::create(context);
    3231           63160 :                     if (!blockObj)
    3232               0 :                         return NULL;
    3233           63160 :                     pn1 = variables(PNK_LET, blockObj, DontHoistVars);
    3234                 :                 }
    3235                 :             }
    3236                 : #endif
    3237                 :             else {
    3238            5953 :                 pn1 = expr();
    3239                 :             }
    3240          108653 :             tc->flags &= ~TCF_IN_FOR_INIT;
    3241          108653 :             if (!pn1)
    3242              90 :                 return NULL;
    3243                 :         }
    3244                 :     }
    3245                 : 
    3246          109906 :     JS_ASSERT_IF(forDecl, pn1->isArity(PN_LIST));
    3247          109906 :     JS_ASSERT(!!blockObj == (forDecl && pn1->isOp(JSOP_NOP)));
    3248                 : 
    3249          109906 :     const TokenPos pos = tokenStream.currentToken().pos;
    3250                 : 
    3251                 :     /* If non-null, the parent that should be returned instead of forHead. */
    3252          109906 :     ParseNode *forParent = NULL;
    3253                 : 
    3254                 :     /*
    3255                 :      * We can be sure that it's a for/in loop if there's still an 'in'
    3256                 :      * keyword here, even if JavaScript recognizes 'in' as an operator,
    3257                 :      * as we've excluded 'in' from being parsed in RelExpr by setting
    3258                 :      * the TCF_IN_FOR_INIT flag in our TreeContext.
    3259                 :      */
    3260                 :     ParseNode *forHead;     /* initialized by both branches. */
    3261                 :     StmtInfo letStmt;       /* used if blockObj != NULL. */
    3262                 :     ParseNode *pn2, *pn3;   /* forHead->pn_kid1 and pn_kid2. */
    3263                 :     bool forOf;
    3264          109906 :     if (pn1 && matchInOrOf(&forOf)) {
    3265                 :         /*
    3266                 :          * Parse the rest of the for/in or for/of head.
    3267                 :          *
    3268                 :          * Here pn1 is everything to the left of 'in' or 'of'. At the end of
    3269                 :          * this block, pn1 is a decl or NULL, pn2 is the assignment target that
    3270                 :          * receives the enumeration value each iteration, and pn3 is the rhs of
    3271                 :          * 'in'.
    3272                 :          */
    3273           42103 :         forStmt.type = STMT_FOR_IN_LOOP;
    3274                 : 
    3275                 :         /* Set pn_iflags and rule out invalid combinations. */
    3276           42103 :         if (forOf && pn->pn_iflags != 0) {
    3277              27 :             JS_ASSERT(pn->pn_iflags == JSITER_FOREACH);
    3278              27 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
    3279              27 :             return NULL;
    3280                 :         }
    3281           42076 :         pn->pn_iflags |= (forOf ? JSITER_FOR_OF : JSITER_ENUMERATE);
    3282                 : 
    3283                 :         /* Check that the left side of the 'in' or 'of' is valid. */
    3284          124349 :         if (forDecl
    3285           39348 :             ? (pn1->pn_count > 1 || pn1->isOp(JSOP_DEFCONST)
    3286                 : #if JS_HAS_DESTRUCTURING
    3287           39348 :                || (versionNumber() == JSVERSION_1_7 &&
    3288               0 :                    pn->isOp(JSOP_ITER) &&
    3289               0 :                    !(pn->pn_iflags & JSITER_FOREACH) &&
    3290               0 :                    (pn1->pn_head->isKind(PNK_RC) ||
    3291               0 :                     (pn1->pn_head->isKind(PNK_RB) &&
    3292                 :                      pn1->pn_head->pn_count != 2) ||
    3293               0 :                     (pn1->pn_head->isKind(PNK_ASSIGN) &&
    3294               0 :                      (!pn1->pn_head->pn_left->isKind(PNK_RB) ||
    3295                 :                       pn1->pn_head->pn_left->pn_count != 2))))
    3296                 : #endif
    3297                 :               )
    3298            2728 :             : (!pn1->isKind(PNK_NAME) &&
    3299             238 :                !pn1->isKind(PNK_DOT) &&
    3300                 : #if JS_HAS_DESTRUCTURING
    3301             193 :                ((versionNumber() == JSVERSION_1_7 &&
    3302               0 :                  pn->isOp(JSOP_ITER) &&
    3303               0 :                  !(pn->pn_iflags & JSITER_FOREACH))
    3304               0 :                 ? (!pn1->isKind(PNK_RB) || pn1->pn_count != 2)
    3305             283 :                 : (!pn1->isKind(PNK_RB) && !pn1->isKind(PNK_RC))) &&
    3306                 : #endif
    3307              45 :                !pn1->isKind(PNK_LP) &&
    3308                 : #if JS_HAS_XML_SUPPORT
    3309              45 :                !pn1->isKind(PNK_XMLUNARY) &&
    3310                 : #endif
    3311              45 :                !pn1->isKind(PNK_LB)))
    3312                 :         {
    3313              27 :             reportErrorNumber(pn1, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE);
    3314              27 :             return NULL;
    3315                 :         }
    3316                 : 
    3317                 :         /*
    3318                 :          * After the following if-else, pn2 will point to the name or
    3319                 :          * destructuring pattern on in's left. pn1 will point to the decl, if
    3320                 :          * any, else NULL. Note that the "declaration with initializer" case
    3321                 :          * rewrites the loop-head, moving the decl and setting pn1 to NULL.
    3322                 :          */
    3323           42049 :         pn2 = NULL;
    3324           42049 :         unsigned dflag = PND_ASSIGNED;
    3325           42049 :         if (forDecl) {
    3326                 :             /* Tell EmitVariables that pn1 is part of a for/in. */
    3327           39348 :             pn1->pn_xflags |= PNX_FORINVAR;
    3328                 : 
    3329           39348 :             pn2 = pn1->pn_head;
    3330           78687 :             if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr())
    3331                 : #if JS_HAS_DESTRUCTURING
    3332           39339 :                 || pn2->isKind(PNK_ASSIGN)
    3333                 : #endif
    3334                 :                 )
    3335                 :             {
    3336                 :                 /*
    3337                 :                  * Declaration with initializer.
    3338                 :                  *
    3339                 :                  * Rewrite 'for (<decl> x = i in o)' where <decl> is 'var' or
    3340                 :                  * 'const' to hoist the initializer or the entire decl out of
    3341                 :                  * the loop head.
    3342                 :                  */
    3343                 : #if JS_HAS_BLOCK_SCOPE
    3344              36 :                 if (blockObj) {
    3345               0 :                     reportErrorNumber(pn2, JSREPORT_ERROR, JSMSG_INVALID_FOR_IN_INIT);
    3346               0 :                     return NULL;
    3347                 :                 }
    3348                 : #endif /* JS_HAS_BLOCK_SCOPE */
    3349                 : 
    3350              36 :                 ParseNode *pnseq = ListNode::create(PNK_SEQ, tc);
    3351              36 :                 if (!pnseq)
    3352               0 :                     return NULL;
    3353                 : 
    3354              36 :                 dflag = PND_INITIALIZED;
    3355                 : 
    3356                 :                 /*
    3357                 :                  * All of 'var x = i' is hoisted above 'for (x in o)',
    3358                 :                  * so clear PNX_FORINVAR.
    3359                 :                  *
    3360                 :                  * Request JSOP_POP here since the var is for a simple
    3361                 :                  * name (it is not a destructuring binding's left-hand
    3362                 :                  * side) and it has an initializer.
    3363                 :                  */
    3364              36 :                 pn1->pn_xflags &= ~PNX_FORINVAR;
    3365              36 :                 pn1->pn_xflags |= PNX_POPVAR;
    3366              36 :                 pnseq->initList(pn1);
    3367              36 :                 pn1 = NULL;
    3368                 : 
    3369                 : #if JS_HAS_DESTRUCTURING
    3370              36 :                 if (pn2->isKind(PNK_ASSIGN)) {
    3371              27 :                     pn2 = pn2->pn_left;
    3372              27 :                     JS_ASSERT(pn2->isKind(PNK_RB) || pn2->isKind(PNK_RC) ||
    3373              27 :                               pn2->isKind(PNK_NAME));
    3374                 :                 }
    3375                 : #endif
    3376              36 :                 pnseq->append(pn);
    3377              36 :                 forParent = pnseq;
    3378                 :             }
    3379                 :         } else {
    3380                 :             /* Not a declaration. */
    3381            2701 :             JS_ASSERT(!blockObj);
    3382            2701 :             pn2 = pn1;
    3383            2701 :             pn1 = NULL;
    3384                 : 
    3385            2701 :             if (!setAssignmentLhsOps(pn2, JSOP_NOP))
    3386               0 :                 return NULL;
    3387                 :         }
    3388                 : 
    3389           42049 :         pn3 = expr();
    3390           42049 :         if (!pn3)
    3391               9 :             return NULL;
    3392                 : 
    3393           42040 :         if (blockObj) {
    3394                 :             /*
    3395                 :              * Now that the pn3 has been parsed, push the let scope. To hold
    3396                 :              * the blockObj for the emitter, wrap the TOK_LEXICALSCOPE node
    3397                 :              * created by PushLetScope around the for's initializer. This also
    3398                 :              * serves to indicate the let-decl to the emitter.
    3399                 :              */
    3400           31614 :             ParseNode *block = PushLetScope(context, tc, *blockObj, &letStmt);
    3401           31614 :             if (!block)
    3402               0 :                 return NULL;
    3403           31614 :             letStmt.flags |= SIF_FOR_BLOCK;
    3404           31614 :             block->pn_expr = pn1;
    3405           31614 :             pn1 = block;
    3406                 :         }
    3407                 : 
    3408           42040 :         if (forDecl) {
    3409                 :             /*
    3410                 :              * pn2 is part of a declaration. Make a copy that can be passed to
    3411                 :              * EmitAssignment. Take care to do this after PushLetScope has
    3412                 :              * Define's the new binding since this pn2->isDefn() which tells
    3413                 :              * CloneLeftHandSide to make the new pn2 a use.
    3414                 :              */
    3415           39348 :             pn2 = CloneLeftHandSide(pn2, tc);
    3416           39348 :             if (!pn2)
    3417               0 :                 return NULL;
    3418                 :         }
    3419                 : 
    3420           42040 :         switch (pn2->getKind()) {
    3421                 :           case PNK_NAME:
    3422                 :             /* Beware 'for (arguments in ...)' with or without a 'var'. */
    3423           39487 :             NoteLValue(context, pn2, tc, dflag);
    3424           39487 :             break;
    3425                 : 
    3426                 : #if JS_HAS_DESTRUCTURING
    3427                 :           case PNK_ASSIGN:
    3428               0 :             JS_NOT_REACHED("forStatement TOK_ASSIGN");
    3429                 :             break;
    3430                 : 
    3431                 :           case PNK_RB:
    3432                 :           case PNK_RC:
    3433            2490 :             if (versionNumber() == JSVERSION_1_7) {
    3434                 :                 /*
    3435                 :                  * Destructuring for-in requires [key, value] enumeration
    3436                 :                  * in JS1.7.
    3437                 :                  */
    3438               0 :                 JS_ASSERT(pn->isOp(JSOP_ITER));
    3439               0 :                 if (!(pn->pn_iflags & JSITER_FOREACH))
    3440               0 :                     pn->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
    3441                 :             }
    3442            2490 :             break;
    3443                 : #endif
    3444                 : 
    3445                 :           default:;
    3446                 :         }
    3447                 : 
    3448           42040 :         forHead = TernaryNode::create(PNK_FORIN, tc);
    3449           42040 :         if (!forHead)
    3450               0 :             return NULL;
    3451                 :     } else {
    3452           67803 :         if (blockObj) {
    3453                 :             /*
    3454                 :              * Desugar 'for (let A; B; C) D' into 'let (A) { for (; B; C) D }'
    3455                 :              * to induce the correct scoping for A.
    3456                 :              */
    3457           31456 :             ParseNode *block = PushLetScope(context, tc, *blockObj, &letStmt);
    3458           31456 :             if (!block)
    3459               0 :                 return NULL;
    3460           31456 :             letStmt.flags |= SIF_FOR_BLOCK;
    3461                 : 
    3462           31456 :             ParseNode *let = new_<BinaryNode>(PNK_LET, JSOP_NOP, pos, pn1, block);
    3463           31456 :             if (!let)
    3464               0 :                 return NULL;
    3465                 : 
    3466           31456 :             pn1 = NULL;
    3467           31456 :             block->pn_expr = pn;
    3468           31456 :             forParent = let;
    3469                 :         }
    3470                 : 
    3471           67803 :         if (pn->pn_iflags & JSITER_FOREACH) {
    3472               0 :             reportErrorNumber(pn, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
    3473               0 :             return NULL;
    3474                 :         }
    3475           67803 :         pn->setOp(JSOP_NOP);
    3476                 : 
    3477                 :         /* Parse the loop condition or null into pn2. */
    3478           67803 :         MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
    3479           67803 :         if (tokenStream.peekToken(TSF_OPERAND) == TOK_SEMI) {
    3480            1339 :             pn2 = NULL;
    3481                 :         } else {
    3482           66464 :             pn2 = expr();
    3483           66464 :             if (!pn2)
    3484               0 :                 return NULL;
    3485                 :         }
    3486                 : 
    3487                 :         /* Parse the update expression or null into pn3. */
    3488           67803 :         MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
    3489           67803 :         if (tokenStream.peekToken(TSF_OPERAND) == TOK_RP) {
    3490            2178 :             pn3 = NULL;
    3491                 :         } else {
    3492           65625 :             pn3 = expr();
    3493           65625 :             if (!pn3)
    3494               0 :                 return NULL;
    3495                 :         }
    3496                 : 
    3497           67803 :         forHead = TernaryNode::create(PNK_FORHEAD, tc);
    3498           67803 :         if (!forHead)
    3499               0 :             return NULL;
    3500                 :     }
    3501                 : 
    3502          109843 :     forHead->pn_pos = pos;
    3503          109843 :     forHead->setOp(JSOP_NOP);
    3504          109843 :     forHead->pn_kid1 = pn1;
    3505          109843 :     forHead->pn_kid2 = pn2;
    3506          109843 :     forHead->pn_kid3 = pn3;
    3507          109843 :     pn->pn_left = forHead;
    3508                 : 
    3509          109843 :     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
    3510                 : 
    3511                 :     /* Parse the loop body. */
    3512          109789 :     ParseNode *body = statement();
    3513          109789 :     if (!body)
    3514               9 :         return NULL;
    3515                 : 
    3516                 :     /* Record the absolute line number for source note emission. */
    3517          109780 :     pn->pn_pos.end = body->pn_pos.end;
    3518          109780 :     pn->pn_right = body;
    3519                 : 
    3520          109780 :     if (forParent) {
    3521           31492 :         forParent->pn_pos.begin = pn->pn_pos.begin;
    3522           31492 :         forParent->pn_pos.end = pn->pn_pos.end;
    3523                 :     }
    3524                 : 
    3525                 : #if JS_HAS_BLOCK_SCOPE
    3526          109780 :     if (blockObj)
    3527           63061 :         PopStatement(tc);
    3528                 : #endif
    3529          109780 :     PopStatement(tc);
    3530          109780 :     return forParent ? forParent : pn;
    3531                 : }
    3532                 : 
    3533                 : ParseNode *
    3534          241156 : Parser::tryStatement()
    3535                 : {
    3536          241156 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_TRY));
    3537                 : 
    3538                 :     /*
    3539                 :      * try nodes are ternary.
    3540                 :      * kid1 is the try statement
    3541                 :      * kid2 is the catch node list or null
    3542                 :      * kid3 is the finally statement
    3543                 :      *
    3544                 :      * catch nodes are ternary.
    3545                 :      * kid1 is the lvalue (TOK_NAME, TOK_LB, or TOK_LC)
    3546                 :      * kid2 is the catch guard or null if no guard
    3547                 :      * kid3 is the catch block
    3548                 :      *
    3549                 :      * catch lvalue nodes are either:
    3550                 :      *   TOK_NAME for a single identifier
    3551                 :      *   TOK_RB or TOK_RC for a destructuring left-hand side
    3552                 :      *
    3553                 :      * finally nodes are TOK_LC statement lists.
    3554                 :      */
    3555          241156 :     ParseNode *pn = TernaryNode::create(PNK_TRY, tc);
    3556          241156 :     if (!pn)
    3557               0 :         return NULL;
    3558          241156 :     pn->setOp(JSOP_NOP);
    3559                 : 
    3560          241156 :     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
    3561                 :     StmtInfo stmtInfo;
    3562          241156 :     if (!PushBlocklikeStatement(&stmtInfo, STMT_TRY, tc))
    3563               0 :         return NULL;
    3564          241156 :     pn->pn_kid1 = statements();
    3565          241156 :     if (!pn->pn_kid1)
    3566               0 :         return NULL;
    3567          241156 :     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY);
    3568          241156 :     PopStatement(tc);
    3569                 : 
    3570                 :     ParseNode *lastCatch;
    3571          241156 :     ParseNode *catchList = NULL;
    3572          241156 :     TokenKind tt = tokenStream.getToken();
    3573          241156 :     if (tt == TOK_CATCH) {
    3574          225058 :         catchList = ListNode::create(PNK_CATCHLIST, tc);
    3575          225058 :         if (!catchList)
    3576               0 :             return NULL;
    3577          225058 :         catchList->makeEmpty();
    3578          225058 :         lastCatch = NULL;
    3579                 : 
    3580          225289 :         do {
    3581                 :             ParseNode *pnblock;
    3582          225289 :             BindData data;
    3583                 : 
    3584                 :             /* Check for another catch after unconditional catch. */
    3585          225289 :             if (lastCatch && !lastCatch->pn_kid2) {
    3586               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CATCH_AFTER_GENERAL);
    3587               0 :                 return NULL;
    3588                 :             }
    3589                 : 
    3590                 :             /*
    3591                 :              * Create a lexical scope node around the whole catch clause,
    3592                 :              * including the head.
    3593                 :              */
    3594          225289 :             pnblock = PushLexicalScope(context, tc, &stmtInfo);
    3595          225289 :             if (!pnblock)
    3596               0 :                 return NULL;
    3597          225289 :             stmtInfo.type = STMT_CATCH;
    3598                 : 
    3599                 :             /*
    3600                 :              * Legal catch forms are:
    3601                 :              *   catch (lhs)
    3602                 :              *   catch (lhs if <boolean_expression>)
    3603                 :              * where lhs is a name or a destructuring left-hand side.
    3604                 :              * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD)
    3605                 :              */
    3606          225289 :             ParseNode *pn2 = TernaryNode::create(PNK_CATCH, tc);
    3607          225289 :             if (!pn2)
    3608               0 :                 return NULL;
    3609          225289 :             pnblock->pn_expr = pn2;
    3610          225289 :             MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
    3611                 : 
    3612                 :             /*
    3613                 :              * Contrary to ECMA Ed. 3, the catch variable is lexically
    3614                 :              * scoped, not a property of a new Object instance.  This is
    3615                 :              * an intentional change that anticipates ECMA Ed. 4.
    3616                 :              */
    3617          225289 :             data.initLet(HoistVars, *tc->blockChain, JSMSG_TOO_MANY_CATCH_VARS);
    3618          225289 :             JS_ASSERT(data.let.blockObj && data.let.blockObj == pnblock->pn_objbox->object);
    3619                 : 
    3620          225289 :             tt = tokenStream.getToken();
    3621                 :             ParseNode *pn3;
    3622          225289 :             switch (tt) {
    3623                 : #if JS_HAS_DESTRUCTURING
    3624                 :               case TOK_LB:
    3625                 :               case TOK_LC:
    3626               0 :                 pn3 = destructuringExpr(&data, tt);
    3627               0 :                 if (!pn3)
    3628               0 :                     return NULL;
    3629               0 :                 break;
    3630                 : #endif
    3631                 : 
    3632                 :               case TOK_NAME:
    3633                 :               {
    3634          225289 :                 JSAtom *label = tokenStream.currentToken().name();
    3635          225289 :                 pn3 = NewBindingNode(label, tc);
    3636          225289 :                 if (!pn3)
    3637               0 :                     return NULL;
    3638          225289 :                 data.pn = pn3;
    3639          225289 :                 if (!data.binder(context, &data, label, tc))
    3640               0 :                     return NULL;
    3641          225289 :                 break;
    3642                 :               }
    3643                 : 
    3644                 :               default:
    3645               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CATCH_IDENTIFIER);
    3646               0 :                 return NULL;
    3647                 :             }
    3648                 : 
    3649          225289 :             pn2->pn_kid1 = pn3;
    3650                 : #if JS_HAS_CATCH_GUARD
    3651                 :             /*
    3652                 :              * We use 'catch (x if x === 5)' (not 'catch (x : x === 5)')
    3653                 :              * to avoid conflicting with the JS2/ECMAv4 type annotation
    3654                 :              * catchguard syntax.
    3655                 :              */
    3656          225289 :             if (tokenStream.matchToken(TOK_IF)) {
    3657            1217 :                 pn2->pn_kid2 = expr();
    3658            1217 :                 if (!pn2->pn_kid2)
    3659               0 :                     return NULL;
    3660                 :             }
    3661                 : #endif
    3662          225289 :             MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
    3663                 : 
    3664          225289 :             MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
    3665          225289 :             pn2->pn_kid3 = statements();
    3666          225289 :             if (!pn2->pn_kid3)
    3667               0 :                 return NULL;
    3668          225289 :             MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH);
    3669          225289 :             PopStatement(tc);
    3670                 : 
    3671          225289 :             catchList->append(pnblock);
    3672          225289 :             lastCatch = pn2;
    3673          225289 :             tt = tokenStream.getToken(TSF_OPERAND);
    3674                 :         } while (tt == TOK_CATCH);
    3675                 :     }
    3676          241156 :     pn->pn_kid2 = catchList;
    3677                 : 
    3678          241156 :     if (tt == TOK_FINALLY) {
    3679           22053 :         MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
    3680           22053 :         if (!PushBlocklikeStatement(&stmtInfo, STMT_FINALLY, tc))
    3681               0 :             return NULL;
    3682           22053 :         pn->pn_kid3 = statements();
    3683           22053 :         if (!pn->pn_kid3)
    3684               0 :             return NULL;
    3685           22053 :         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY);
    3686           22053 :         PopStatement(tc);
    3687                 :     } else {
    3688          219103 :         tokenStream.ungetToken();
    3689                 :     }
    3690          241156 :     if (!catchList && !pn->pn_kid3) {
    3691               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CATCH_OR_FINALLY);
    3692               0 :         return NULL;
    3693                 :     }
    3694          241156 :     return pn;
    3695                 : }
    3696                 : 
    3697                 : ParseNode *
    3698             630 : Parser::withStatement()
    3699                 : {
    3700             630 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_WITH));
    3701                 : 
    3702                 :     /*
    3703                 :      * In most cases, we want the constructs forbidden in strict mode
    3704                 :      * code to be a subset of those that JSOPTION_STRICT warns about, and
    3705                 :      * we should use ReportStrictModeError.  However, 'with' is the sole
    3706                 :      * instance of a construct that is forbidden in strict mode code, but
    3707                 :      * doesn't even merit a warning under JSOPTION_STRICT.  See
    3708                 :      * https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
    3709                 :      */
    3710             630 :     if (tc->flags & TCF_STRICT_MODE_CODE) {
    3711               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_STRICT_CODE_WITH);
    3712               0 :         return NULL;
    3713                 :     }
    3714                 : 
    3715             630 :     ParseNode *pn = BinaryNode::create(PNK_WITH, tc);
    3716             630 :     if (!pn)
    3717               0 :         return NULL;
    3718             630 :     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
    3719             630 :     ParseNode *pn2 = parenExpr();
    3720             630 :     if (!pn2)
    3721               0 :         return NULL;
    3722             630 :     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH);
    3723             630 :     pn->pn_left = pn2;
    3724                 : 
    3725             630 :     ParseNode *oldWith = tc->innermostWith;
    3726             630 :     tc->innermostWith = pn;
    3727                 : 
    3728                 :     StmtInfo stmtInfo;
    3729             630 :     PushStatement(tc, &stmtInfo, STMT_WITH, -1);
    3730             630 :     pn2 = statement();
    3731             630 :     if (!pn2)
    3732               0 :         return NULL;
    3733             630 :     PopStatement(tc);
    3734                 : 
    3735             630 :     pn->pn_pos.end = pn2->pn_pos.end;
    3736             630 :     pn->pn_right = pn2;
    3737             630 :     tc->flags |= TCF_FUN_HEAVYWEIGHT;
    3738             630 :     tc->innermostWith = oldWith;
    3739                 : 
    3740                 :     /*
    3741                 :      * Make sure to deoptimize lexical dependencies inside the |with|
    3742                 :      * to safely optimize binding globals (see bug 561923).
    3743                 :      */
    3744            1530 :     for (AtomDefnRange r = tc->lexdeps->all(); !r.empty(); r.popFront()) {
    3745             900 :         Definition *defn = r.front().value();
    3746             900 :         Definition *lexdep = defn->resolve();
    3747             900 :         DeoptimizeUsesWithin(lexdep, pn->pn_pos);
    3748                 :     }
    3749                 : 
    3750             630 :     return pn;
    3751                 : }
    3752                 : 
    3753                 : #if JS_HAS_BLOCK_SCOPE
    3754                 : ParseNode *
    3755          518050 : Parser::letStatement()
    3756                 : {
    3757                 :     ParseNode *pn;
    3758                 :     do {
    3759                 :         /* Check for a let statement or let expression. */
    3760          518050 :         if (tokenStream.peekToken() == TOK_LP) {
    3761           13299 :             pn = letBlock(LetStatement);
    3762           13299 :             if (!pn)
    3763             144 :                 return NULL;
    3764                 : 
    3765           13155 :             JS_ASSERT(pn->isKind(PNK_LET) || pn->isKind(PNK_SEMI));
    3766           13155 :             if (pn->isKind(PNK_LET) && pn->pn_expr->getOp() == JSOP_LEAVEBLOCK)
    3767           12921 :                 return pn;
    3768                 : 
    3769                 :             /* Let expressions require automatic semicolon insertion. */
    3770             234 :             JS_ASSERT(pn->isKind(PNK_SEMI) || pn->isOp(JSOP_NOP));
    3771             234 :             break;
    3772                 :         }
    3773                 : 
    3774                 :         /*
    3775                 :          * This is a let declaration. We must be directly under a block per the
    3776                 :          * proposed ES4 specs, but not an implicit block created due to
    3777                 :          * 'for (let ...)'. If we pass this error test, make the enclosing
    3778                 :          * StmtInfo be our scope. Further let declarations in this block will
    3779                 :          * find this scope statement and use the same block object.
    3780                 :          *
    3781                 :          * If we are the first let declaration in this block (i.e., when the
    3782                 :          * enclosing maybe-scope StmtInfo isn't yet a scope statement) then
    3783                 :          * we also need to set tc->blockNode to be our TOK_LEXICALSCOPE.
    3784                 :          */
    3785          504751 :         StmtInfo *stmt = tc->topStmt;
    3786         1491645 :         if (stmt &&
    3787          986894 :             (!STMT_MAYBE_SCOPE(stmt) || (stmt->flags & SIF_FOR_BLOCK))) {
    3788               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_LET_DECL_NOT_IN_BLOCK);
    3789               0 :             return NULL;
    3790                 :         }
    3791                 : 
    3792          504751 :         if (stmt && (stmt->flags & SIF_SCOPE)) {
    3793           73003 :             JS_ASSERT(tc->blockChain == stmt->blockObj);
    3794                 :         } else {
    3795          431748 :             if (!stmt || (stmt->flags & SIF_BODY_BLOCK)) {
    3796                 :                 /*
    3797                 :                  * ES4 specifies that let at top level and at body-block scope
    3798                 :                  * does not shadow var, so convert back to var.
    3799                 :                  */
    3800          299164 :                 pn = variables(PNK_VAR);
    3801          299164 :                 if (!pn)
    3802               0 :                     return NULL;
    3803          299164 :                 pn->pn_xflags |= PNX_POPVAR;
    3804          299164 :                 break;
    3805                 :             }
    3806                 : 
    3807                 :             /*
    3808                 :              * Some obvious assertions here, but they may help clarify the
    3809                 :              * situation. This stmt is not yet a scope, so it must not be a
    3810                 :              * catch block (catch is a lexical scope by definition).
    3811                 :              */
    3812          132584 :             JS_ASSERT(!(stmt->flags & SIF_SCOPE));
    3813          132584 :             JS_ASSERT(stmt != tc->topScopeStmt);
    3814               0 :             JS_ASSERT(stmt->type == STMT_BLOCK ||
    3815                 :                       stmt->type == STMT_SWITCH ||
    3816                 :                       stmt->type == STMT_TRY ||
    3817          132584 :                       stmt->type == STMT_FINALLY);
    3818          132584 :             JS_ASSERT(!stmt->downScope);
    3819                 : 
    3820                 :             /* Convert the block statement into a scope statement. */
    3821          132584 :             StaticBlockObject *blockObj = StaticBlockObject::create(tc->parser->context);
    3822          132584 :             if (!blockObj)
    3823               0 :                 return NULL;
    3824                 : 
    3825          132584 :             ObjectBox *blockbox = tc->parser->newObjectBox(blockObj);
    3826          132584 :             if (!blockbox)
    3827               0 :                 return NULL;
    3828                 : 
    3829                 :             /*
    3830                 :              * Insert stmt on the tc->topScopeStmt/stmtInfo.downScope linked
    3831                 :              * list stack, if it isn't already there.  If it is there, but it
    3832                 :              * lacks the SIF_SCOPE flag, it must be a try, catch, or finally
    3833                 :              * block.
    3834                 :              */
    3835          132584 :             stmt->flags |= SIF_SCOPE;
    3836          132584 :             stmt->downScope = tc->topScopeStmt;
    3837          132584 :             tc->topScopeStmt = stmt;
    3838                 : 
    3839          132584 :             blockObj->setEnclosingBlock(tc->blockChain);
    3840          132584 :             tc->blockChain = blockObj;
    3841          132584 :             stmt->blockObj = blockObj;
    3842                 : 
    3843                 : #ifdef DEBUG
    3844          132584 :             ParseNode *tmp = tc->blockNode;
    3845          132584 :             JS_ASSERT(!tmp || !tmp->isKind(PNK_LEXICALSCOPE));
    3846                 : #endif
    3847                 : 
    3848                 :             /* Create a new lexical scope node for these statements. */
    3849          132584 :             ParseNode *pn1 = LexicalScopeNode::create(PNK_LEXICALSCOPE, tc);
    3850          132584 :             if (!pn1)
    3851               0 :                 return NULL;
    3852                 : 
    3853          132584 :             pn1->setOp(JSOP_LEAVEBLOCK);
    3854          132584 :             pn1->pn_pos = tc->blockNode->pn_pos;
    3855          132584 :             pn1->pn_objbox = blockbox;
    3856          132584 :             pn1->pn_expr = tc->blockNode;
    3857          132584 :             pn1->pn_blockid = tc->blockNode->pn_blockid;
    3858          132584 :             tc->blockNode = pn1;
    3859                 :         }
    3860                 : 
    3861          205587 :         pn = variables(PNK_LET, tc->blockChain, HoistVars);
    3862          205587 :         if (!pn)
    3863              27 :             return NULL;
    3864          205560 :         pn->pn_xflags = PNX_POPVAR;
    3865                 :     } while (0);
    3866                 : 
    3867                 :     /* Check termination of this primitive statement. */
    3868          504958 :     return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL;
    3869                 : }
    3870                 : #endif
    3871                 : 
    3872                 : ParseNode *
    3873         6471069 : Parser::expressionStatement()
    3874                 : {
    3875         6471069 :     tokenStream.ungetToken();
    3876         6471069 :     ParseNode *pn2 = expr();
    3877         6471069 :     if (!pn2)
    3878             194 :         return NULL;
    3879                 : 
    3880         6470875 :     if (tokenStream.peekToken() == TOK_COLON) {
    3881             211 :         if (!pn2->isKind(PNK_NAME)) {
    3882               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_LABEL);
    3883               0 :             return NULL;
    3884                 :         }
    3885             211 :         JSAtom *label = pn2->pn_atom;
    3886             696 :         for (StmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) {
    3887             485 :             if (stmt->type == STMT_LABEL && stmt->label == label) {
    3888               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_DUPLICATE_LABEL);
    3889               0 :                 return NULL;
    3890                 :             }
    3891                 :         }
    3892             211 :         ForgetUse(pn2);
    3893                 : 
    3894             211 :         (void) tokenStream.getToken();
    3895                 : 
    3896                 :         /* Push a label struct and parse the statement. */
    3897                 :         StmtInfo stmtInfo;
    3898             211 :         PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
    3899             211 :         stmtInfo.label = label;
    3900             211 :         ParseNode *pn = statement();
    3901             211 :         if (!pn)
    3902               0 :             return NULL;
    3903                 : 
    3904                 :         /* Normalize empty statement to empty block for the decompiler. */
    3905             211 :         if (pn->isKind(PNK_SEMI) && !pn->pn_kid) {
    3906               0 :             pn->setKind(PNK_STATEMENTLIST);
    3907               0 :             pn->setArity(PN_LIST);
    3908               0 :             pn->makeEmpty();
    3909                 :         }
    3910                 : 
    3911                 :         /* Pop the label, set pn_expr, and return early. */
    3912             211 :         PopStatement(tc);
    3913             211 :         pn2->setKind(PNK_COLON);
    3914             211 :         pn2->pn_pos.end = pn->pn_pos.end;
    3915             211 :         pn2->pn_expr = pn;
    3916             211 :         return pn2;
    3917                 :     }
    3918                 : 
    3919         6470664 :     ParseNode *pn = UnaryNode::create(PNK_SEMI, tc);
    3920         6470664 :     if (!pn)
    3921               0 :         return NULL;
    3922         6470664 :     pn->pn_pos = pn2->pn_pos;
    3923         6470664 :     pn->pn_kid = pn2;
    3924                 : 
    3925         6470664 :     switch (pn2->getKind()) {
    3926                 :       case PNK_LP:
    3927                 :         /*
    3928                 :          * Flag lambdas immediately applied as statements as instances of
    3929                 :          * the JS "module pattern". See CheckForImmediatelyAppliedLambda.
    3930                 :          */
    3931         1749055 :         if (pn2->pn_head->isKind(PNK_FUNCTION) &&
    3932            2344 :             !pn2->pn_head->pn_funbox->node->isFunArg()) {
    3933            2168 :             pn2->pn_head->pn_funbox->tcflags |= TCF_FUN_MODULE_PATTERN;
    3934                 :         }
    3935         1746711 :         break;
    3936                 :       case PNK_ASSIGN:
    3937                 :         /*
    3938                 :          * Keep track of all apparent methods created by assignments such
    3939                 :          * as this.foo = function (...) {...} in a function that could end
    3940                 :          * up a constructor function. See Parser::setFunctionKinds.
    3941                 :          */
    3942         2895160 :         JS_ASSERT(pn2->isOp(JSOP_NOP));
    3943         4629253 :         if (tc->funbox &&
    3944          901432 :             pn2->pn_left->isOp(JSOP_SETPROP) &&
    3945          559719 :             pn2->pn_left->pn_expr->isKind(PNK_THIS) &&
    3946          272942 :             pn2->pn_right->isOp(JSOP_LAMBDA))
    3947                 :         {
    3948            7266 :             JS_ASSERT(!pn2->isDefn());
    3949            7266 :             JS_ASSERT(!pn2->isUsed());
    3950            7266 :             pn2->pn_right->pn_link = tc->funbox->methods;
    3951            7266 :             tc->funbox->methods = pn2->pn_right;
    3952                 :         }
    3953         2895160 :         break;
    3954                 :       default:;
    3955                 :     }
    3956                 : 
    3957                 :     /* Check termination of this primitive statement. */
    3958         6470664 :     return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL;
    3959                 : }
    3960                 : 
    3961                 : ParseNode *
    3962        10995009 : Parser::statement()
    3963                 : {
    3964                 :     ParseNode *pn;
    3965                 : 
    3966        10995009 :     JS_CHECK_RECURSION(context, return NULL);
    3967                 : 
    3968        10995009 :     switch (tokenStream.getToken(TSF_OPERAND)) {
    3969                 :       case TOK_FUNCTION:
    3970                 :       {
    3971                 : #if JS_HAS_XML_SUPPORT
    3972          229274 :         if (!tc->inStrictMode()) {
    3973          169737 :             TokenKind tt = tokenStream.peekToken(TSF_KEYWORD_IS_NAME);
    3974          169737 :             if (tt == TOK_DBLCOLON)
    3975              18 :                 return expressionStatement();
    3976                 :         }
    3977                 : #endif
    3978          229256 :         return functionStmt();
    3979                 :       }
    3980                 : 
    3981                 :       case TOK_IF:
    3982                 :       {
    3983                 :         /* An IF node has three kids: condition, then, and optional else. */
    3984          947006 :         pn = TernaryNode::create(PNK_IF, tc);
    3985          947006 :         if (!pn)
    3986               0 :             return NULL;
    3987          947006 :         ParseNode *pn1 = condition();
    3988          947006 :         if (!pn1)
    3989               0 :             return NULL;
    3990                 : 
    3991                 :         StmtInfo stmtInfo;
    3992          947006 :         PushStatement(tc, &stmtInfo, STMT_IF, -1);
    3993          947006 :         ParseNode *pn2 = statement();
    3994          947006 :         if (!pn2)
    3995              36 :             return NULL;
    3996                 : 
    3997         1134786 :         if (pn2->isKind(PNK_SEMI) &&
    3998          187813 :             !pn2->pn_kid &&
    3999               3 :             !reportErrorNumber(NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_EMPTY_CONSEQUENT))
    4000                 :         {
    4001               0 :             return NULL;
    4002                 :         }
    4003                 : 
    4004                 :         ParseNode *pn3;
    4005          946970 :         if (tokenStream.matchToken(TOK_ELSE, TSF_OPERAND)) {
    4006          156612 :             stmtInfo.type = STMT_ELSE;
    4007          156612 :             pn3 = statement();
    4008          156612 :             if (!pn3)
    4009               0 :                 return NULL;
    4010          156612 :             pn->pn_pos.end = pn3->pn_pos.end;
    4011                 :         } else {
    4012          790358 :             pn3 = NULL;
    4013          790358 :             pn->pn_pos.end = pn2->pn_pos.end;
    4014                 :         }
    4015          946970 :         PopStatement(tc);
    4016          946970 :         pn->pn_kid1 = pn1;
    4017          946970 :         pn->pn_kid2 = pn2;
    4018          946970 :         pn->pn_kid3 = pn3;
    4019          946970 :         return pn;
    4020                 :       }
    4021                 : 
    4022                 :       case TOK_SWITCH:
    4023           17276 :         return switchStatement();
    4024                 : 
    4025                 :       case TOK_WHILE:
    4026                 :       {
    4027           51638 :         pn = BinaryNode::create(PNK_WHILE, tc);
    4028           51638 :         if (!pn)
    4029               0 :             return NULL;
    4030                 :         StmtInfo stmtInfo;
    4031           51638 :         PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1);
    4032           51638 :         ParseNode *pn2 = condition();
    4033           51638 :         if (!pn2)
    4034               0 :             return NULL;
    4035           51638 :         pn->pn_left = pn2;
    4036           51638 :         ParseNode *pn3 = statement();
    4037           51638 :         if (!pn3)
    4038               0 :             return NULL;
    4039           51638 :         PopStatement(tc);
    4040           51638 :         pn->pn_pos.end = pn3->pn_pos.end;
    4041           51638 :         pn->pn_right = pn3;
    4042           51638 :         return pn;
    4043                 :       }
    4044                 : 
    4045                 :       case TOK_DO:
    4046                 :       {
    4047             383 :         pn = BinaryNode::create(PNK_DOWHILE, tc);
    4048             383 :         if (!pn)
    4049               0 :             return NULL;
    4050                 :         StmtInfo stmtInfo;
    4051             383 :         PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1);
    4052             383 :         ParseNode *pn2 = statement();
    4053             383 :         if (!pn2)
    4054               0 :             return NULL;
    4055             383 :         pn->pn_left = pn2;
    4056             383 :         MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO);
    4057             383 :         ParseNode *pn3 = condition();
    4058             383 :         if (!pn3)
    4059               0 :             return NULL;
    4060             383 :         PopStatement(tc);
    4061             383 :         pn->pn_pos.end = pn3->pn_pos.end;
    4062             383 :         pn->pn_right = pn3;
    4063             383 :         if (versionNumber() != JSVERSION_ECMA_3) {
    4064                 :             /*
    4065                 :              * All legacy and extended versions must do automatic semicolon
    4066                 :              * insertion after do-while.  See the testcase and discussion in
    4067                 :              * http://bugzilla.mozilla.org/show_bug.cgi?id=238945.
    4068                 :              */
    4069             383 :             (void) tokenStream.matchToken(TOK_SEMI);
    4070             383 :             return pn;
    4071                 :         }
    4072               0 :         break;
    4073                 :       }
    4074                 : 
    4075                 :       case TOK_FOR:
    4076          109996 :         return forStatement();
    4077                 : 
    4078                 :       case TOK_TRY:
    4079          241156 :         return tryStatement();
    4080                 : 
    4081                 :       case TOK_THROW:
    4082                 :       {
    4083          123782 :         pn = UnaryNode::create(PNK_THROW, tc);
    4084          123782 :         if (!pn)
    4085               0 :             return NULL;
    4086                 : 
    4087                 :         /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */
    4088          123782 :         TokenKind tt = tokenStream.peekTokenSameLine(TSF_OPERAND);
    4089          123782 :         if (tt == TOK_ERROR)
    4090               0 :             return NULL;
    4091          123782 :         if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) {
    4092               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
    4093               0 :             return NULL;
    4094                 :         }
    4095                 : 
    4096          123782 :         ParseNode *pn2 = expr();
    4097          123782 :         if (!pn2)
    4098               0 :             return NULL;
    4099          123782 :         pn->pn_pos.end = pn2->pn_pos.end;
    4100          123782 :         pn->setOp(JSOP_THROW);
    4101          123782 :         pn->pn_kid = pn2;
    4102          123782 :         break;
    4103                 :       }
    4104                 : 
    4105                 :       /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
    4106                 :       case TOK_CATCH:
    4107               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CATCH_WITHOUT_TRY);
    4108               0 :         return NULL;
    4109                 : 
    4110                 :       case TOK_FINALLY:
    4111               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_FINALLY_WITHOUT_TRY);
    4112               0 :         return NULL;
    4113                 : 
    4114                 :       case TOK_BREAK:
    4115                 :       {
    4116           53082 :         TokenPtr begin = tokenStream.currentToken().pos.begin;
    4117                 :         PropertyName *label;
    4118           53082 :         if (!MatchLabel(context, &tokenStream, &label))
    4119               0 :             return NULL;
    4120           53082 :         TokenPtr end = tokenStream.currentToken().pos.end;
    4121           53082 :         pn = new_<BreakStatement>(label, begin, end);
    4122           53082 :         if (!pn)
    4123               0 :             return NULL;
    4124           53082 :         StmtInfo *stmt = tc->topStmt;
    4125           53082 :         if (label) {
    4126             522 :             for (; ; stmt = stmt->down) {
    4127             630 :                 if (!stmt) {
    4128               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND);
    4129               0 :                     return NULL;
    4130                 :                 }
    4131             630 :                 if (stmt->type == STMT_LABEL && stmt->label == label)
    4132                 :                     break;
    4133                 :             }
    4134                 :         } else {
    4135           26637 :             for (; ; stmt = stmt->down) {
    4136           79611 :                 if (!stmt) {
    4137               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_TOUGH_BREAK);
    4138               0 :                     return NULL;
    4139                 :                 }
    4140           79611 :                 if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH)
    4141           52974 :                     break;
    4142                 :             }
    4143                 :         }
    4144           53082 :         break;
    4145                 :       }
    4146                 : 
    4147                 :       case TOK_CONTINUE:
    4148                 :       {
    4149           38621 :         TokenPtr begin = tokenStream.currentToken().pos.begin;
    4150                 :         PropertyName *label;
    4151           38621 :         if (!MatchLabel(context, &tokenStream, &label))
    4152               0 :             return NULL;
    4153           38621 :         TokenPtr end = tokenStream.currentToken().pos.begin;
    4154           38621 :         pn = new_<ContinueStatement>(label, begin, end);
    4155           38621 :         if (!pn)
    4156               0 :             return NULL;
    4157           38621 :         StmtInfo *stmt = tc->topStmt;
    4158           38621 :         if (label) {
    4159             255 :             for (StmtInfo *stmt2 = NULL; ; stmt = stmt->down) {
    4160             255 :                 if (!stmt) {
    4161               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND);
    4162               0 :                     return NULL;
    4163                 :                 }
    4164             255 :                 if (stmt->type == STMT_LABEL) {
    4165              46 :                     if (stmt->label == label) {
    4166              46 :                         if (!stmt2 || !STMT_IS_LOOP(stmt2)) {
    4167               0 :                             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_CONTINUE);
    4168               0 :                             return NULL;
    4169                 :                         }
    4170                 :                         break;
    4171                 :                     }
    4172                 :                 } else {
    4173             209 :                     stmt2 = stmt;
    4174                 :                 }
    4175                 :             }
    4176                 :         } else {
    4177          128113 :             for (; ; stmt = stmt->down) {
    4178          166688 :                 if (!stmt) {
    4179               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_CONTINUE);
    4180               0 :                     return NULL;
    4181                 :                 }
    4182          166688 :                 if (STMT_IS_LOOP(stmt))
    4183           38575 :                     break;
    4184                 :             }
    4185                 :         }
    4186           38621 :         break;
    4187                 :       }
    4188                 : 
    4189                 :       case TOK_WITH:
    4190             630 :         return withStatement();
    4191                 : 
    4192                 :       case TOK_VAR:
    4193          524233 :         pn = variables(PNK_VAR);
    4194          524233 :         if (!pn)
    4195               9 :             return NULL;
    4196                 : 
    4197                 :         /* Tell js_EmitTree to generate a final POP. */
    4198          524224 :         pn->pn_xflags |= PNX_POPVAR;
    4199          524224 :         break;
    4200                 : 
    4201                 :       case TOK_CONST:
    4202          168769 :         pn = variables(PNK_CONST);
    4203          168769 :         if (!pn)
    4204               0 :             return NULL;
    4205                 : 
    4206                 :         /* Tell js_EmitTree to generate a final POP. */
    4207          168769 :         pn->pn_xflags |= PNX_POPVAR;
    4208          168769 :         break;
    4209                 : 
    4210                 : #if JS_HAS_BLOCK_SCOPE
    4211                 :       case TOK_LET:
    4212          518050 :         return letStatement();
    4213                 : #endif /* JS_HAS_BLOCK_SCOPE */
    4214                 : 
    4215                 :       case TOK_RETURN:
    4216          633724 :         pn = returnOrYield(false);
    4217          633724 :         if (!pn)
    4218               0 :             return NULL;
    4219          633724 :         break;
    4220                 : 
    4221                 :       case TOK_LC:
    4222                 :       {
    4223                 :         unsigned oldflags;
    4224                 : 
    4225          857093 :         oldflags = tc->flags;
    4226          857093 :         tc->flags = oldflags & ~TCF_HAS_FUNCTION_STMT;
    4227                 :         StmtInfo stmtInfo;
    4228          857093 :         if (!PushBlocklikeStatement(&stmtInfo, STMT_BLOCK, tc))
    4229               0 :             return NULL;
    4230          857093 :         pn = statements();
    4231          857093 :         if (!pn)
    4232              36 :             return NULL;
    4233                 : 
    4234          857057 :         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND);
    4235          857057 :         PopStatement(tc);
    4236                 : 
    4237                 :         /*
    4238                 :          * If we contain a function statement and our container is top-level
    4239                 :          * or another block, flag pn to preserve braces when decompiling.
    4240                 :          */
    4241          858684 :         if ((tc->flags & TCF_HAS_FUNCTION_STMT) &&
    4242            1627 :             (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)) {
    4243             161 :             pn->pn_xflags |= PNX_NEEDBRACES;
    4244                 :         }
    4245          857057 :         tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_RETURN_FLAGS));
    4246          857057 :         return pn;
    4247                 :       }
    4248                 : 
    4249                 :       case TOK_SEMI:
    4250            4839 :         pn = UnaryNode::create(PNK_SEMI, tc);
    4251            4839 :         if (!pn)
    4252               0 :             return NULL;
    4253            4839 :         return pn;
    4254                 : 
    4255                 :       case TOK_DEBUGGER:
    4256            4397 :         pn = tc->parser->new_<DebuggerStatement>(tokenStream.currentToken().pos);
    4257            4397 :         if (!pn)
    4258               0 :             return NULL;
    4259            4397 :         tc->flags |= TCF_FUN_HEAVYWEIGHT;
    4260            4397 :         break;
    4261                 : 
    4262                 : #if JS_HAS_XML_SUPPORT
    4263                 :       case TOK_DEFAULT:
    4264                 :       {
    4265               9 :         if (tc->inStrictMode())
    4266               0 :             return expressionStatement();
    4267                 : 
    4268               9 :         pn = UnaryNode::create(PNK_DEFXMLNS, tc);
    4269               9 :         if (!pn)
    4270               0 :             return NULL;
    4271              45 :         if (!tokenStream.matchToken(TOK_NAME) ||
    4272               9 :             tokenStream.currentToken().name() != context->runtime->atomState.xmlAtom ||
    4273               9 :             !tokenStream.matchToken(TOK_NAME) ||
    4274               9 :             tokenStream.currentToken().name() != context->runtime->atomState.namespaceAtom ||
    4275               9 :             !tokenStream.matchToken(TOK_ASSIGN))
    4276                 :         {
    4277               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_DEFAULT_XML_NAMESPACE);
    4278               0 :             return NULL;
    4279                 :         }
    4280                 : 
    4281               9 :         JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NOP);
    4282                 : 
    4283                 :         /* Is this an E4X dagger I see before me? */
    4284               9 :         tc->flags |= TCF_FUN_HEAVYWEIGHT;
    4285               9 :         ParseNode *pn2 = expr();
    4286               9 :         if (!pn2)
    4287               0 :             return NULL;
    4288               9 :         pn->setOp(JSOP_DEFXMLNS);
    4289               9 :         pn->pn_pos.end = pn2->pn_pos.end;
    4290               9 :         pn->pn_kid = pn2;
    4291               9 :         break;
    4292                 :       }
    4293                 : #endif
    4294                 : 
    4295                 :       case TOK_ERROR:
    4296               0 :         return NULL;
    4297                 : 
    4298                 :       default:
    4299         6471051 :         return expressionStatement();
    4300                 :     }
    4301                 : 
    4302                 :     /* Check termination of this primitive statement. */
    4303         1546608 :     return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL;
    4304                 : }
    4305                 : 
    4306                 : /*
    4307                 :  * The 'blockObj' parameter is non-null when parsing the 'vars' in a let
    4308                 :  * expression, block statement, non-top-level let declaration in statement
    4309                 :  * context, and the let-initializer of a for-statement.
    4310                 :  */
    4311                 : ParseNode *
    4312         1315578 : Parser::variables(ParseNodeKind kind, StaticBlockObject *blockObj, VarContext varContext)
    4313                 : {
    4314                 :     /*
    4315                 :      * The four options here are:
    4316                 :      * - PNK_VAR:   We're parsing var declarations.
    4317                 :      * - PNK_CONST: We're parsing const declarations.
    4318                 :      * - PNK_LET:   We are parsing a let declaration.
    4319                 :      * - PNK_LP:    We are parsing the head of a let block.
    4320                 :      */
    4321         1315578 :     JS_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || kind == PNK_LP);
    4322                 : 
    4323         1315578 :     ParseNode *pn = ListNode::create(kind, tc);
    4324         1315578 :     if (!pn)
    4325               0 :         return NULL;
    4326                 : 
    4327         1315578 :     pn->setOp(blockObj ? JSOP_NOP : kind == PNK_VAR ? JSOP_DEFVAR : JSOP_DEFCONST);
    4328         1315578 :     pn->makeEmpty();
    4329                 : 
    4330                 :     /*
    4331                 :      * SpiderMonkey const is really "write once per initialization evaluation"
    4332                 :      * var, whereas let is block scoped. ES-Harmony wants block-scoped const so
    4333                 :      * this code will change soon.
    4334                 :      */
    4335         1315578 :     BindData data;
    4336         1315578 :     if (blockObj)
    4337          283953 :         data.initLet(varContext, *blockObj, JSMSG_TOO_MANY_LOCALS);
    4338                 :     else
    4339         1031625 :         data.initVarOrConst(pn->getOp());
    4340                 : 
    4341                 :     ParseNode *pn2;
    4342         1636228 :     do {
    4343         1636462 :         TokenKind tt = tokenStream.getToken();
    4344                 : #if JS_HAS_DESTRUCTURING
    4345         1636462 :         if (tt == TOK_LB || tt == TOK_LC) {
    4346           15630 :             tc->flags |= TCF_DECL_DESTRUCTURING;
    4347           15630 :             pn2 = primaryExpr(tt, JS_FALSE);
    4348           15630 :             tc->flags &= ~TCF_DECL_DESTRUCTURING;
    4349           15630 :             if (!pn2)
    4350               0 :                 return NULL;
    4351                 : 
    4352           15630 :             if (!CheckDestructuring(context, &data, pn2, tc))
    4353             162 :                 return NULL;
    4354                 :             bool ignored;
    4355           15468 :             if ((tc->flags & TCF_IN_FOR_INIT) && matchInOrOf(&ignored)) {
    4356            2315 :                 tokenStream.ungetToken();
    4357            2315 :                 pn->append(pn2);
    4358            2315 :                 continue;
    4359                 :             }
    4360                 : 
    4361           13153 :             MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
    4362           13153 :             JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NOP);
    4363                 : 
    4364           13153 :             ParseNode *init = assignExpr();
    4365           13153 :             if (!init)
    4366               0 :                 return NULL;
    4367           13153 :             UndominateInitializers(pn2, init->pn_pos.end, tc);
    4368                 : 
    4369           13153 :             pn2 = ParseNode::newBinaryOrAppend(PNK_ASSIGN, JSOP_NOP, pn2, init, tc);
    4370           13153 :             if (!pn2)
    4371               0 :                 return NULL;
    4372           13153 :             pn->append(pn2);
    4373           13153 :             continue;
    4374                 :         }
    4375                 : #endif /* JS_HAS_DESTRUCTURING */
    4376                 : 
    4377         1620832 :         if (tt != TOK_NAME) {
    4378               9 :             if (tt != TOK_ERROR)
    4379               9 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NO_VARIABLE_NAME);
    4380               9 :             return NULL;
    4381                 :         }
    4382                 : 
    4383         1620823 :         PropertyName *name = tokenStream.currentToken().name();
    4384         1620823 :         pn2 = NewBindingNode(name, tc, blockObj, varContext);
    4385         1620823 :         if (!pn2)
    4386               0 :             return NULL;
    4387         1620823 :         if (data.op == JSOP_DEFCONST)
    4388          168764 :             pn2->pn_dflags |= PND_CONST;
    4389         1620823 :         data.pn = pn2;
    4390         1620823 :         if (!data.binder(context, &data, name, tc))
    4391              54 :             return NULL;
    4392         1620769 :         pn->append(pn2);
    4393                 : 
    4394         1620769 :         if (tokenStream.matchToken(TOK_ASSIGN)) {
    4395         1246952 :             JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NOP);
    4396                 : 
    4397         1246952 :             ParseNode *init = assignExpr();
    4398         1246952 :             if (!init)
    4399               9 :                 return NULL;
    4400                 : 
    4401         1246943 :             if (pn2->isUsed()) {
    4402            7511 :                 pn2 = MakeAssignment(pn2, init, tc);
    4403            7511 :                 if (!pn2)
    4404               0 :                     return NULL;
    4405                 :             } else {
    4406         1239432 :                 pn2->pn_expr = init;
    4407                 :             }
    4408                 : 
    4409         1246943 :             JS_ASSERT_IF(pn2->pn_dflags & PND_GVAR, !(pn2->pn_dflags & PND_BOUND));
    4410                 : 
    4411         1246943 :             pn2->setOp(pn2->isOp(JSOP_ARGUMENTS)
    4412                 :                        ? JSOP_SETNAME
    4413                 :                        : (pn2->pn_dflags & PND_BOUND)
    4414                 :                        ? JSOP_SETLOCAL
    4415                 :                        : (data.op == JSOP_DEFCONST)
    4416                 :                        ? JSOP_SETCONST
    4417         1246943 :                        : JSOP_SETNAME);
    4418                 : 
    4419         1246943 :             NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED);
    4420                 : 
    4421                 :             /* The declarator's position must include the initializer. */
    4422         1246943 :             pn2->pn_pos.end = init->pn_pos.end;
    4423                 : 
    4424         1246943 :             if (tc->inFunction() && name == context->runtime->atomState.argumentsAtom) {
    4425              27 :                 tc->noteArgumentsNameUse(pn2);
    4426              27 :                 if (!blockObj)
    4427              27 :                     tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
    4428                 :             }
    4429                 :         }
    4430         1636228 :     } while (tokenStream.matchToken(TOK_COMMA));
    4431                 : 
    4432         1315344 :     pn->pn_pos.end = pn->last()->pn_pos.end;
    4433         1315344 :     return pn;
    4434                 : }
    4435                 : 
    4436                 : ParseNode *
    4437        15848673 : Parser::expr()
    4438                 : {
    4439        15848673 :     ParseNode *pn = assignExpr();
    4440        15848673 :     if (pn && tokenStream.matchToken(TOK_COMMA)) {
    4441            2152 :         ParseNode *pn2 = ListNode::create(PNK_COMMA, tc);
    4442            2152 :         if (!pn2)
    4443               0 :             return NULL;
    4444            2152 :         pn2->pn_pos.begin = pn->pn_pos.begin;
    4445            2152 :         pn2->initList(pn);
    4446            2152 :         pn = pn2;
    4447            2663 :         do {
    4448                 : #if JS_HAS_GENERATORS
    4449            2663 :             pn2 = pn->last();
    4450            2663 :             if (pn2->isKind(PNK_YIELD) && !pn2->isInParens()) {
    4451               0 :                 reportErrorNumber(pn2, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
    4452               0 :                 return NULL;
    4453                 :             }
    4454                 : #endif
    4455            2663 :             pn2 = assignExpr();
    4456            2663 :             if (!pn2)
    4457               0 :                 return NULL;
    4458            2663 :             pn->append(pn2);
    4459            2663 :         } while (tokenStream.matchToken(TOK_COMMA));
    4460            2152 :         pn->pn_pos.end = pn->last()->pn_pos.end;
    4461                 :     }
    4462        15848673 :     return pn;
    4463                 : }
    4464                 : 
    4465                 : /*
    4466                 :  * For a number of the expression parsers we define an always-inlined version
    4467                 :  * and a never-inlined version (which just calls the always-inlined version).
    4468                 :  * Using the always-inlined version in the hot call-sites givs a ~5% parsing
    4469                 :  * speedup.  These macros help avoid some boilerplate code.
    4470                 :  */
    4471                 : #define BEGIN_EXPR_PARSER(name)                                               \
    4472                 :     JS_ALWAYS_INLINE ParseNode *                                              \
    4473                 :     Parser::name##i()
    4474                 : 
    4475                 : #define END_EXPR_PARSER(name)                                                 \
    4476                 :     JS_NEVER_INLINE ParseNode *                                               \
    4477                 :     Parser::name##n() {                                                       \
    4478                 :         return name##i();                                                     \
    4479                 :     }
    4480                 : 
    4481        34171194 : BEGIN_EXPR_PARSER(mulExpr1)
    4482                 : {
    4483        34171194 :     ParseNode *pn = unaryExpr();
    4484                 : 
    4485                 :     /*
    4486                 :      * Note: unlike addExpr1() et al, we use getToken() here instead of
    4487                 :      * isCurrentTokenType() because unaryExpr() doesn't leave the TokenStream
    4488                 :      * state one past the end of the unary expression.
    4489                 :      */
    4490                 :     TokenKind tt;
    4491        68364155 :     while (pn && ((tt = tokenStream.getToken()) == TOK_STAR || tt == TOK_DIV || tt == TOK_MOD)) {
    4492                 :         ParseNodeKind kind = (tt == TOK_STAR)
    4493                 :                              ? PNK_STAR
    4494                 :                              : (tt == TOK_DIV)
    4495                 :                              ? PNK_DIV
    4496           21767 :                              : PNK_MOD;
    4497           21767 :         JSOp op = tokenStream.currentToken().t_op;
    4498           21767 :         pn = ParseNode::newBinaryOrAppend(kind, op, pn, unaryExpr(), tc);
    4499                 :     }
    4500        34171194 :     return pn;
    4501                 : }
    4502         2332460 : END_EXPR_PARSER(mulExpr1)
    4503                 : 
    4504        31838734 : BEGIN_EXPR_PARSER(addExpr1)
    4505                 : {
    4506        31838734 :     ParseNode *pn = mulExpr1i();
    4507        66009928 :     while (pn && tokenStream.isCurrentTokenType(TOK_PLUS, TOK_MINUS)) {
    4508         2332460 :         TokenKind tt = tokenStream.currentToken().type;
    4509         2332460 :         JSOp op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB;
    4510         2332460 :         ParseNodeKind kind = (tt == TOK_PLUS) ? PNK_ADD : PNK_SUB;
    4511         2332460 :         pn = ParseNode::newBinaryOrAppend(kind, op, pn, mulExpr1n(), tc);
    4512                 :     }
    4513        31838734 :     return pn;
    4514                 : }
    4515            7976 : END_EXPR_PARSER(addExpr1)
    4516                 : 
    4517                 : inline ParseNodeKind
    4518            7976 : ShiftTokenToParseNodeKind(const Token &token)
    4519                 : {
    4520            7976 :     switch (token.type) {
    4521                 :       case TOK_LSH:
    4522            2687 :         return PNK_LSH;
    4523                 :       case TOK_RSH:
    4524            3855 :         return PNK_RSH;
    4525                 :       default:
    4526            1434 :         JS_ASSERT(token.type == TOK_URSH);
    4527            1434 :         return PNK_URSH;
    4528                 :     }
    4529                 : }
    4530                 : 
    4531        31830758 : BEGIN_EXPR_PARSER(shiftExpr1)
    4532                 : {
    4533        31830758 :     ParseNode *left = addExpr1i();
    4534        63669492 :     while (left && tokenStream.isCurrentTokenShift()) {
    4535            7976 :         ParseNodeKind kind = ShiftTokenToParseNodeKind(tokenStream.currentToken());
    4536            7976 :         JSOp op = tokenStream.currentToken().t_op;
    4537            7976 :         ParseNode *right = addExpr1n();
    4538            7976 :         if (!right)
    4539               0 :             return NULL;
    4540            7976 :         left = tc->parser->new_<BinaryNode>(kind, op, left, right);
    4541                 :     }
    4542        31830758 :     return left;
    4543                 : }
    4544          300183 : END_EXPR_PARSER(shiftExpr1)
    4545                 : 
    4546                 : inline ParseNodeKind
    4547          300183 : RelationalTokenToParseNodeKind(const Token &token)
    4548                 : {
    4549          300183 :     switch (token.type) {
    4550                 :       case TOK_IN:
    4551          102423 :         return PNK_IN;
    4552                 :       case TOK_INSTANCEOF:
    4553           38327 :         return PNK_INSTANCEOF;
    4554                 :       case TOK_LT:
    4555           92980 :         return PNK_LT;
    4556                 :       case TOK_LE:
    4557            9864 :         return PNK_LE;
    4558                 :       case TOK_GT:
    4559           40897 :         return PNK_GT;
    4560                 :       default:
    4561           15692 :         JS_ASSERT(token.type == TOK_GE);
    4562           15692 :         return PNK_GE;
    4563                 :     }
    4564                 : }
    4565                 : 
    4566        31530575 : BEGIN_EXPR_PARSER(relExpr1)
    4567                 : {
    4568        31530575 :     unsigned inForInitFlag = tc->flags & TCF_IN_FOR_INIT;
    4569                 : 
    4570                 :     /*
    4571                 :      * Uses of the in operator in shiftExprs are always unambiguous,
    4572                 :      * so unset the flag that prohibits recognizing it.
    4573                 :      */
    4574        31530575 :     tc->flags &= ~TCF_IN_FOR_INIT;
    4575                 : 
    4576        31530575 :     ParseNode *pn = shiftExpr1i();
    4577       158351844 :     while (pn &&
    4578        31830518 :            (tokenStream.isCurrentTokenRelational() ||
    4579                 :             /*
    4580                 :              * Recognize the 'in' token as an operator only if we're not
    4581                 :              * currently in the init expr of a for loop.
    4582                 :              */
    4583        31591331 :             (inForInitFlag == 0 && tokenStream.isCurrentTokenType(TOK_IN)) ||
    4584        31568662 :             tokenStream.isCurrentTokenType(TOK_INSTANCEOF))) {
    4585          300183 :         ParseNodeKind kind = RelationalTokenToParseNodeKind(tokenStream.currentToken());
    4586          300183 :         JSOp op = tokenStream.currentToken().t_op;
    4587          300183 :         pn = ParseNode::newBinaryOrAppend(kind, op, pn, shiftExpr1n(), tc);
    4588                 :     }
    4589                 :     /* Restore previous state of inForInit flag. */
    4590        31530575 :     tc->flags |= inForInitFlag;
    4591                 : 
    4592        31530575 :     return pn;
    4593                 : }
    4594          392403 : END_EXPR_PARSER(relExpr1)
    4595                 : 
    4596                 : inline ParseNodeKind
    4597          392403 : EqualityTokenToParseNodeKind(const Token &token)
    4598                 : {
    4599          392403 :     switch (token.type) {
    4600                 :       case TOK_STRICTEQ:
    4601           41605 :         return PNK_STRICTEQ;
    4602                 :       case TOK_EQ:
    4603          217741 :         return PNK_EQ;
    4604                 :       case TOK_STRICTNE:
    4605           21207 :         return PNK_STRICTNE;
    4606                 :       default:
    4607          111850 :         JS_ASSERT(token.type == TOK_NE);
    4608          111850 :         return PNK_NE;
    4609                 :     }
    4610                 : }
    4611                 : 
    4612        31138172 : BEGIN_EXPR_PARSER(eqExpr1)
    4613                 : {
    4614        31138172 :     ParseNode *left = relExpr1i();
    4615        62668747 :     while (left && tokenStream.isCurrentTokenEquality()) {
    4616          392403 :         ParseNodeKind kind = EqualityTokenToParseNodeKind(tokenStream.currentToken());
    4617          392403 :         JSOp op = tokenStream.currentToken().t_op;
    4618          392403 :         ParseNode *right = relExpr1n();
    4619          392403 :         if (!right)
    4620               0 :             return NULL;
    4621          392403 :         left = tc->parser->new_<BinaryNode>(kind, op, left, right);
    4622                 :     }
    4623        31138172 :     return left;
    4624                 : }
    4625           10661 : END_EXPR_PARSER(eqExpr1)
    4626                 : 
    4627        31127511 : BEGIN_EXPR_PARSER(bitAndExpr1)
    4628                 : {
    4629        31127511 :     ParseNode *pn = eqExpr1i();
    4630        62265683 :     while (pn && tokenStream.isCurrentTokenType(TOK_BITAND))
    4631           10661 :         pn = ParseNode::newBinaryOrAppend(PNK_BITAND, JSOP_BITAND, pn, eqExpr1n(), tc);
    4632        31127511 :     return pn;
    4633                 : }
    4634            2601 : END_EXPR_PARSER(bitAndExpr1)
    4635                 : 
    4636        31124910 : BEGIN_EXPR_PARSER(bitXorExpr1)
    4637                 : {
    4638        31124910 :     ParseNode *pn = bitAndExpr1i();
    4639        62252421 :     while (pn && tokenStream.isCurrentTokenType(TOK_BITXOR))
    4640            2601 :         pn = ParseNode::newBinaryOrAppend(PNK_BITXOR, JSOP_BITXOR, pn, bitAndExpr1n(), tc);
    4641        31124910 :     return pn;
    4642                 : }
    4643           30305 : END_EXPR_PARSER(bitXorExpr1)
    4644                 : 
    4645        31094605 : BEGIN_EXPR_PARSER(bitOrExpr1)
    4646                 : {
    4647        31094605 :     ParseNode *pn = bitXorExpr1i();
    4648        62219515 :     while (pn && tokenStream.isCurrentTokenType(TOK_BITOR))
    4649           30305 :         pn = ParseNode::newBinaryOrAppend(PNK_BITOR, JSOP_BITOR, pn, bitXorExpr1n(), tc);
    4650        31094605 :     return pn;
    4651                 : }
    4652          152461 : END_EXPR_PARSER(bitOrExpr1)
    4653                 : 
    4654        30942144 : BEGIN_EXPR_PARSER(andExpr1)
    4655                 : {
    4656        30942144 :     ParseNode *pn = bitOrExpr1i();
    4657        62036749 :     while (pn && tokenStream.isCurrentTokenType(TOK_AND))
    4658          152461 :         pn = ParseNode::newBinaryOrAppend(PNK_AND, JSOP_AND, pn, bitOrExpr1n(), tc);
    4659        30942144 :     return pn;
    4660                 : }
    4661          120345 : END_EXPR_PARSER(andExpr1)
    4662                 : 
    4663                 : JS_ALWAYS_INLINE ParseNode *
    4664        30821799 : Parser::orExpr1()
    4665                 : {
    4666        30821799 :     ParseNode *pn = andExpr1i();
    4667        61763943 :     while (pn && tokenStream.isCurrentTokenType(TOK_OR))
    4668          120345 :         pn = ParseNode::newBinaryOrAppend(PNK_OR, JSOP_OR, pn, andExpr1n(), tc);
    4669        30821799 :     return pn;
    4670                 : }
    4671                 : 
    4672                 : JS_ALWAYS_INLINE ParseNode *
    4673        30821799 : Parser::condExpr1()
    4674                 : {
    4675        30821799 :     ParseNode *condition = orExpr1();
    4676        30821799 :     if (!condition || !tokenStream.isCurrentTokenType(TOK_HOOK))
    4677        30753428 :         return condition;
    4678                 : 
    4679                 :     /*
    4680                 :      * Always accept the 'in' operator in the middle clause of a ternary,
    4681                 :      * where it's unambiguous, even if we might be parsing the init of a
    4682                 :      * for statement.
    4683                 :      */
    4684           68371 :     unsigned oldflags = tc->flags;
    4685           68371 :     tc->flags &= ~TCF_IN_FOR_INIT;
    4686           68371 :     ParseNode *thenExpr = assignExpr();
    4687           68371 :     tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
    4688           68371 :     if (!thenExpr)
    4689               0 :         return NULL;
    4690                 : 
    4691           68371 :     MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
    4692                 : 
    4693           68371 :     ParseNode *elseExpr = assignExpr();
    4694           68371 :     if (!elseExpr)
    4695               0 :         return NULL;
    4696                 : 
    4697           68371 :     tokenStream.getToken(); /* read one token past the end */
    4698           68371 :     return new_<ConditionalExpression>(condition, thenExpr, elseExpr);
    4699                 : }
    4700                 : 
    4701                 : bool
    4702         3021959 : Parser::setAssignmentLhsOps(ParseNode *pn, JSOp op)
    4703                 : {
    4704         3021959 :     switch (pn->getKind()) {
    4705                 :       case PNK_NAME:
    4706          660140 :         if (!CheckStrictAssignment(context, tc, pn))
    4707               0 :             return false;
    4708          660140 :         pn->setOp(pn->isOp(JSOP_GETLOCAL) ? JSOP_SETLOCAL : JSOP_SETNAME);
    4709          660140 :         NoteLValue(context, pn, tc);
    4710          660140 :         break;
    4711                 :       case PNK_DOT:
    4712          648244 :         pn->setOp(JSOP_SETPROP);
    4713          648244 :         break;
    4714                 :       case PNK_LB:
    4715         1710806 :         pn->setOp(JSOP_SETELEM);
    4716         1710806 :         break;
    4717                 : #if JS_HAS_DESTRUCTURING
    4718                 :       case PNK_RB:
    4719                 :       case PNK_RC:
    4720            2724 :         if (op != JSOP_NOP) {
    4721               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_DESTRUCT_ASS);
    4722               0 :             return false;
    4723                 :         }
    4724            2724 :         if (!CheckDestructuring(context, NULL, pn, tc))
    4725               0 :             return false;
    4726            2724 :         break;
    4727                 : #endif
    4728                 :       case PNK_LP:
    4729              18 :         if (!MakeSetCall(context, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS))
    4730               0 :             return false;
    4731              18 :         break;
    4732                 : #if JS_HAS_XML_SUPPORT
    4733                 :       case PNK_XMLUNARY:
    4734              18 :         JS_ASSERT(pn->isOp(JSOP_XMLNAME));
    4735              18 :         pn->setOp(JSOP_SETXMLNAME);
    4736              18 :         break;
    4737                 : #endif
    4738                 :       default:
    4739               9 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS);
    4740               9 :         return false;
    4741                 :     }
    4742         3021950 :     return true;
    4743                 : }
    4744                 : 
    4745                 : ParseNode *
    4746        30826005 : Parser::assignExpr()
    4747                 : {
    4748        30826005 :     JS_CHECK_RECURSION(context, return NULL);
    4749                 : 
    4750                 : #if JS_HAS_GENERATORS
    4751        30826005 :     if (tokenStream.matchToken(TOK_YIELD, TSF_OPERAND))
    4752            4206 :         return returnOrYield(true);
    4753                 : #endif
    4754                 : 
    4755        30821799 :     ParseNode *lhs = condExpr1();
    4756        30821799 :     if (!lhs)
    4757             240 :         return NULL;
    4758                 : 
    4759                 :     ParseNodeKind kind;
    4760        30821559 :     switch (tokenStream.currentToken().type) {
    4761         2937739 :       case TOK_ASSIGN:       kind = PNK_ASSIGN;       break;
    4762           66722 :       case TOK_ADDASSIGN:    kind = PNK_ADDASSIGN;    break;
    4763            1509 :       case TOK_SUBASSIGN:    kind = PNK_SUBASSIGN;    break;
    4764           12310 :       case TOK_BITORASSIGN:  kind = PNK_BITORASSIGN;  break;
    4765              54 :       case TOK_BITXORASSIGN: kind = PNK_BITXORASSIGN; break;
    4766             186 :       case TOK_BITANDASSIGN: kind = PNK_BITANDASSIGN; break;
    4767              18 :       case TOK_LSHASSIGN:    kind = PNK_LSHASSIGN;    break;
    4768             158 :       case TOK_RSHASSIGN:    kind = PNK_RSHASSIGN;    break;
    4769               0 :       case TOK_URSHASSIGN:   kind = PNK_URSHASSIGN;   break;
    4770             439 :       case TOK_MULASSIGN:    kind = PNK_MULASSIGN;    break;
    4771              78 :       case TOK_DIVASSIGN:    kind = PNK_DIVASSIGN;    break;
    4772              45 :       case TOK_MODASSIGN:    kind = PNK_MODASSIGN;    break;
    4773                 :       default:
    4774        27802301 :         JS_ASSERT(!tokenStream.isCurrentTokenAssignment());
    4775        27802301 :         tokenStream.ungetToken();
    4776        27802301 :         return lhs;
    4777                 :     }
    4778                 : 
    4779         3019258 :     JSOp op = tokenStream.currentToken().t_op;
    4780         3019258 :     if (!setAssignmentLhsOps(lhs, op))
    4781               9 :         return NULL;
    4782                 : 
    4783         3019249 :     ParseNode *rhs = assignExpr();
    4784         3019249 :     if (!rhs)
    4785               0 :         return NULL;
    4786         3019249 :     if (lhs->isKind(PNK_NAME) && lhs->isUsed()) {
    4787          657614 :         Definition *dn = lhs->pn_lexdef;
    4788                 : 
    4789                 :         /*
    4790                 :          * If the definition is not flagged as assigned, we must have imputed
    4791                 :          * the initialized flag to it, to optimize for flat closures. But that
    4792                 :          * optimization uses source coordinates to check dominance relations,
    4793                 :          * so we must extend the end of the definition to cover the right-hand
    4794                 :          * side of this assignment, i.e., the initializer.
    4795                 :          */
    4796          657614 :         if (!dn->isAssigned()) {
    4797            2802 :             JS_ASSERT(dn->isInitialized());
    4798            2802 :             dn->pn_pos.end = rhs->pn_pos.end;
    4799                 :         }
    4800                 :     }
    4801                 : 
    4802         3019249 :     return ParseNode::newBinaryOrAppend(kind, op, lhs, rhs, tc);
    4803                 : }
    4804                 : 
    4805                 : static bool
    4806         1737386 : SetLvalKid(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn, ParseNode *kid,
    4807                 :            const char *name)
    4808                 : {
    4809         8297718 :     if (!kid->isKind(PNK_NAME) &&
    4810         1643743 :         !kid->isKind(PNK_DOT) &&
    4811         1638869 :         (!kid->isKind(PNK_LP) ||
    4812               9 :          (!kid->isOp(JSOP_CALL) && !kid->isOp(JSOP_EVAL) &&
    4813               0 :           !kid->isOp(JSOP_FUNCALL) && !kid->isOp(JSOP_FUNAPPLY))) &&
    4814                 : #if JS_HAS_XML_SUPPORT
    4815         1638860 :         !kid->isKind(PNK_XMLUNARY) &&
    4816                 : #endif
    4817         1638851 :         !kid->isKind(PNK_LB))
    4818                 :     {
    4819               0 :         ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_OPERAND, name);
    4820               0 :         return false;
    4821                 :     }
    4822         1737386 :     if (!CheckStrictAssignment(cx, tc, kid))
    4823               0 :         return false;
    4824         1737386 :     pn->pn_kid = kid;
    4825         1737386 :     return true;
    4826                 : }
    4827                 : 
    4828                 : static const char incop_name_str[][10] = {"increment", "decrement"};
    4829                 : 
    4830                 : static JSBool
    4831         1737386 : SetIncOpKid(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn, ParseNode *kid,
    4832                 :             TokenKind tt, bool preorder)
    4833                 : {
    4834                 :     JSOp op;
    4835                 : 
    4836         1737386 :     if (!SetLvalKid(cx, ts, tc, pn, kid, incop_name_str[tt == TOK_DEC]))
    4837               0 :         return false;
    4838         1737386 :     switch (kid->getKind()) {
    4839                 :       case PNK_NAME:
    4840                 :         op = (tt == TOK_INC)
    4841                 :              ? (preorder ? JSOP_INCNAME : JSOP_NAMEINC)
    4842           93643 :              : (preorder ? JSOP_DECNAME : JSOP_NAMEDEC);
    4843           93643 :         NoteLValue(cx, kid, tc);
    4844           93643 :         break;
    4845                 : 
    4846                 :       case PNK_DOT:
    4847                 :         op = (tt == TOK_INC)
    4848                 :              ? (preorder ? JSOP_INCPROP : JSOP_PROPINC)
    4849            4874 :              : (preorder ? JSOP_DECPROP : JSOP_PROPDEC);
    4850            4874 :         break;
    4851                 : 
    4852                 :       case PNK_LP:
    4853               9 :         if (!MakeSetCall(cx, kid, tc, JSMSG_BAD_INCOP_OPERAND))
    4854               0 :             return JS_FALSE;
    4855                 :         /* FALL THROUGH */
    4856                 : #if JS_HAS_XML_SUPPORT
    4857                 :       case PNK_XMLUNARY:
    4858              18 :         if (kid->isOp(JSOP_XMLNAME))
    4859               9 :             kid->setOp(JSOP_SETXMLNAME);
    4860                 :         /* FALL THROUGH */
    4861                 : #endif
    4862                 :       case PNK_LB:
    4863                 :         op = (tt == TOK_INC)
    4864                 :              ? (preorder ? JSOP_INCELEM : JSOP_ELEMINC)
    4865         1638869 :              : (preorder ? JSOP_DECELEM : JSOP_ELEMDEC);
    4866         1638869 :         break;
    4867                 : 
    4868                 :       default:
    4869               0 :         JS_ASSERT(0);
    4870               0 :         op = JSOP_NOP;
    4871                 :     }
    4872         1737386 :     pn->setOp(op);
    4873         1737386 :     return JS_TRUE;
    4874                 : }
    4875                 : 
    4876                 : ParseNode *
    4877          490820 : Parser::unaryOpExpr(ParseNodeKind kind, JSOp op)
    4878                 : {
    4879          490820 :     TokenPtr begin = tokenStream.currentToken().pos.begin;
    4880          490820 :     ParseNode *kid = unaryExpr();
    4881          490820 :     if (!kid)
    4882               4 :         return NULL;
    4883          490816 :     return new_<UnaryNode>(kind, op, TokenPos::make(begin, kid->pn_pos.end), kid);
    4884                 : }
    4885                 : 
    4886                 : ParseNode *
    4887        34721275 : Parser::unaryExpr()
    4888                 : {
    4889                 :     ParseNode *pn, *pn2;
    4890                 : 
    4891        34721275 :     JS_CHECK_RECURSION(context, return NULL);
    4892                 : 
    4893        34721275 :     switch (TokenKind tt = tokenStream.getToken(TSF_OPERAND)) {
    4894                 :       case TOK_TYPEOF:
    4895           18113 :         return unaryOpExpr(PNK_TYPEOF, JSOP_TYPEOF);
    4896                 :       case TOK_VOID:
    4897            1206 :         return unaryOpExpr(PNK_VOID, JSOP_VOID);
    4898                 :       case TOK_NOT:
    4899          381778 :         return unaryOpExpr(PNK_NOT, JSOP_NOT);
    4900                 :       case TOK_BITNOT:
    4901             285 :         return unaryOpExpr(PNK_BITNOT, JSOP_BITNOT);
    4902                 :       case TOK_PLUS:
    4903             704 :         return unaryOpExpr(PNK_POS, JSOP_POS);
    4904                 :       case TOK_MINUS:
    4905           88734 :         return unaryOpExpr(PNK_NEG, JSOP_NEG);
    4906                 : 
    4907                 :       case TOK_INC:
    4908                 :       case TOK_DEC:
    4909           28517 :         pn = UnaryNode::create((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT, tc);
    4910           28517 :         if (!pn)
    4911               0 :             return NULL;
    4912           28517 :         pn2 = memberExpr(JS_TRUE);
    4913           28517 :         if (!pn2)
    4914               0 :             return NULL;
    4915           28517 :         if (!SetIncOpKid(context, &tokenStream, tc, pn, pn2, tt, true))
    4916               0 :             return NULL;
    4917           28517 :         pn->pn_pos.end = pn2->pn_pos.end;
    4918           28517 :         break;
    4919                 : 
    4920                 :       case TOK_DELETE:
    4921                 :       {
    4922           37494 :         pn = UnaryNode::create(PNK_DELETE, tc);
    4923           37494 :         if (!pn)
    4924               0 :             return NULL;
    4925           37494 :         pn2 = unaryExpr();
    4926           37494 :         if (!pn2)
    4927               0 :             return NULL;
    4928           37494 :         pn->pn_pos.end = pn2->pn_pos.end;
    4929                 : 
    4930                 :         /*
    4931                 :          * Under ECMA3, deleting any unary expression is valid -- it simply
    4932                 :          * returns true. Here we fold constants before checking for a call
    4933                 :          * expression, in order to rule out delete of a generator expression.
    4934                 :          */
    4935           37494 :         if (foldConstants && !FoldConstants(context, pn2, tc))
    4936               0 :             return NULL;
    4937           37494 :         switch (pn2->getKind()) {
    4938                 :           case PNK_LP:
    4939               0 :             if (!(pn2->pn_xflags & PNX_SETCALL)) {
    4940                 :                 /*
    4941                 :                  * Call MakeSetCall to check for errors, but clear PNX_SETCALL
    4942                 :                  * because the optimizer will eliminate the useless delete.
    4943                 :                  */
    4944               0 :                 if (!MakeSetCall(context, pn2, tc, JSMSG_BAD_DELETE_OPERAND))
    4945               0 :                     return NULL;
    4946               0 :                 pn2->pn_xflags &= ~PNX_SETCALL;
    4947                 :             }
    4948               0 :             break;
    4949                 :           case PNK_NAME:
    4950             491 :             if (!ReportStrictModeError(context, &tokenStream, tc, pn,
    4951             491 :                                        JSMSG_DEPRECATED_DELETE_OPERAND)) {
    4952               0 :                 return NULL;
    4953                 :             }
    4954             491 :             pn2->setOp(JSOP_DELNAME);
    4955             491 :             if (pn2->pn_atom == context->runtime->atomState.argumentsAtom) {
    4956               0 :                 tc->flags |= TCF_FUN_HEAVYWEIGHT;
    4957               0 :                 tc->countArgumentsUse(pn2);
    4958                 :             }
    4959             491 :             break;
    4960                 :           default:;
    4961                 :         }
    4962           37494 :         pn->pn_kid = pn2;
    4963           37494 :         break;
    4964                 :       }
    4965                 :       case TOK_ERROR:
    4966               0 :         return NULL;
    4967                 : 
    4968                 :       default:
    4969        34164444 :         tokenStream.ungetToken();
    4970        34164444 :         pn = memberExpr(JS_TRUE);
    4971        34164444 :         if (!pn)
    4972             240 :             return NULL;
    4973                 : 
    4974                 :         /* Don't look across a newline boundary for a postfix incop. */
    4975        34164204 :         if (tokenStream.onCurrentLine(pn->pn_pos)) {
    4976        33937770 :             tt = tokenStream.peekTokenSameLine(TSF_OPERAND);
    4977        33937770 :             if (tt == TOK_INC || tt == TOK_DEC) {
    4978         1708869 :                 tokenStream.consumeKnownToken(tt);
    4979         1708869 :                 pn2 = UnaryNode::create((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, tc);
    4980         1708869 :                 if (!pn2)
    4981               0 :                     return NULL;
    4982         1708869 :                 if (!SetIncOpKid(context, &tokenStream, tc, pn2, pn, tt, false))
    4983               0 :                     return NULL;
    4984         1708869 :                 pn2->pn_pos.begin = pn->pn_pos.begin;
    4985         1708869 :                 pn = pn2;
    4986                 :             }
    4987                 :         }
    4988        34164204 :         break;
    4989                 :     }
    4990        34230215 :     return pn;
    4991                 : }
    4992                 : 
    4993                 : #if JS_HAS_GENERATORS
    4994                 : 
    4995                 : /*
    4996                 :  * A dedicated helper for transplanting the comprehension expression E in
    4997                 :  *
    4998                 :  *   [E for (V in I)]   // array comprehension
    4999                 :  *   (E for (V in I))   // generator expression
    5000                 :  *
    5001                 :  * from its initial location in the AST, on the left of the 'for', to its final
    5002                 :  * position on the right. To avoid a separate pass we do this by adjusting the
    5003                 :  * blockids and name binding links that were established when E was parsed.
    5004                 :  *
    5005                 :  * A generator expression desugars like so:
    5006                 :  *
    5007                 :  *   (E for (V in I)) => (function () { for (var V in I) yield E; })()
    5008                 :  *
    5009                 :  * so the transplanter must adjust static level as well as blockid. E's source
    5010                 :  * coordinates in root->pn_pos are critical to deciding which binding links to
    5011                 :  * preserve and which to cut.
    5012                 :  *
    5013                 :  * NB: This is not a general tree transplanter -- it knows in particular that
    5014                 :  * the one or more bindings induced by V have not yet been created.
    5015                 :  */
    5016                 : class CompExprTransplanter {
    5017                 :     ParseNode       *root;
    5018                 :     TreeContext     *tc;
    5019                 :     bool            genexp;
    5020                 :     unsigned           adjust;
    5021                 :     unsigned           funcLevel;
    5022                 : 
    5023                 :   public:
    5024           13071 :     CompExprTransplanter(ParseNode *pn, TreeContext *tc, bool ge, unsigned adj)
    5025           13071 :       : root(pn), tc(tc), genexp(ge), adjust(adj), funcLevel(0)
    5026                 :     {
    5027           13071 :     }
    5028                 : 
    5029                 :     bool transplant(ParseNode *pn);
    5030                 : };
    5031                 : 
    5032                 : /*
    5033                 :  * A helper for lazily checking for the presence of illegal |yield| or |arguments|
    5034                 :  * tokens inside of generator expressions. This must be done lazily since we don't
    5035                 :  * know whether we're in a generator expression until we see the "for" token after
    5036                 :  * we've already parsed the body expression.
    5037                 :  *
    5038                 :  * Use in any context which may turn out to be inside a generator expression. This
    5039                 :  * includes parenthesized expressions and argument lists, and it includes the tail
    5040                 :  * of generator expressions.
    5041                 :  *
    5042                 :  * The guard will keep track of any |yield| or |arguments| tokens that occur while
    5043                 :  * parsing the body. As soon as the parser reaches the end of the body expression,
    5044                 :  * call endBody() to reset the context's state, and then immediately call:
    5045                 :  *
    5046                 :  * - checkValidBody() if this *did* turn out to be a generator expression
    5047                 :  * - maybeNoteGenerator() if this *did not* turn out to be a generator expression
    5048                 :  */
    5049                 : class GenexpGuard {
    5050                 :     TreeContext     *tc;
    5051                 :     uint32_t        startYieldCount;
    5052                 :     uint32_t        startArgumentsCount;
    5053                 : 
    5054                 :   public:
    5055         4176789 :     explicit GenexpGuard(TreeContext *tc)
    5056         4176789 :       : tc(tc)
    5057                 :     {
    5058         4176789 :         if (tc->parenDepth == 0) {
    5059         3727845 :             tc->yieldCount = tc->argumentsCount = 0;
    5060         3727845 :             tc->yieldNode = tc->argumentsNode = NULL;
    5061                 :         }
    5062         4176789 :         startYieldCount = tc->yieldCount;
    5063         4176789 :         startArgumentsCount = tc->argumentsCount;
    5064         4176789 :         tc->parenDepth++;
    5065         4176789 :     }
    5066                 : 
    5067                 :     void endBody();
    5068                 :     bool checkValidBody(ParseNode *pn);
    5069                 :     bool maybeNoteGenerator(ParseNode *pn);
    5070                 : };
    5071                 : 
    5072                 : void
    5073         4176626 : GenexpGuard::endBody()
    5074                 : {
    5075         4176626 :     tc->parenDepth--;
    5076         4176626 : }
    5077                 : 
    5078                 : /*
    5079                 :  * Check whether a |yield| or |arguments| token has been encountered in the
    5080                 :  * body expression, and if so, report an error.
    5081                 :  *
    5082                 :  * Call this after endBody() when determining that the body *was* in a
    5083                 :  * generator expression.
    5084                 :  */
    5085                 : bool
    5086             435 : GenexpGuard::checkValidBody(ParseNode *pn)
    5087                 : {
    5088             435 :     if (tc->yieldCount > startYieldCount) {
    5089               0 :         ParseNode *errorNode = tc->yieldNode;
    5090               0 :         if (!errorNode)
    5091               0 :             errorNode = pn;
    5092               0 :         tc->parser->reportErrorNumber(errorNode, JSREPORT_ERROR, JSMSG_BAD_GENEXP_BODY, js_yield_str);
    5093               0 :         return false;
    5094                 :     }
    5095                 : 
    5096             435 :     if (tc->argumentsCount > startArgumentsCount) {
    5097               9 :         ParseNode *errorNode = tc->argumentsNode;
    5098               9 :         if (!errorNode)
    5099               0 :             errorNode = pn;
    5100               9 :         tc->parser->reportErrorNumber(errorNode, JSREPORT_ERROR, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
    5101               9 :         return false;
    5102                 :     }
    5103                 : 
    5104             426 :     return true;
    5105                 : }
    5106                 : 
    5107                 : /*
    5108                 :  * Check whether a |yield| token has been encountered in the body expression,
    5109                 :  * and if so, note that the current function is a generator function.
    5110                 :  *
    5111                 :  * Call this after endBody() when determining that the body *was not* in a
    5112                 :  * generator expression.
    5113                 :  */
    5114                 : bool
    5115         4176191 : GenexpGuard::maybeNoteGenerator(ParseNode *pn)
    5116                 : {
    5117         4176191 :     if (tc->yieldCount > 0) {
    5118               0 :         tc->flags |= TCF_FUN_IS_GENERATOR;
    5119               0 :         if (!tc->inFunction()) {
    5120                 :             tc->parser->reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN_OR_YIELD,
    5121               0 :                                           js_yield_str);
    5122               0 :             return false;
    5123                 :         }
    5124               0 :         if (tc->flags & TCF_RETURN_EXPR) {
    5125                 :             /* At the time we saw the yield, we might not have set TCF_FUN_IS_GENERATOR yet. */
    5126                 :             ReportBadReturn(tc->parser->context, tc, pn, JSREPORT_ERROR,
    5127                 :                             JSMSG_BAD_GENERATOR_RETURN,
    5128               0 :                             JSMSG_BAD_ANON_GENERATOR_RETURN);
    5129               0 :             return false;
    5130                 :         }
    5131                 :     }
    5132         4176191 :     return true;
    5133                 : }
    5134                 : 
    5135                 : /*
    5136                 :  * Any definitions nested within the comprehension expression of a generator
    5137                 :  * expression must move "down" one static level, which of course increases the
    5138                 :  * upvar-frame-skip count.
    5139                 :  */
    5140                 : static bool
    5141             208 : BumpStaticLevel(ParseNode *pn, TreeContext *tc)
    5142                 : {
    5143             208 :     if (!pn->pn_cookie.isFree()) {
    5144               0 :         unsigned level = pn->pn_cookie.level() + 1;
    5145                 : 
    5146               0 :         JS_ASSERT(level >= tc->staticLevel);
    5147               0 :         if (level >= UpvarCookie::FREE_LEVEL) {
    5148                 :             JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL,
    5149               0 :                                  JSMSG_TOO_DEEP, js_function_str);
    5150               0 :             return false;
    5151                 :         }
    5152                 : 
    5153               0 :         pn->pn_cookie.set(level, pn->pn_cookie.slot());
    5154                 :     }
    5155             208 :     return true;
    5156                 : }
    5157                 : 
    5158                 : static void
    5159           57788 : AdjustBlockId(ParseNode *pn, unsigned adjust, TreeContext *tc)
    5160                 : {
    5161           57788 :     JS_ASSERT(pn->isArity(PN_LIST) || pn->isArity(PN_FUNC) || pn->isArity(PN_NAME));
    5162           57788 :     pn->pn_blockid += adjust;
    5163           57788 :     if (pn->pn_blockid >= tc->blockidGen)
    5164             664 :         tc->blockidGen = pn->pn_blockid + 1;
    5165           57788 : }
    5166                 : 
    5167                 : bool
    5168           67613 : CompExprTransplanter::transplant(ParseNode *pn)
    5169                 : {
    5170           67613 :     if (!pn)
    5171           21348 :         return true;
    5172                 : 
    5173           46265 :     switch (pn->getArity()) {
    5174                 :       case PN_LIST:
    5175           27607 :         for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    5176           18688 :             if (!transplant(pn2))
    5177               0 :                 return false;
    5178                 :         }
    5179            8919 :         if (pn->pn_pos >= root->pn_pos)
    5180            8919 :             AdjustBlockId(pn, adjust, tc);
    5181            8919 :         break;
    5182                 : 
    5183                 :       case PN_TERNARY:
    5184               0 :         if (!transplant(pn->pn_kid1) ||
    5185               0 :             !transplant(pn->pn_kid2) ||
    5186               0 :             !transplant(pn->pn_kid3))
    5187               0 :             return false;
    5188               0 :         break;
    5189                 : 
    5190                 :       case PN_BINARY:
    5191            2861 :         if (!transplant(pn->pn_left))
    5192               0 :             return false;
    5193                 : 
    5194                 :         /* Binary TOK_COLON nodes can have left == right. See bug 492714. */
    5195            2861 :         if (pn->pn_right != pn->pn_left) {
    5196            2861 :             if (!transplant(pn->pn_right))
    5197               0 :                 return false;
    5198                 :         }
    5199            2861 :         break;
    5200                 : 
    5201                 :       case PN_UNARY:
    5202             226 :         if (!transplant(pn->pn_kid))
    5203               0 :             return false;
    5204             226 :         break;
    5205                 : 
    5206                 :       case PN_FUNC:
    5207                 :       {
    5208                 :         /*
    5209                 :          * Only the first level of transplant recursion through functions needs
    5210                 :          * to reparent the funbox, since all descendant functions are correctly
    5211                 :          * linked under the top-most funbox. But every visit to this case needs
    5212                 :          * to update funbox->level.
    5213                 :          *
    5214                 :          * Recall that funbox->level is the static level of the code containing
    5215                 :          * the definition or expression of the function and not the static level
    5216                 :          * of the function's body.
    5217                 :          */
    5218               9 :         FunctionBox *funbox = pn->pn_funbox;
    5219                 : 
    5220               9 :         funbox->level = tc->staticLevel + funcLevel;
    5221               9 :         if (++funcLevel == 1 && genexp) {
    5222               0 :             FunctionBox *parent = tc->funbox;
    5223                 : 
    5224               0 :             FunctionBox **funboxp = &tc->parent->functionList;
    5225               0 :             while (*funboxp != funbox)
    5226               0 :                 funboxp = &(*funboxp)->siblings;
    5227               0 :             *funboxp = funbox->siblings;
    5228                 : 
    5229               0 :             funbox->parent = parent;
    5230               0 :             funbox->siblings = parent->kids;
    5231               0 :             parent->kids = funbox;
    5232               0 :             funbox->level = tc->staticLevel;
    5233                 :         }
    5234                 :         /* FALL THROUGH */
    5235                 :       }
    5236                 : 
    5237                 :       case PN_NAME:
    5238           29897 :         if (!transplant(pn->maybeExpr()))
    5239               0 :             return false;
    5240           29897 :         if (pn->isArity(PN_FUNC))
    5241               9 :             --funcLevel;
    5242                 : 
    5243           29897 :         if (pn->isDefn()) {
    5244               0 :             if (genexp && !BumpStaticLevel(pn, tc))
    5245               0 :                 return false;
    5246           29897 :         } else if (pn->isUsed()) {
    5247           21348 :             JS_ASSERT(!pn->isOp(JSOP_NOP));
    5248           21348 :             JS_ASSERT(pn->pn_cookie.isFree());
    5249                 : 
    5250           21348 :             Definition *dn = pn->pn_lexdef;
    5251           21348 :             JS_ASSERT(dn->isDefn());
    5252                 : 
    5253                 :             /*
    5254                 :              * Adjust the definition's block id only if it is a placeholder not
    5255                 :              * to the left of the root node, and if pn is the last use visited
    5256                 :              * in the comprehension expression (to avoid adjusting the blockid
    5257                 :              * multiple times).
    5258                 :              *
    5259                 :              * Non-placeholder definitions within the comprehension expression
    5260                 :              * will be visited further below.
    5261                 :              */
    5262           21348 :             if (dn->isPlaceholder() && dn->pn_pos >= root->pn_pos && dn->dn_uses == pn) {
    5263           18972 :                 if (genexp && !BumpStaticLevel(dn, tc))
    5264               0 :                     return false;
    5265           18972 :                 AdjustBlockId(dn, adjust, tc);
    5266                 :             }
    5267                 : 
    5268           21348 :             JSAtom *atom = pn->pn_atom;
    5269                 : #ifdef DEBUG
    5270           21348 :             StmtInfo *stmt = LexicalLookup(tc, atom, NULL);
    5271           21348 :             JS_ASSERT(!stmt || stmt != tc->topStmt);
    5272                 : #endif
    5273           21348 :             if (genexp && !dn->isOp(JSOP_CALLEE)) {
    5274             232 :                 JS_ASSERT(!tc->decls.lookupFirst(atom));
    5275                 : 
    5276             232 :                 if (dn->pn_pos < root->pn_pos) {
    5277                 :                     /*
    5278                 :                      * The variable originally appeared to be a use of a
    5279                 :                      * definition or placeholder outside the generator, but now
    5280                 :                      * we know it is scoped within the comprehension tail's
    5281                 :                      * clauses. Make it (along with any other uses within the
    5282                 :                      * generator) a use of a new placeholder in the generator's
    5283                 :                      * lexdeps.
    5284                 :                      */
    5285               4 :                     Definition *dn2 = MakePlaceholder(pn, tc);
    5286               4 :                     if (!dn2)
    5287               0 :                         return false;
    5288               4 :                     dn2->pn_pos = root->pn_pos;
    5289                 : 
    5290                 :                     /*
    5291                 :                      * Change all uses of |dn| that lie within the generator's
    5292                 :                      * |yield| expression into uses of dn2.
    5293                 :                      */
    5294               4 :                     ParseNode **pnup = &dn->dn_uses;
    5295                 :                     ParseNode *pnu;
    5296              12 :                     while ((pnu = *pnup) != NULL && pnu->pn_pos >= root->pn_pos) {
    5297               4 :                         pnu->pn_lexdef = dn2;
    5298               4 :                         dn2->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
    5299               4 :                         pnup = &pnu->pn_link;
    5300                 :                     }
    5301               4 :                     dn2->dn_uses = dn->dn_uses;
    5302               4 :                     dn->dn_uses = *pnup;
    5303               4 :                     *pnup = NULL;
    5304               4 :                     if (!tc->lexdeps->put(atom, dn2))
    5305               0 :                         return false;
    5306             228 :                 } else if (dn->isPlaceholder()) {
    5307                 :                     /*
    5308                 :                      * The variable first occurs free in the 'yield' expression;
    5309                 :                      * move the existing placeholder node (and all its uses)
    5310                 :                      * from the parent's lexdeps into the generator's lexdeps.
    5311                 :                      */
    5312             228 :                     tc->parent->lexdeps->remove(atom);
    5313             228 :                     if (!tc->lexdeps->put(atom, dn))
    5314               0 :                         return false;
    5315                 :                 }
    5316                 :             }
    5317                 :         }
    5318                 : 
    5319           29897 :         if (pn->pn_pos >= root->pn_pos)
    5320           29897 :             AdjustBlockId(pn, adjust, tc);
    5321           29897 :         break;
    5322                 : 
    5323                 :       case PN_NAMESET:
    5324               9 :         if (!transplant(pn->pn_tree))
    5325               0 :             return false;
    5326               9 :         break;
    5327                 : 
    5328                 :       case PN_NULLARY:
    5329                 :         /* Nothing. */
    5330            4353 :         break;
    5331                 :     }
    5332           46265 :     return true;
    5333                 : }
    5334                 : 
    5335                 : /*
    5336                 :  * Starting from a |for| keyword after the first array initialiser element or
    5337                 :  * an expression in an open parenthesis, parse the tail of the comprehension
    5338                 :  * or generator expression signified by this |for| keyword in context.
    5339                 :  *
    5340                 :  * Return null on failure, else return the top-most parse node for the array
    5341                 :  * comprehension or generator expression, with a unary node as the body of the
    5342                 :  * (possibly nested) for-loop, initialized by |kind, op, kid|.
    5343                 :  */
    5344                 : ParseNode *
    5345           13071 : Parser::comprehensionTail(ParseNode *kid, unsigned blockid, bool isGenexp,
    5346                 :                           ParseNodeKind kind, JSOp op)
    5347                 : {
    5348                 :     unsigned adjust;
    5349                 :     ParseNode *pn, *pn2, *pn3, **pnp;
    5350                 :     StmtInfo stmtInfo;
    5351           13071 :     BindData data;
    5352                 :     TokenKind tt;
    5353                 : 
    5354           13071 :     JS_ASSERT(tokenStream.currentToken().type == TOK_FOR);
    5355                 : 
    5356           13071 :     if (kind == PNK_SEMI) {
    5357                 :         /*
    5358                 :          * Generator expression desugars to an immediately applied lambda that
    5359                 :          * yields the next value from a for-in loop (possibly nested, and with
    5360                 :          * optional if guard). Make pn be the TOK_LC body node.
    5361                 :          */
    5362             213 :         pn = PushLexicalScope(context, tc, &stmtInfo);
    5363             213 :         if (!pn)
    5364               0 :             return NULL;
    5365             213 :         adjust = pn->pn_blockid - blockid;
    5366                 :     } else {
    5367           12858 :         JS_ASSERT(kind == PNK_ARRAYPUSH);
    5368                 : 
    5369                 :         /*
    5370                 :          * Make a parse-node and literal object representing the block scope of
    5371                 :          * this array comprehension. Our caller in primaryExpr, the TOK_LB case
    5372                 :          * aka the array initialiser case, has passed the blockid to claim for
    5373                 :          * the comprehension's block scope. We allocate that id or one above it
    5374                 :          * here, by calling PushLexicalScope.
    5375                 :          *
    5376                 :          * In the case of a comprehension expression that has nested blocks
    5377                 :          * (e.g., let expressions), we will allocate a higher blockid but then
    5378                 :          * slide all blocks "to the right" to make room for the comprehension's
    5379                 :          * block scope.
    5380                 :          */
    5381           12858 :         adjust = tc->blockid();
    5382           12858 :         pn = PushLexicalScope(context, tc, &stmtInfo);
    5383           12858 :         if (!pn)
    5384               0 :             return NULL;
    5385                 : 
    5386           12858 :         JS_ASSERT(blockid <= pn->pn_blockid);
    5387           12858 :         JS_ASSERT(blockid < tc->blockidGen);
    5388           12858 :         JS_ASSERT(tc->bodyid < blockid);
    5389           12858 :         pn->pn_blockid = stmtInfo.blockid = blockid;
    5390           12858 :         JS_ASSERT(adjust < blockid);
    5391           12858 :         adjust = blockid - adjust;
    5392                 :     }
    5393                 : 
    5394           13071 :     pnp = &pn->pn_expr;
    5395                 : 
    5396           13071 :     CompExprTransplanter transplanter(kid, tc, kind == PNK_SEMI, adjust);
    5397           13071 :     transplanter.transplant(kid);
    5398                 : 
    5399           13071 :     JS_ASSERT(tc->blockChain && tc->blockChain == pn->pn_objbox->object);
    5400           13071 :     data.initLet(HoistVars, *tc->blockChain, JSMSG_ARRAY_INIT_TOO_BIG);
    5401                 : 
    5402           12963 :     do {
    5403                 :         /*
    5404                 :          * FOR node is binary, left is loop control and right is body.  Use
    5405                 :          * index to count each block-local let-variable on the left-hand side
    5406                 :          * of the in/of.
    5407                 :          */
    5408           13098 :         pn2 = BinaryNode::create(PNK_FOR, tc);
    5409           13098 :         if (!pn2)
    5410               0 :             return NULL;
    5411                 : 
    5412           13098 :         pn2->setOp(JSOP_ITER);
    5413           13098 :         pn2->pn_iflags = JSITER_ENUMERATE;
    5414           13098 :         if (tokenStream.matchToken(TOK_NAME)) {
    5415            9905 :             if (tokenStream.currentToken().name() == context->runtime->atomState.eachAtom)
    5416            9905 :                 pn2->pn_iflags |= JSITER_FOREACH;
    5417                 :             else
    5418               0 :                 tokenStream.ungetToken();
    5419                 :         }
    5420           13098 :         MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
    5421                 : 
    5422           13098 :         GenexpGuard guard(tc);
    5423                 : 
    5424           13098 :         PropertyName *name = NULL;
    5425           13098 :         tt = tokenStream.getToken();
    5426           13098 :         switch (tt) {
    5427                 : #if JS_HAS_DESTRUCTURING
    5428                 :           case TOK_LB:
    5429                 :           case TOK_LC:
    5430             689 :             tc->flags |= TCF_DECL_DESTRUCTURING;
    5431             689 :             pn3 = primaryExpr(tt, JS_FALSE);
    5432             689 :             tc->flags &= ~TCF_DECL_DESTRUCTURING;
    5433             689 :             if (!pn3)
    5434               0 :                 return NULL;
    5435             689 :             break;
    5436                 : #endif
    5437                 : 
    5438                 :           case TOK_NAME:
    5439           12355 :             name = tokenStream.currentToken().name();
    5440                 : 
    5441                 :             /*
    5442                 :              * Create a name node with pn_op JSOP_NAME.  We can't set pn_op to
    5443                 :              * JSOP_GETLOCAL here, because we don't yet know the block's depth
    5444                 :              * in the operand stack frame.  The code generator computes that,
    5445                 :              * and it tries to bind all names to slots, so we must let it do
    5446                 :              * the deed.
    5447                 :              */
    5448           12355 :             pn3 = NewBindingNode(name, tc);
    5449           12355 :             if (!pn3)
    5450               0 :                 return NULL;
    5451           12355 :             break;
    5452                 : 
    5453                 :           default:
    5454              54 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NO_VARIABLE_NAME);
    5455                 : 
    5456                 :           case TOK_ERROR:
    5457              54 :             return NULL;
    5458                 :         }
    5459                 : 
    5460                 :         bool forOf;
    5461           13044 :         if (!matchInOrOf(&forOf)) {
    5462               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_IN_AFTER_FOR_NAME);
    5463               0 :             return NULL;
    5464                 :         }
    5465           13044 :         if (forOf) {
    5466             153 :             if (pn2->pn_iflags != JSITER_ENUMERATE) {
    5467              27 :                 JS_ASSERT(pn2->pn_iflags == (JSITER_FOREACH | JSITER_ENUMERATE));
    5468              27 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
    5469              27 :                 return NULL;
    5470                 :             }
    5471             126 :             pn2->pn_iflags = JSITER_FOR_OF;
    5472                 :         }
    5473                 : 
    5474           13017 :         ParseNode *pn4 = expr();
    5475           13017 :         if (!pn4)
    5476               0 :             return NULL;
    5477           13017 :         MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
    5478                 : 
    5479           12963 :         guard.endBody();
    5480                 : 
    5481           12963 :         if (isGenexp) {
    5482             213 :             if (!guard.checkValidBody(pn2))
    5483               0 :                 return NULL;
    5484                 :         } else {
    5485           12750 :             if (!guard.maybeNoteGenerator(pn2))
    5486               0 :                 return NULL;
    5487                 :         }
    5488                 : 
    5489           12963 :         switch (tt) {
    5490                 : #if JS_HAS_DESTRUCTURING
    5491                 :           case TOK_LB:
    5492                 :           case TOK_LC:
    5493             689 :             if (!CheckDestructuring(context, &data, pn3, tc))
    5494               0 :                 return NULL;
    5495                 : 
    5496             689 :             if (versionNumber() == JSVERSION_1_7) {
    5497                 :                 /* Destructuring requires [key, value] enumeration in JS1.7. */
    5498               0 :                 if (!pn3->isKind(PNK_RB) || pn3->pn_count != 2) {
    5499               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE);
    5500               0 :                     return NULL;
    5501                 :                 }
    5502                 : 
    5503               0 :                 JS_ASSERT(pn2->isOp(JSOP_ITER));
    5504               0 :                 JS_ASSERT(pn2->pn_iflags & JSITER_ENUMERATE);
    5505               0 :                 if (!(pn2->pn_iflags & JSITER_FOREACH))
    5506               0 :                     pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
    5507                 :             }
    5508             689 :             break;
    5509                 : #endif
    5510                 : 
    5511                 :           case TOK_NAME:
    5512           12274 :             data.pn = pn3;
    5513           12274 :             if (!data.binder(context, &data, name, tc))
    5514               0 :                 return NULL;
    5515           12274 :             break;
    5516                 : 
    5517                 :           default:;
    5518                 :         }
    5519                 : 
    5520                 :         /*
    5521                 :          * Synthesize a declaration. Every definition must appear in the parse
    5522                 :          * tree in order for ComprehensionTranslator to work.
    5523                 :          */
    5524           12963 :         ParseNode *vars = ListNode::create(PNK_VAR, tc);
    5525           12963 :         if (!vars)
    5526               0 :             return NULL;
    5527           12963 :         vars->setOp(JSOP_NOP);
    5528           12963 :         vars->pn_pos = pn3->pn_pos;
    5529           12963 :         vars->makeEmpty();
    5530           12963 :         vars->append(pn3);
    5531           12963 :         vars->pn_xflags |= PNX_FORINVAR;
    5532                 : 
    5533                 :         /* Definitions can't be passed directly to EmitAssignment as lhs. */
    5534           12963 :         pn3 = CloneLeftHandSide(pn3, tc);
    5535           12963 :         if (!pn3)
    5536               0 :             return NULL;
    5537                 : 
    5538           12963 :         pn2->pn_left = new_<TernaryNode>(PNK_FORIN, JSOP_NOP, vars, pn3, pn4);
    5539           12963 :         if (!pn2->pn_left)
    5540               0 :             return NULL;
    5541           12963 :         *pnp = pn2;
    5542           12963 :         pnp = &pn2->pn_right;
    5543           12963 :     } while (tokenStream.matchToken(TOK_FOR));
    5544                 : 
    5545           12936 :     if (tokenStream.matchToken(TOK_IF)) {
    5546            2857 :         pn2 = TernaryNode::create(PNK_IF, tc);
    5547            2857 :         if (!pn2)
    5548               0 :             return NULL;
    5549            2857 :         pn2->pn_kid1 = condition();
    5550            2857 :         if (!pn2->pn_kid1)
    5551               0 :             return NULL;
    5552            2857 :         *pnp = pn2;
    5553            2857 :         pnp = &pn2->pn_kid2;
    5554                 :     }
    5555                 : 
    5556           12936 :     pn2 = UnaryNode::create(kind, tc);
    5557           12936 :     if (!pn2)
    5558               0 :         return NULL;
    5559           12936 :     pn2->setOp(op);
    5560           12936 :     pn2->pn_kid = kid;
    5561           12936 :     *pnp = pn2;
    5562                 : 
    5563           12936 :     PopStatement(tc);
    5564           12936 :     return pn;
    5565                 : }
    5566                 : 
    5567                 : #if JS_HAS_GENERATOR_EXPRS
    5568                 : 
    5569                 : /*
    5570                 :  * Starting from a |for| keyword after an expression, parse the comprehension
    5571                 :  * tail completing this generator expression. Wrap the expression at kid in a
    5572                 :  * generator function that is immediately called to evaluate to the generator
    5573                 :  * iterator that is the value of this generator expression.
    5574                 :  *
    5575                 :  * |kid| must be the expression before the |for| keyword; we return an
    5576                 :  * application of a generator function that includes the |for| loops and
    5577                 :  * |if| guards, with |kid| as the operand of a |yield| expression as the
    5578                 :  * innermost loop body.
    5579                 :  *
    5580                 :  * Note how unlike Python, we do not evaluate the expression to the right of
    5581                 :  * the first |in| in the chain of |for| heads. Instead, a generator expression
    5582                 :  * is merely sugar for a generator function expression and its application.
    5583                 :  */
    5584                 : ParseNode *
    5585             213 : Parser::generatorExpr(ParseNode *kid)
    5586                 : {
    5587             213 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
    5588                 : 
    5589                 :     /* Create a |yield| node for |kid|. */
    5590             213 :     ParseNode *pn = UnaryNode::create(PNK_YIELD, tc);
    5591             213 :     if (!pn)
    5592               0 :         return NULL;
    5593             213 :     pn->setOp(JSOP_YIELD);
    5594             213 :     pn->setInParens(true);
    5595             213 :     pn->pn_pos = kid->pn_pos;
    5596             213 :     pn->pn_kid = kid;
    5597             213 :     pn->pn_hidden = true;
    5598                 : 
    5599                 :     /* Make a new node for the desugared generator function. */
    5600             213 :     ParseNode *genfn = FunctionNode::create(PNK_FUNCTION, tc);
    5601             213 :     if (!genfn)
    5602               0 :         return NULL;
    5603             213 :     genfn->setOp(JSOP_LAMBDA);
    5604             213 :     JS_ASSERT(!genfn->pn_body);
    5605             213 :     genfn->pn_dflags = PND_FUNARG;
    5606                 : 
    5607                 :     {
    5608             213 :         TreeContext *outertc = tc;
    5609             426 :         TreeContext gentc(tc->parser);
    5610             213 :         if (!gentc.init(context))
    5611               0 :             return NULL;
    5612                 : 
    5613             213 :         FunctionBox *funbox = EnterFunction(genfn, &gentc);
    5614             213 :         if (!funbox)
    5615               0 :             return NULL;
    5616                 : 
    5617                 :         /*
    5618                 :          * We assume conservatively that any deoptimization flag in tc->flags
    5619                 :          * besides TCF_FUN_PARAM_ARGUMENTS can come from the kid. So we
    5620                 :          * propagate these flags into genfn. For code simplicity we also do
    5621                 :          * not detect if the flags were only set in the kid and could be
    5622                 :          * removed from tc->flags.
    5623                 :          */
    5624                 :         gentc.flags |= TCF_FUN_IS_GENERATOR | TCF_GENEXP_LAMBDA |
    5625             213 :                        (outertc->flags & (TCF_FUN_FLAGS & ~TCF_FUN_PARAM_ARGUMENTS));
    5626             213 :         funbox->tcflags |= gentc.flags;
    5627             213 :         genfn->pn_funbox = funbox;
    5628             213 :         genfn->pn_blockid = gentc.bodyid;
    5629                 : 
    5630             213 :         ParseNode *body = comprehensionTail(pn, outertc->blockid(), true);
    5631             213 :         if (!body)
    5632               0 :             return NULL;
    5633             213 :         JS_ASSERT(!genfn->pn_body);
    5634             213 :         genfn->pn_body = body;
    5635             213 :         genfn->pn_pos.begin = body->pn_pos.begin = kid->pn_pos.begin;
    5636             213 :         genfn->pn_pos.end = body->pn_pos.end = tokenStream.currentToken().pos.end;
    5637                 : 
    5638             213 :         if (!LeaveFunction(genfn, &gentc))
    5639               0 :             return NULL;
    5640                 :     }
    5641                 : 
    5642                 :     /*
    5643                 :      * Our result is a call expression that invokes the anonymous generator
    5644                 :      * function object.
    5645                 :      */
    5646             213 :     ParseNode *result = ListNode::create(PNK_LP, tc);
    5647             213 :     if (!result)
    5648               0 :         return NULL;
    5649             213 :     result->setOp(JSOP_CALL);
    5650             213 :     result->pn_pos.begin = genfn->pn_pos.begin;
    5651             213 :     result->initList(genfn);
    5652             213 :     return result;
    5653                 : }
    5654                 : 
    5655                 : static const char js_generator_str[] = "generator";
    5656                 : 
    5657                 : #endif /* JS_HAS_GENERATOR_EXPRS */
    5658                 : #endif /* JS_HAS_GENERATORS */
    5659                 : 
    5660                 : JSBool
    5661         3330396 : Parser::argumentList(ParseNode *listNode)
    5662                 : {
    5663         3330396 :     if (tokenStream.matchToken(TOK_RP, TSF_OPERAND))
    5664          562818 :         return JS_TRUE;
    5665                 : 
    5666         2767578 :     GenexpGuard guard(tc);
    5667         2767578 :     bool arg0 = true;
    5668                 : 
    5669         4364320 :     do {
    5670         4364330 :         ParseNode *argNode = assignExpr();
    5671         4364330 :         if (!argNode)
    5672              10 :             return JS_FALSE;
    5673         4364320 :         if (arg0)
    5674         2767568 :             guard.endBody();
    5675                 : 
    5676                 : #if JS_HAS_GENERATORS
    5677         4364320 :         if (argNode->isKind(PNK_YIELD) &&
    5678               0 :             !argNode->isInParens() &&
    5679               0 :             tokenStream.peekToken() == TOK_COMMA) {
    5680               0 :             reportErrorNumber(argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
    5681               0 :             return JS_FALSE;
    5682                 :         }
    5683                 : #endif
    5684                 : #if JS_HAS_GENERATOR_EXPRS
    5685         4364320 :         if (tokenStream.matchToken(TOK_FOR)) {
    5686              27 :             if (!guard.checkValidBody(argNode))
    5687               0 :                 return JS_FALSE;
    5688              27 :             argNode = generatorExpr(argNode);
    5689              27 :             if (!argNode)
    5690               0 :                 return JS_FALSE;
    5691              54 :             if (listNode->pn_count > 1 ||
    5692              27 :                 tokenStream.peekToken() == TOK_COMMA) {
    5693                 :                 reportErrorNumber(argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX,
    5694               0 :                                   js_generator_str);
    5695               0 :                 return JS_FALSE;
    5696                 :             }
    5697                 :         } else
    5698                 : #endif
    5699         4364293 :         if (arg0 && !guard.maybeNoteGenerator(argNode))
    5700               0 :             return JS_FALSE;
    5701                 : 
    5702         4364320 :         arg0 = false;
    5703                 : 
    5704         4364320 :         listNode->append(argNode);
    5705         4364320 :     } while (tokenStream.matchToken(TOK_COMMA));
    5706                 : 
    5707         2767568 :     if (tokenStream.getToken() != TOK_RP) {
    5708               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_AFTER_ARGS);
    5709               0 :         return JS_FALSE;
    5710                 :     }
    5711         2767568 :     return JS_TRUE;
    5712                 : }
    5713                 : 
    5714                 : /* Check for an immediately-applied (new'ed) lambda and clear PND_FUNARG. */
    5715                 : static ParseNode *
    5716         3332456 : CheckForImmediatelyAppliedLambda(ParseNode *pn)
    5717                 : {
    5718         3332456 :     if (pn->isKind(PNK_FUNCTION)) {
    5719            3310 :         JS_ASSERT(pn->isArity(PN_FUNC));
    5720                 : 
    5721            3310 :         FunctionBox *funbox = pn->pn_funbox;
    5722            3310 :         JS_ASSERT((funbox->function())->flags & JSFUN_LAMBDA);
    5723            3310 :         if (!(funbox->tcflags & (TCF_FUN_USES_ARGUMENTS | TCF_FUN_USES_OWN_NAME)))
    5724            2999 :             pn->pn_dflags &= ~PND_FUNARG;
    5725                 :     }
    5726         3332456 :     return pn;
    5727                 : }
    5728                 : 
    5729                 : ParseNode *
    5730        34352613 : Parser::memberExpr(JSBool allowCallSyntax)
    5731                 : {
    5732                 :     ParseNode *lhs;
    5733                 : 
    5734        34352613 :     JS_CHECK_RECURSION(context, return NULL);
    5735                 : 
    5736                 :     /* Check for new expression first. */
    5737        34352613 :     TokenKind tt = tokenStream.getToken(TSF_OPERAND);
    5738        34352613 :     if (tt == TOK_NEW) {
    5739          159652 :         lhs = ListNode::create(PNK_NEW, tc);
    5740          159652 :         if (!lhs)
    5741               0 :             return NULL;
    5742          159652 :         ParseNode *ctorExpr = memberExpr(JS_FALSE);
    5743          159652 :         if (!ctorExpr)
    5744               0 :             return NULL;
    5745          159652 :         ctorExpr = CheckForImmediatelyAppliedLambda(ctorExpr);
    5746          159652 :         lhs->setOp(JSOP_NEW);
    5747          159652 :         lhs->initList(ctorExpr);
    5748          159652 :         lhs->pn_pos.begin = ctorExpr->pn_pos.begin;
    5749                 : 
    5750          159652 :         if (tokenStream.matchToken(TOK_LP) && !argumentList(lhs))
    5751               0 :             return NULL;
    5752          159652 :         if (lhs->pn_count > ARGC_LIMIT) {
    5753                 :             JS_ReportErrorNumber(context, js_GetErrorMessage, NULL,
    5754               0 :                                  JSMSG_TOO_MANY_CON_ARGS);
    5755               0 :             return NULL;
    5756                 :         }
    5757          159652 :         lhs->pn_pos.end = lhs->last()->pn_pos.end;
    5758                 :     } else {
    5759        34192961 :         lhs = primaryExpr(tt, JS_FALSE);
    5760        34192961 :         if (!lhs)
    5761             230 :             return NULL;
    5762                 : 
    5763        34192731 :         if (lhs->isXMLNameOp()) {
    5764              90 :             lhs = new_<UnaryNode>(PNK_XMLUNARY, JSOP_XMLNAME, lhs->pn_pos, lhs);
    5765              90 :             if (!lhs)
    5766               0 :                 return NULL;
    5767                 :         }
    5768                 :     }
    5769                 : 
    5770        85440954 :     while ((tt = tokenStream.getToken()) > TOK_EOF) {
    5771                 :         ParseNode *nextMember;
    5772        51054211 :         if (tt == TOK_DOT) {
    5773         6496852 :             tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
    5774         6496852 :             if (tt == TOK_ERROR)
    5775               0 :                 return NULL;
    5776         6496852 :             if (tt == TOK_NAME) {
    5777                 : #if JS_HAS_XML_SUPPORT
    5778         6496789 :                 if (!tc->inStrictMode() && tokenStream.peekToken() == TOK_DBLCOLON) {
    5779               9 :                     ParseNode *propertyId = propertyQualifiedIdentifier();
    5780               9 :                     if (!propertyId)
    5781               0 :                         return NULL;
    5782                 : 
    5783                 :                     nextMember = new_<XMLDoubleColonProperty>(lhs, propertyId,
    5784                 :                                                               lhs->pn_pos.begin,
    5785               9 :                                                               tokenStream.currentToken().pos.end);
    5786               9 :                     if (!nextMember)
    5787               0 :                         return NULL;
    5788                 :                 } else
    5789                 : #endif
    5790                 :                 {
    5791         6496780 :                     PropertyName *field = tokenStream.currentToken().name();
    5792                 :                     nextMember = new_<PropertyAccess>(lhs, field,
    5793                 :                                                       lhs->pn_pos.begin,
    5794         6496780 :                                                       tokenStream.currentToken().pos.end);
    5795         6496780 :                     if (!nextMember)
    5796               0 :                         return NULL;
    5797                 :                 }
    5798                 :             }
    5799                 : #if JS_HAS_XML_SUPPORT
    5800              63 :             else if (!tc->inStrictMode()) {
    5801              63 :                 TokenPtr begin = lhs->pn_pos.begin;
    5802              63 :                 if (tt == TOK_LP) {
    5803                 :                     /* Filters are effectively 'with', so deoptimize names. */
    5804              63 :                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
    5805                 : 
    5806                 :                     StmtInfo stmtInfo;
    5807              63 :                     ParseNode *oldWith = tc->innermostWith;
    5808              63 :                     tc->innermostWith = lhs;
    5809              63 :                     PushStatement(tc, &stmtInfo, STMT_WITH, -1);
    5810                 : 
    5811              63 :                     ParseNode *filter = bracketedExpr();
    5812              63 :                     if (!filter)
    5813               0 :                         return NULL;
    5814              63 :                     filter->setInParens(true);
    5815              63 :                     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
    5816                 : 
    5817              63 :                     tc->innermostWith = oldWith;
    5818              63 :                     PopStatement(tc);
    5819                 : 
    5820                 :                     nextMember =
    5821                 :                         new_<XMLFilterExpression>(lhs, filter,
    5822              63 :                                                   begin, tokenStream.currentToken().pos.end);
    5823              63 :                     if (!nextMember)
    5824               0 :                         return NULL;
    5825               0 :                 } else if (tt == TOK_AT || tt == TOK_STAR) {
    5826               0 :                     ParseNode *propertyId = starOrAtPropertyIdentifier(tt);
    5827               0 :                     if (!propertyId)
    5828               0 :                         return NULL;
    5829                 :                     nextMember = new_<XMLProperty>(lhs, propertyId,
    5830               0 :                                                    begin, tokenStream.currentToken().pos.end);
    5831               0 :                     if (!nextMember)
    5832               0 :                         return NULL;
    5833                 :                 } else {
    5834               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
    5835               0 :                     return NULL;
    5836                 :                 }
    5837                 :             }
    5838                 : #endif
    5839                 :             else {
    5840               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
    5841               0 :                 return NULL;
    5842                 :             }
    5843                 :         }
    5844                 : #if JS_HAS_XML_SUPPORT
    5845        44557359 :         else if (tt == TOK_DBLDOT) {
    5846               9 :             if (tc->inStrictMode()) {
    5847               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
    5848               0 :                 return NULL;
    5849                 :             }
    5850                 : 
    5851               9 :             nextMember = BinaryNode::create(PNK_DBLDOT, tc);
    5852               9 :             if (!nextMember)
    5853               0 :                 return NULL;
    5854               9 :             tt = tokenStream.getToken(TSF_OPERAND | TSF_KEYWORD_IS_NAME);
    5855               9 :             ParseNode *pn3 = primaryExpr(tt, JS_TRUE);
    5856               9 :             if (!pn3)
    5857               0 :                 return NULL;
    5858               9 :             if (pn3->isKind(PNK_NAME) && !pn3->isInParens()) {
    5859               9 :                 pn3->setKind(PNK_STRING);
    5860               9 :                 pn3->setArity(PN_NULLARY);
    5861               9 :                 pn3->setOp(JSOP_QNAMEPART);
    5862               0 :             } else if (!pn3->isXMLPropertyIdentifier()) {
    5863               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
    5864               0 :                 return NULL;
    5865                 :             }
    5866               9 :             nextMember->setOp(JSOP_DESCENDANTS);
    5867               9 :             nextMember->pn_left = lhs;
    5868               9 :             nextMember->pn_right = pn3;
    5869               9 :             nextMember->pn_pos.begin = lhs->pn_pos.begin;
    5870               9 :             nextMember->pn_pos.end = tokenStream.currentToken().pos.end;
    5871                 :         }
    5872                 : #endif
    5873        44557350 :         else if (tt == TOK_LB) {
    5874         7066533 :             ParseNode *propExpr = expr();
    5875         7066533 :             if (!propExpr)
    5876               0 :                 return NULL;
    5877                 : 
    5878         7066533 :             MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
    5879         7066533 :             TokenPtr begin = lhs->pn_pos.begin, end = tokenStream.currentToken().pos.end;
    5880                 : 
    5881                 :             /*
    5882                 :              * Optimize property name lookups.  If the name is a PropertyName,
    5883                 :              * then make a name-based node so the emitter will use a name-based
    5884                 :              * bytecode.  Otherwise make a node using the property expression
    5885                 :              * by value.  If the node is a string containing an index, convert
    5886                 :              * it to a number to save work later.
    5887                 :              */
    5888                 :             uint32_t index;
    5889         7066533 :             PropertyName *name = NULL;
    5890         7066533 :             if (propExpr->isKind(PNK_STRING)) {
    5891         3425272 :                 JSAtom *atom = propExpr->pn_atom;
    5892         3425272 :                 if (atom->isIndex(&index)) {
    5893               9 :                     propExpr->setKind(PNK_NUMBER);
    5894               9 :                     propExpr->setOp(JSOP_DOUBLE);
    5895               9 :                     propExpr->pn_dval = index;
    5896                 :                 } else {
    5897         3425263 :                     name = atom->asPropertyName();
    5898                 :                 }
    5899         3641261 :             } else if (propExpr->isKind(PNK_NUMBER)) {
    5900                 :                 JSAtom *atom;
    5901         3327351 :                 if (!js_ValueToAtom(context, NumberValue(propExpr->pn_dval), &atom))
    5902               0 :                     return NULL;
    5903         3327351 :                 if (!atom->isIndex(&index))
    5904              72 :                     name = atom->asPropertyName();
    5905                 :             }
    5906                 : 
    5907         7066533 :             if (name)
    5908         3425335 :                 nextMember = new_<PropertyAccess>(lhs, name, begin, end);
    5909                 :             else
    5910         3641198 :                 nextMember = new_<PropertyByValue>(lhs, propExpr, begin, end);
    5911         7066533 :             if (!nextMember)
    5912               0 :                 return NULL;
    5913        37490817 :         } else if (allowCallSyntax && tt == TOK_LP) {
    5914         3172804 :             nextMember = ListNode::create(PNK_LP, tc);
    5915         3172804 :             if (!nextMember)
    5916               0 :                 return NULL;
    5917         3172804 :             nextMember->setOp(JSOP_CALL);
    5918                 : 
    5919         3172804 :             lhs = CheckForImmediatelyAppliedLambda(lhs);
    5920         3172804 :             if (lhs->isOp(JSOP_NAME)) {
    5921          861369 :                 if (lhs->pn_atom == context->runtime->atomState.evalAtom) {
    5922                 :                     /* Select JSOP_EVAL and flag tc as heavyweight. */
    5923            5393 :                     nextMember->setOp(JSOP_EVAL);
    5924            5393 :                     tc->noteCallsEval();
    5925            5393 :                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
    5926                 :                     /*
    5927                 :                      * In non-strict mode code, direct calls to eval can add
    5928                 :                      * variables to the call object.
    5929                 :                      */
    5930            5393 :                     if (!tc->inStrictMode())
    5931            5105 :                         tc->noteHasExtensibleScope();
    5932                 :                 }
    5933         2311435 :             } else if (lhs->isOp(JSOP_GETPROP)) {
    5934                 :                 /* Select JSOP_FUNAPPLY given foo.apply(...). */
    5935         2297746 :                 if (lhs->pn_atom == context->runtime->atomState.applyAtom)
    5936            9033 :                     nextMember->setOp(JSOP_FUNAPPLY);
    5937         2288713 :                 else if (lhs->pn_atom == context->runtime->atomState.callAtom)
    5938           11322 :                     nextMember->setOp(JSOP_FUNCALL);
    5939                 :             }
    5940                 : 
    5941         3172804 :             nextMember->initList(lhs);
    5942         3172804 :             nextMember->pn_pos.begin = lhs->pn_pos.begin;
    5943                 : 
    5944         3172804 :             if (!argumentList(nextMember))
    5945              10 :                 return NULL;
    5946         3172794 :             if (nextMember->pn_count > ARGC_LIMIT) {
    5947                 :                 JS_ReportErrorNumber(context, js_GetErrorMessage, NULL,
    5948               0 :                                      JSMSG_TOO_MANY_FUN_ARGS);
    5949               0 :                 return NULL;
    5950                 :             }
    5951         3172794 :             nextMember->pn_pos.end = tokenStream.currentToken().pos.end;
    5952                 :         } else {
    5953        34318013 :             tokenStream.ungetToken();
    5954        34318013 :             return lhs;
    5955                 :         }
    5956                 : 
    5957        16736188 :         lhs = nextMember;
    5958                 :     }
    5959           34360 :     if (tt == TOK_ERROR)
    5960               0 :         return NULL;
    5961           34360 :     return lhs;
    5962                 : }
    5963                 : 
    5964                 : ParseNode *
    5965         1396176 : Parser::bracketedExpr()
    5966                 : {
    5967                 :     unsigned oldflags;
    5968                 :     ParseNode *pn;
    5969                 : 
    5970                 :     /*
    5971                 :      * Always accept the 'in' operator in a parenthesized expression,
    5972                 :      * where it's unambiguous, even if we might be parsing the init of a
    5973                 :      * for statement.
    5974                 :      */
    5975         1396176 :     oldflags = tc->flags;
    5976         1396176 :     tc->flags &= ~TCF_IN_FOR_INIT;
    5977         1396176 :     pn = expr();
    5978         1396176 :     tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
    5979         1396176 :     return pn;
    5980                 : }
    5981                 : 
    5982                 : #if JS_HAS_XML_SUPPORT
    5983                 : 
    5984                 : ParseNode *
    5985               0 : Parser::endBracketedExpr()
    5986                 : {
    5987               0 :     JS_ASSERT(!tc->inStrictMode());
    5988                 : 
    5989               0 :     ParseNode *pn = bracketedExpr();
    5990               0 :     if (!pn)
    5991               0 :         return NULL;
    5992                 : 
    5993               0 :     MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ATTR_EXPR);
    5994               0 :     return pn;
    5995                 : }
    5996                 : 
    5997                 : /*
    5998                 :  * From the ECMA-357 grammar in 11.1.1 and 11.1.2:
    5999                 :  *
    6000                 :  *      AttributeIdentifier:
    6001                 :  *              @ PropertySelector
    6002                 :  *              @ QualifiedIdentifier
    6003                 :  *              @ [ Expression ]
    6004                 :  *
    6005                 :  *      PropertySelector:
    6006                 :  *              Identifier
    6007                 :  *              *
    6008                 :  *
    6009                 :  *      QualifiedIdentifier:
    6010                 :  *              PropertySelector :: PropertySelector
    6011                 :  *              PropertySelector :: [ Expression ]
    6012                 :  *
    6013                 :  * We adapt AttributeIdentifier and QualifiedIdentier to be LL(1), like so:
    6014                 :  *
    6015                 :  *      AttributeIdentifier:
    6016                 :  *              @ QualifiedIdentifier
    6017                 :  *              @ [ Expression ]
    6018                 :  *
    6019                 :  *      PropertySelector:
    6020                 :  *              Identifier
    6021                 :  *              *
    6022                 :  *
    6023                 :  *      QualifiedIdentifier:
    6024                 :  *              PropertySelector :: PropertySelector
    6025                 :  *              PropertySelector :: [ Expression ]
    6026                 :  *              PropertySelector
    6027                 :  *
    6028                 :  * As PrimaryExpression: Identifier is in ECMA-262 and we want the semantics
    6029                 :  * for that rule to result in a name node, but ECMA-357 extends the grammar
    6030                 :  * to include PrimaryExpression: QualifiedIdentifier, we must factor further:
    6031                 :  *
    6032                 :  *      QualifiedIdentifier:
    6033                 :  *              PropertySelector QualifiedSuffix
    6034                 :  *
    6035                 :  *      QualifiedSuffix:
    6036                 :  *              :: PropertySelector
    6037                 :  *              :: [ Expression ]
    6038                 :  *              /nothing/
    6039                 :  *
    6040                 :  * And use this production instead of PrimaryExpression: QualifiedIdentifier:
    6041                 :  *
    6042                 :  *      PrimaryExpression:
    6043                 :  *              Identifier QualifiedSuffix
    6044                 :  *
    6045                 :  * We hoist the :: match into callers of QualifiedSuffix, in order to tweak
    6046                 :  * PropertySelector vs. Identifier pn_arity, pn_op, and other members.
    6047                 :  */
    6048                 : ParseNode *
    6049              54 : Parser::propertySelector()
    6050                 : {
    6051              54 :     JS_ASSERT(!tc->inStrictMode());
    6052                 : 
    6053                 :     ParseNode *selector;
    6054              54 :     if (tokenStream.isCurrentTokenType(TOK_STAR)) {
    6055              45 :         selector = NullaryNode::create(PNK_ANYNAME, tc);
    6056              45 :         if (!selector)
    6057               0 :             return NULL;
    6058              45 :         selector->setOp(JSOP_ANYNAME);
    6059              45 :         selector->pn_atom = context->runtime->atomState.starAtom;
    6060                 :     } else {
    6061               9 :         JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
    6062               9 :         selector = NullaryNode::create(PNK_NAME, tc);
    6063               9 :         if (!selector)
    6064               0 :             return NULL;
    6065               9 :         selector->setOp(JSOP_QNAMEPART);
    6066               9 :         selector->setArity(PN_NAME);
    6067               9 :         selector->pn_atom = tokenStream.currentToken().name();
    6068               9 :         selector->pn_cookie.makeFree();
    6069                 :     }
    6070              54 :     return selector;
    6071                 : }
    6072                 : 
    6073                 : ParseNode *
    6074              72 : Parser::qualifiedSuffix(ParseNode *pn)
    6075                 : {
    6076              72 :     JS_ASSERT(!tc->inStrictMode());
    6077                 : 
    6078              72 :     JS_ASSERT(tokenStream.currentToken().type == TOK_DBLCOLON);
    6079              72 :     ParseNode *pn2 = NameNode::create(PNK_DBLCOLON, NULL, tc);
    6080              72 :     if (!pn2)
    6081               0 :         return NULL;
    6082                 : 
    6083                 :     /* This qualifiedSuffice may refer to 'arguments'. */
    6084              72 :     tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
    6085                 : 
    6086                 :     /* Left operand of :: must be evaluated if it is an identifier. */
    6087              72 :     if (pn->isOp(JSOP_QNAMEPART))
    6088               0 :         pn->setOp(JSOP_NAME);
    6089                 : 
    6090              72 :     TokenKind tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
    6091              72 :     if (tt == TOK_STAR || tt == TOK_NAME) {
    6092                 :         /* Inline and specialize propertySelector for JSOP_QNAMECONST. */
    6093              72 :         pn2->setOp(JSOP_QNAMECONST);
    6094              72 :         pn2->pn_pos.begin = pn->pn_pos.begin;
    6095                 :         pn2->pn_atom = (tt == TOK_STAR)
    6096                 :                        ? context->runtime->atomState.starAtom
    6097              72 :                        : tokenStream.currentToken().name();
    6098              72 :         pn2->pn_expr = pn;
    6099              72 :         pn2->pn_cookie.makeFree();
    6100              72 :         return pn2;
    6101                 :     }
    6102                 : 
    6103               0 :     if (tt != TOK_LB) {
    6104               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
    6105               0 :         return NULL;
    6106                 :     }
    6107               0 :     ParseNode *pn3 = endBracketedExpr();
    6108               0 :     if (!pn3)
    6109               0 :         return NULL;
    6110                 : 
    6111               0 :     pn2->setOp(JSOP_QNAME);
    6112               0 :     pn2->setArity(PN_BINARY);
    6113               0 :     pn2->pn_pos.begin = pn->pn_pos.begin;
    6114               0 :     pn2->pn_pos.end = pn3->pn_pos.end;
    6115               0 :     pn2->pn_left = pn;
    6116               0 :     pn2->pn_right = pn3;
    6117               0 :     return pn2;
    6118                 : }
    6119                 : 
    6120                 : ParseNode *
    6121              54 : Parser::qualifiedIdentifier()
    6122                 : {
    6123              54 :     JS_ASSERT(!tc->inStrictMode());
    6124                 : 
    6125              54 :     ParseNode *pn = propertySelector();
    6126              54 :     if (!pn)
    6127               0 :         return NULL;
    6128              54 :     if (tokenStream.matchToken(TOK_DBLCOLON)) {
    6129                 :         /* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */
    6130              27 :         tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
    6131              27 :         pn = qualifiedSuffix(pn);
    6132                 :     }
    6133              54 :     return pn;
    6134                 : }
    6135                 : 
    6136                 : ParseNode *
    6137               9 : Parser::attributeIdentifier()
    6138                 : {
    6139               9 :     JS_ASSERT(!tc->inStrictMode());
    6140                 : 
    6141               9 :     JS_ASSERT(tokenStream.currentToken().type == TOK_AT);
    6142               9 :     ParseNode *pn = UnaryNode::create(PNK_AT, tc);
    6143               9 :     if (!pn)
    6144               0 :         return NULL;
    6145               9 :     pn->setOp(JSOP_TOATTRNAME);
    6146                 : 
    6147                 :     ParseNode *pn2;
    6148               9 :     TokenKind tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
    6149               9 :     if (tt == TOK_STAR || tt == TOK_NAME) {
    6150               9 :         pn2 = qualifiedIdentifier();
    6151               0 :     } else if (tt == TOK_LB) {
    6152               0 :         pn2 = endBracketedExpr();
    6153                 :     } else {
    6154               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
    6155               0 :         return NULL;
    6156                 :     }
    6157               9 :     if (!pn2)
    6158               0 :         return NULL;
    6159               9 :     pn->pn_kid = pn2;
    6160               9 :     return pn;
    6161                 : }
    6162                 : 
    6163                 : /*
    6164                 :  * Make a TOK_LC unary node whose pn_kid is an expression.
    6165                 :  */
    6166                 : ParseNode *
    6167               0 : Parser::xmlExpr(JSBool inTag)
    6168                 : {
    6169               0 :     JS_ASSERT(!tc->inStrictMode());
    6170                 : 
    6171               0 :     JS_ASSERT(tokenStream.currentToken().type == TOK_LC);
    6172               0 :     ParseNode *pn = UnaryNode::create(PNK_XMLCURLYEXPR, tc);
    6173               0 :     if (!pn)
    6174               0 :         return NULL;
    6175                 : 
    6176                 :     /*
    6177                 :      * Turn off XML tag mode. We save the old value of the flag because it may
    6178                 :      * already be off: XMLExpr is called both from within a tag, and from
    6179                 :      * within text contained in an element, but outside of any start, end, or
    6180                 :      * point tag.
    6181                 :      */
    6182               0 :     bool oldflag = tokenStream.isXMLTagMode();
    6183               0 :     tokenStream.setXMLTagMode(false);
    6184               0 :     ParseNode *pn2 = expr();
    6185               0 :     if (!pn2)
    6186               0 :         return NULL;
    6187                 : 
    6188               0 :     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_XML_EXPR);
    6189               0 :     tokenStream.setXMLTagMode(oldflag);
    6190               0 :     pn->pn_kid = pn2;
    6191               0 :     pn->setOp(inTag ? JSOP_XMLTAGEXPR : JSOP_XMLELTEXPR);
    6192               0 :     return pn;
    6193                 : }
    6194                 : 
    6195                 : ParseNode *
    6196        10477791 : Parser::atomNode(ParseNodeKind kind, JSOp op)
    6197                 : {
    6198        10477791 :     ParseNode *node = NullaryNode::create(kind, tc);
    6199        10477791 :     if (!node)
    6200               0 :         return NULL;
    6201        10477791 :     node->setOp(op);
    6202        10477791 :     const Token &tok = tokenStream.currentToken();
    6203        10477791 :     node->pn_atom = tok.atom();
    6204        10477791 :     return node;
    6205                 : }
    6206                 : 
    6207                 : /*
    6208                 :  * Parse the productions:
    6209                 :  *
    6210                 :  *      XMLNameExpr:
    6211                 :  *              XMLName XMLNameExpr?
    6212                 :  *              { Expr } XMLNameExpr?
    6213                 :  *
    6214                 :  * Return a PN_LIST, PN_UNARY, or PN_NULLARY according as XMLNameExpr produces
    6215                 :  * a list of names and/or expressions, a single expression, or a single name.
    6216                 :  * If PN_LIST or PN_NULLARY, getKind() will be PNK_XMLNAME.  Otherwise if
    6217                 :  * PN_UNARY, getKind() will be PNK_XMLCURLYEXPR.
    6218                 :  */
    6219                 : ParseNode *
    6220            3438 : Parser::xmlNameExpr()
    6221                 : {
    6222            3438 :     JS_ASSERT(!tc->inStrictMode());
    6223                 : 
    6224                 :     ParseNode *pn, *pn2, *list;
    6225                 :     TokenKind tt;
    6226                 : 
    6227            3438 :     pn = list = NULL;
    6228            3438 :     do {
    6229            3438 :         tt = tokenStream.currentToken().type;
    6230            3438 :         if (tt == TOK_LC) {
    6231               0 :             pn2 = xmlExpr(JS_TRUE);
    6232               0 :             if (!pn2)
    6233               0 :                 return NULL;
    6234                 :         } else {
    6235            3438 :             JS_ASSERT(tt == TOK_XMLNAME);
    6236            3438 :             JS_ASSERT(tokenStream.currentToken().t_op == JSOP_STRING);
    6237            3438 :             pn2 = atomNode(PNK_XMLNAME, JSOP_STRING);
    6238            3438 :             if (!pn2)
    6239               0 :                 return NULL;
    6240                 :         }
    6241                 : 
    6242            3438 :         if (!pn) {
    6243            3438 :             pn = pn2;
    6244                 :         } else {
    6245               0 :             if (!list) {
    6246               0 :                 list = ListNode::create(PNK_XMLNAME, tc);
    6247               0 :                 if (!list)
    6248               0 :                     return NULL;
    6249               0 :                 list->pn_pos.begin = pn->pn_pos.begin;
    6250               0 :                 list->initList(pn);
    6251               0 :                 list->pn_xflags = PNX_CANTFOLD;
    6252               0 :                 pn = list;
    6253                 :             }
    6254               0 :             pn->pn_pos.end = pn2->pn_pos.end;
    6255               0 :             pn->append(pn2);
    6256                 :         }
    6257            3438 :     } while ((tt = tokenStream.getToken()) == TOK_XMLNAME || tt == TOK_LC);
    6258                 : 
    6259            3438 :     tokenStream.ungetToken();
    6260            3438 :     return pn;
    6261                 : }
    6262                 : 
    6263                 : /*
    6264                 :  * Macro to test whether an XMLNameExpr or XMLTagContent node can be folded
    6265                 :  * at compile time into a JSXML tree.
    6266                 :  */
    6267                 : #define XML_FOLDABLE(pn)        ((pn)->isArity(PN_LIST)                     \
    6268                 :                                  ? ((pn)->pn_xflags & PNX_CANTFOLD) == 0    \
    6269                 :                                  : !(pn)->isKind(PNK_XMLCURLYEXPR))
    6270                 : 
    6271                 : /*
    6272                 :  * Parse the productions:
    6273                 :  *
    6274                 :  *      XMLTagContent:
    6275                 :  *              XMLNameExpr
    6276                 :  *              XMLTagContent S XMLNameExpr S? = S? XMLAttr
    6277                 :  *              XMLTagContent S XMLNameExpr S? = S? { Expr }
    6278                 :  *
    6279                 :  * Return a PN_LIST, PN_UNARY, or PN_NULLARY according to how XMLTagContent
    6280                 :  * produces a list of name and attribute values and/or braced expressions, a
    6281                 :  * single expression, or a single name.
    6282                 :  *
    6283                 :  * If PN_LIST or PN_NULLARY, getKind() will be PNK_XMLNAME for the case where
    6284                 :  * XMLTagContent: XMLNameExpr.  If getKind() is not PNK_XMLNAME but getArity()
    6285                 :  * is PN_LIST, getKind() will be tagkind.  If PN_UNARY, getKind() will be
    6286                 :  * PNK_XMLCURLYEXPR and we parsed exactly one expression.
    6287                 :  */
    6288                 : ParseNode *
    6289            2797 : Parser::xmlTagContent(ParseNodeKind tagkind, JSAtom **namep)
    6290                 : {
    6291            2797 :     JS_ASSERT(!tc->inStrictMode());
    6292                 : 
    6293                 :     ParseNode *pn, *pn2, *list;
    6294                 :     TokenKind tt;
    6295                 : 
    6296            2797 :     pn = xmlNameExpr();
    6297            2797 :     if (!pn)
    6298               0 :         return NULL;
    6299            2797 :     *namep = (pn->isArity(PN_NULLARY)) ? pn->pn_atom : NULL;
    6300            2797 :     list = NULL;
    6301                 : 
    6302            6235 :     while (tokenStream.matchToken(TOK_XMLSPACE)) {
    6303             641 :         tt = tokenStream.getToken();
    6304             641 :         if (tt != TOK_XMLNAME && tt != TOK_LC) {
    6305               0 :             tokenStream.ungetToken();
    6306               0 :             break;
    6307                 :         }
    6308                 : 
    6309             641 :         pn2 = xmlNameExpr();
    6310             641 :         if (!pn2)
    6311               0 :             return NULL;
    6312             641 :         if (!list) {
    6313             641 :             list = ListNode::create(tagkind, tc);
    6314             641 :             if (!list)
    6315               0 :                 return NULL;
    6316             641 :             list->pn_pos.begin = pn->pn_pos.begin;
    6317             641 :             list->initList(pn);
    6318             641 :             pn = list;
    6319                 :         }
    6320             641 :         pn->append(pn2);
    6321             641 :         if (!XML_FOLDABLE(pn2))
    6322               0 :             pn->pn_xflags |= PNX_CANTFOLD;
    6323                 : 
    6324             641 :         tokenStream.matchToken(TOK_XMLSPACE);
    6325             641 :         MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_NO_ASSIGN_IN_XML_ATTR);
    6326             641 :         tokenStream.matchToken(TOK_XMLSPACE);
    6327                 : 
    6328             641 :         tt = tokenStream.getToken();
    6329             641 :         if (tt == TOK_XMLATTR) {
    6330             641 :             JS_ASSERT(tokenStream.currentToken().t_op == JSOP_STRING);
    6331             641 :             pn2 = atomNode(PNK_XMLATTR, JSOP_STRING);
    6332               0 :         } else if (tt == TOK_LC) {
    6333               0 :             pn2 = xmlExpr(JS_TRUE);
    6334               0 :             pn->pn_xflags |= PNX_CANTFOLD;
    6335                 :         } else {
    6336               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_ATTR_VALUE);
    6337               0 :             return NULL;
    6338                 :         }
    6339             641 :         if (!pn2)
    6340               0 :             return NULL;
    6341             641 :         pn->pn_pos.end = pn2->pn_pos.end;
    6342             641 :         pn->append(pn2);
    6343                 :     }
    6344                 : 
    6345            2797 :     return pn;
    6346                 : }
    6347                 : 
    6348                 : #define XML_CHECK_FOR_ERROR_AND_EOF(tt,result)                                              \
    6349                 :     JS_BEGIN_MACRO                                                                          \
    6350                 :         if ((tt) <= TOK_EOF) {                                                              \
    6351                 :             if ((tt) == TOK_EOF) {                                                          \
    6352                 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_END_OF_XML_SOURCE);           \
    6353                 :             }                                                                               \
    6354                 :             return result;                                                                  \
    6355                 :         }                                                                                   \
    6356                 :     JS_END_MACRO
    6357                 : 
    6358                 : /*
    6359                 :  * Consume XML element tag content, including the TOK_XMLETAGO (</) sequence
    6360                 :  * that opens the end tag for the container.
    6361                 :  */
    6362                 : JSBool
    6363            1178 : Parser::xmlElementContent(ParseNode *pn)
    6364                 : {
    6365            1178 :     JS_ASSERT(!tc->inStrictMode());
    6366                 : 
    6367            1178 :     tokenStream.setXMLTagMode(false);
    6368             706 :     for (;;) {
    6369            1884 :         TokenKind tt = tokenStream.getToken(TSF_XMLTEXTMODE);
    6370            1884 :         XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE);
    6371                 : 
    6372            1884 :         JS_ASSERT(tt == TOK_XMLSPACE || tt == TOK_XMLTEXT);
    6373            1884 :         JSAtom *textAtom = tokenStream.currentToken().atom();
    6374            1884 :         if (textAtom) {
    6375                 :             /* Non-zero-length XML text scanned. */
    6376             155 :             JS_ASSERT(tokenStream.currentToken().t_op == JSOP_STRING);
    6377                 :             ParseNode *pn2 = atomNode(tt == TOK_XMLSPACE ? PNK_XMLSPACE : PNK_XMLTEXT,
    6378             155 :                                       JSOP_STRING);
    6379             155 :             if (!pn2)
    6380               0 :                 return false;
    6381             155 :             pn->pn_pos.end = pn2->pn_pos.end;
    6382             155 :             pn->append(pn2);
    6383                 :         }
    6384                 : 
    6385            1884 :         tt = tokenStream.getToken(TSF_OPERAND);
    6386            1884 :         XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE);
    6387            1884 :         if (tt == TOK_XMLETAGO)
    6388                 :             break;
    6389                 : 
    6390                 :         ParseNode *pn2;
    6391             706 :         if (tt == TOK_LC) {
    6392               0 :             pn2 = xmlExpr(JS_FALSE);
    6393               0 :             if (!pn2)
    6394               0 :                 return false;
    6395               0 :             pn->pn_xflags |= PNX_CANTFOLD;
    6396             706 :         } else if (tt == TOK_XMLSTAGO) {
    6397             706 :             pn2 = xmlElementOrList(JS_FALSE);
    6398             706 :             if (!pn2)
    6399               0 :                 return false;
    6400             706 :             pn2->pn_xflags &= ~PNX_XMLROOT;
    6401             706 :             pn->pn_xflags |= pn2->pn_xflags;
    6402               0 :         } else if (tt == TOK_XMLPI) {
    6403               0 :             const Token &tok = tokenStream.currentToken();
    6404               0 :             pn2 = new_<XMLProcessingInstruction>(tok.xmlPITarget(), tok.xmlPIData(), tok.pos);
    6405               0 :             if (!pn2)
    6406               0 :                 return false;
    6407                 :         } else {
    6408               0 :             JS_ASSERT(tt == TOK_XMLCDATA || tt == TOK_XMLCOMMENT);
    6409                 :             pn2 = atomNode(tt == TOK_XMLCDATA ? PNK_XMLCDATA : PNK_XMLCOMMENT,
    6410               0 :                            tokenStream.currentToken().t_op);
    6411               0 :             if (!pn2)
    6412               0 :                 return false;
    6413                 :         }
    6414             706 :         pn->pn_pos.end = pn2->pn_pos.end;
    6415             706 :         pn->append(pn2);
    6416                 :     }
    6417            1178 :     tokenStream.setXMLTagMode(true);
    6418                 : 
    6419            1178 :     JS_ASSERT(tokenStream.currentToken().type == TOK_XMLETAGO);
    6420            1178 :     return JS_TRUE;
    6421                 : }
    6422                 : 
    6423                 : /*
    6424                 :  * Return a PN_LIST node containing an XML or XMLList Initialiser.
    6425                 :  */
    6426                 : ParseNode *
    6427            1655 : Parser::xmlElementOrList(JSBool allowList)
    6428                 : {
    6429            1655 :     JS_ASSERT(!tc->inStrictMode());
    6430                 : 
    6431                 :     ParseNode *pn, *pn2, *list;
    6432                 :     TokenKind tt;
    6433                 :     JSAtom *startAtom, *endAtom;
    6434                 : 
    6435            1655 :     JS_CHECK_RECURSION(context, return NULL);
    6436                 : 
    6437            1655 :     JS_ASSERT(tokenStream.currentToken().type == TOK_XMLSTAGO);
    6438            1655 :     pn = ListNode::create(PNK_XMLSTAGO, tc);
    6439            1655 :     if (!pn)
    6440               0 :         return NULL;
    6441                 : 
    6442            1655 :     tokenStream.setXMLTagMode(true);
    6443            1655 :     tt = tokenStream.getToken();
    6444            1655 :     if (tt == TOK_ERROR)
    6445               0 :         return NULL;
    6446                 : 
    6447            1655 :     if (tt == TOK_XMLNAME || tt == TOK_LC) {
    6448                 :         /*
    6449                 :          * XMLElement.  Append the tag and its contents, if any, to pn.
    6450                 :          */
    6451            1637 :         pn2 = xmlTagContent(PNK_XMLSTAGO, &startAtom);
    6452            1637 :         if (!pn2)
    6453               0 :             return NULL;
    6454            1637 :         tokenStream.matchToken(TOK_XMLSPACE);
    6455                 : 
    6456            1637 :         tt = tokenStream.getToken();
    6457            1637 :         if (tt == TOK_XMLPTAGC) {
    6458                 :             /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */
    6459             477 :             if (pn2->isKind(PNK_XMLSTAGO)) {
    6460              18 :                 pn->makeEmpty();
    6461              18 :                 freeTree(pn);
    6462              18 :                 pn = pn2;
    6463                 :             } else {
    6464             459 :                 JS_ASSERT(pn2->isKind(PNK_XMLNAME) || pn2->isKind(PNK_XMLCURLYEXPR));
    6465             459 :                 pn->initList(pn2);
    6466             459 :                 if (!XML_FOLDABLE(pn2))
    6467               0 :                     pn->pn_xflags |= PNX_CANTFOLD;
    6468                 :             }
    6469             477 :             pn->setKind(PNK_XMLPTAGC);
    6470             477 :             pn->pn_xflags |= PNX_XMLROOT;
    6471                 :         } else {
    6472                 :             /* We had better have a tag-close (>) at this point. */
    6473            1160 :             if (tt != TOK_XMLTAGC) {
    6474               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
    6475               0 :                 return NULL;
    6476                 :             }
    6477            1160 :             pn2->pn_pos.end = tokenStream.currentToken().pos.end;
    6478                 : 
    6479                 :             /* Make sure pn2 is a TOK_XMLSTAGO list containing tag contents. */
    6480            1160 :             if (!pn2->isKind(PNK_XMLSTAGO)) {
    6481             537 :                 pn->initList(pn2);
    6482             537 :                 if (!XML_FOLDABLE(pn2))
    6483               0 :                     pn->pn_xflags |= PNX_CANTFOLD;
    6484             537 :                 pn2 = pn;
    6485             537 :                 pn = ListNode::create(PNK_XMLTAGC, tc);
    6486             537 :                 if (!pn)
    6487               0 :                     return NULL;
    6488                 :             }
    6489                 : 
    6490                 :             /* Now make pn a nominal-root TOK_XMLELEM list containing pn2. */
    6491            1160 :             pn->setKind(PNK_XMLELEM);
    6492            1160 :             pn->pn_pos.begin = pn2->pn_pos.begin;
    6493            1160 :             pn->initList(pn2);
    6494            1160 :             if (!XML_FOLDABLE(pn2))
    6495               0 :                 pn->pn_xflags |= PNX_CANTFOLD;
    6496            1160 :             pn->pn_xflags |= PNX_XMLROOT;
    6497                 : 
    6498                 :             /* Get element contents and delimiting end-tag-open sequence. */
    6499            1160 :             if (!xmlElementContent(pn))
    6500               0 :                 return NULL;
    6501                 : 
    6502            1160 :             tt = tokenStream.getToken();
    6503            1160 :             XML_CHECK_FOR_ERROR_AND_EOF(tt, NULL);
    6504            1160 :             if (tt != TOK_XMLNAME && tt != TOK_LC) {
    6505               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
    6506               0 :                 return NULL;
    6507                 :             }
    6508                 : 
    6509                 :             /* Parse end tag; check mismatch at compile-time if we can. */
    6510            1160 :             pn2 = xmlTagContent(PNK_XMLETAGO, &endAtom);
    6511            1160 :             if (!pn2)
    6512               0 :                 return NULL;
    6513            1160 :             if (pn2->isKind(PNK_XMLETAGO)) {
    6514                 :                 /* Oops, end tag has attributes! */
    6515               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
    6516               0 :                 return NULL;
    6517                 :             }
    6518            1160 :             if (endAtom && startAtom && endAtom != startAtom) {
    6519                 :                 /* End vs. start tag name mismatch: point to the tag name. */
    6520                 :                 reportErrorNumber(pn2, JSREPORT_UC | JSREPORT_ERROR, JSMSG_XML_TAG_NAME_MISMATCH,
    6521               0 :                                   startAtom->chars());
    6522               0 :                 return NULL;
    6523                 :             }
    6524                 : 
    6525                 :             /* Make a TOK_XMLETAGO list with pn2 as its single child. */
    6526            1160 :             JS_ASSERT(pn2->isKind(PNK_XMLNAME) || pn2->isKind(PNK_XMLCURLYEXPR));
    6527            1160 :             list = ListNode::create(PNK_XMLETAGO, tc);
    6528            1160 :             if (!list)
    6529               0 :                 return NULL;
    6530            1160 :             list->initList(pn2);
    6531            1160 :             pn->append(list);
    6532            1160 :             if (!XML_FOLDABLE(pn2)) {
    6533               0 :                 list->pn_xflags |= PNX_CANTFOLD;
    6534               0 :                 pn->pn_xflags |= PNX_CANTFOLD;
    6535                 :             }
    6536                 : 
    6537            1160 :             tokenStream.matchToken(TOK_XMLSPACE);
    6538            1160 :             MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX);
    6539                 :         }
    6540                 : 
    6541                 :         /* Set pn_op now that pn has been updated to its final value. */
    6542            1637 :         pn->setOp(JSOP_TOXML);
    6543              18 :     } else if (allowList && tt == TOK_XMLTAGC) {
    6544                 :         /* XMLList Initialiser. */
    6545              18 :         pn->setKind(PNK_XMLLIST);
    6546              18 :         pn->setOp(JSOP_TOXMLLIST);
    6547              18 :         pn->makeEmpty();
    6548              18 :         pn->pn_xflags |= PNX_XMLROOT;
    6549              18 :         if (!xmlElementContent(pn))
    6550               0 :             return NULL;
    6551                 : 
    6552              18 :         MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_LIST_SYNTAX);
    6553                 :     } else {
    6554               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_NAME_SYNTAX);
    6555               0 :         return NULL;
    6556                 :     }
    6557            1655 :     tokenStream.setXMLTagMode(false);
    6558                 : 
    6559            1655 :     pn->pn_pos.end = tokenStream.currentToken().pos.end;
    6560            1655 :     return pn;
    6561                 : }
    6562                 : 
    6563                 : ParseNode *
    6564             949 : Parser::xmlElementOrListRoot(JSBool allowList)
    6565                 : {
    6566             949 :     JS_ASSERT(!tc->inStrictMode());
    6567                 : 
    6568                 :     /*
    6569                 :      * Force XML support to be enabled so that comments and CDATA literals
    6570                 :      * are recognized, instead of <! followed by -- starting an HTML comment
    6571                 :      * to end of line (used in script tags to hide content from old browsers
    6572                 :      * that don't recognize <script>).
    6573                 :      */
    6574             949 :     bool hadXML = tokenStream.hasXML();
    6575             949 :     tokenStream.setXML(true);
    6576             949 :     ParseNode *pn = xmlElementOrList(allowList);
    6577             949 :     tokenStream.setXML(hadXML);
    6578             949 :     return pn;
    6579                 : }
    6580                 : 
    6581                 : ParseNode *
    6582             623 : Parser::parseXMLText(JSObject *chain, bool allowList)
    6583                 : {
    6584                 :     /*
    6585                 :      * Push a compiler frame if we have no frames, or if the top frame is a
    6586                 :      * lightweight function activation, or if its scope chain doesn't match
    6587                 :      * the one passed to us.
    6588                 :      */
    6589            1246 :     TreeContext xmltc(this);
    6590             623 :     if (!xmltc.init(context))
    6591               0 :         return NULL;
    6592             623 :     JS_ASSERT(!xmltc.inStrictMode());
    6593             623 :     xmltc.setScopeChain(chain);
    6594                 : 
    6595                 :     /* Set XML-only mode to turn off special treatment of {expr} in XML. */
    6596             623 :     tokenStream.setXMLOnlyMode();
    6597             623 :     TokenKind tt = tokenStream.getToken(TSF_OPERAND);
    6598                 : 
    6599                 :     ParseNode *pn;
    6600             623 :     if (tt != TOK_XMLSTAGO) {
    6601               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP);
    6602               0 :         pn = NULL;
    6603                 :     } else {
    6604             623 :         pn = xmlElementOrListRoot(allowList);
    6605                 :     }
    6606             623 :     tokenStream.setXMLOnlyMode(false);
    6607                 : 
    6608             623 :     return pn;
    6609                 : }
    6610                 : 
    6611                 : #endif /* JS_HAS_XMLSUPPORT */
    6612                 : 
    6613                 : bool
    6614               9 : Parser::checkForFunctionNode(PropertyName *name, ParseNode *node)
    6615                 : {
    6616                 :     /*
    6617                 :      * In |a.ns::name|, |ns| refers to an in-scope variable, so |ns| can't be a
    6618                 :      * keyword.  (Exception: |function::name| is the actual name property, not
    6619                 :      * what E4X would expose.)  We parsed |ns| accepting a keyword as a name,
    6620                 :      * so we must implement the keyword restriction manually in this case.
    6621                 :      */
    6622               9 :     if (const KeywordInfo *ki = FindKeyword(name->charsZ(), name->length())) {
    6623               9 :         if (ki->tokentype != TOK_FUNCTION) {
    6624               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_KEYWORD_NOT_NS);
    6625               0 :             return false;
    6626                 :         }
    6627                 : 
    6628               9 :         node->setArity(PN_NULLARY);
    6629               9 :         node->setKind(PNK_FUNCTION);
    6630                 :     }
    6631                 : 
    6632               9 :     return true;
    6633                 : }
    6634                 : 
    6635                 : #if JS_HAS_XML_SUPPORT
    6636                 : ParseNode *
    6637               9 : Parser::propertyQualifiedIdentifier()
    6638                 : {
    6639               9 :     JS_ASSERT(!tc->inStrictMode());
    6640               9 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
    6641               9 :     JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME);
    6642               9 :     JS_ASSERT(tokenStream.peekToken() == TOK_DBLCOLON);
    6643                 : 
    6644                 :     /* Deoptimize QualifiedIdentifier properties to avoid tricky analysis. */
    6645               9 :     tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
    6646                 : 
    6647               9 :     PropertyName *name = tokenStream.currentToken().name();
    6648               9 :     ParseNode *node = NameNode::create(PNK_NAME, name, tc);
    6649               9 :     if (!node)
    6650               0 :         return NULL;
    6651               9 :     node->setOp(JSOP_NAME);
    6652               9 :     node->pn_dflags |= PND_DEOPTIMIZED;
    6653                 : 
    6654               9 :     if (!checkForFunctionNode(name, node))
    6655               0 :         return NULL;
    6656                 : 
    6657               9 :     tokenStream.consumeKnownToken(TOK_DBLCOLON);
    6658               9 :     return qualifiedSuffix(node);
    6659                 : }
    6660                 : #endif
    6661                 : 
    6662                 : ParseNode *
    6663        13876124 : Parser::identifierName(bool afterDoubleDot)
    6664                 : {
    6665        13876124 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
    6666                 : 
    6667        13876124 :     PropertyName *name = tokenStream.currentToken().name();
    6668        13876124 :     ParseNode *node = NameNode::create(PNK_NAME, name, tc);
    6669        13876124 :     if (!node)
    6670               0 :         return NULL;
    6671        13876124 :     JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME);
    6672        13876124 :     node->setOp(JSOP_NAME);
    6673                 : 
    6674        13876124 :     if ((tc->flags & (TCF_IN_FUNCTION | TCF_FUN_PARAM_ARGUMENTS)) == TCF_IN_FUNCTION &&
    6675                 :         name == context->runtime->atomState.argumentsAtom)
    6676                 :     {
    6677                 :         /*
    6678                 :          * Bind early to JSOP_ARGUMENTS to relieve later code from having
    6679                 :          * to do this work (new rule for the emitter to count on).
    6680                 :          */
    6681           27694 :         if (!afterDoubleDot) {
    6682                 :             /*
    6683                 :              * Note use of |arguments| to ensure we can properly create the
    6684                 :              * |arguments| object for this function.
    6685                 :              */
    6686           13838 :             tc->noteArgumentsNameUse(node);
    6687                 : 
    6688           13838 :             if (!(tc->flags & TCF_DECL_DESTRUCTURING) && !tc->inStatement(STMT_WITH)) {
    6689           13838 :                 node->setOp(JSOP_ARGUMENTS);
    6690           13838 :                 node->pn_dflags |= PND_BOUND;
    6691                 :             }
    6692                 :         }
    6693        27724554 :     } else if ((!afterDoubleDot
    6694                 : #if JS_HAS_XML_SUPPORT
    6695               0 :                 || (!tc->inStrictMode() && tokenStream.peekToken() == TOK_DBLCOLON)
    6696                 : #endif
    6697        13862277 :                ) && !(tc->flags & TCF_DECL_DESTRUCTURING))
    6698                 :     {
    6699                 :         /* In case this is a generator expression outside of any function. */
    6700        13833948 :         if (!tc->inFunction() && name == context->runtime->atomState.argumentsAtom)
    6701             352 :             tc->countArgumentsUse(node);
    6702                 : 
    6703        13833948 :         StmtInfo *stmt = LexicalLookup(tc, name, NULL);
    6704                 : 
    6705        13833948 :         MultiDeclRange mdl = tc->decls.lookupMulti(name);
    6706                 : 
    6707                 :         Definition *dn;
    6708        13833948 :         if (!mdl.empty()) {
    6709         5661014 :             dn = mdl.front();
    6710                 :         } else {
    6711         8172934 :             if (AtomDefnAddPtr p = tc->lexdeps->lookupForAdd(name)) {
    6712         5876520 :                 dn = p.value();
    6713                 :             } else {
    6714                 :                 /*
    6715                 :                  * No definition before this use in any lexical scope.
    6716                 :                  * Create a placeholder definition node to either:
    6717                 :                  * - Be adopted when we parse the real defining
    6718                 :                  *   declaration, or
    6719                 :                  * - Be left as a free variable definition if we never
    6720                 :                  *   see the real definition.
    6721                 :                  */
    6722         2296414 :                 dn = MakePlaceholder(node, tc);
    6723         2296414 :                 if (!dn || !tc->lexdeps->add(p, name, dn))
    6724               0 :                     return NULL;
    6725                 : 
    6726                 :                 /*
    6727                 :                  * In case this is a forward reference to a function,
    6728                 :                  * we pessimistically set PND_FUNARG if the next token
    6729                 :                  * is not a left parenthesis.
    6730                 :                  *
    6731                 :                  * If the definition eventually parsed into dn is not a
    6732                 :                  * function, this flag won't hurt, and if we do parse a
    6733                 :                  * function with pn's name, then the PND_FUNARG flag is
    6734                 :                  * necessary for safe context->display-based optimiza-
    6735                 :                  * tion of the closure's static link.
    6736                 :                  */
    6737         2296414 :                 if (tokenStream.peekToken() != TOK_LP)
    6738         1670366 :                     dn->pn_dflags |= PND_FUNARG;
    6739                 :             }
    6740                 :         }
    6741                 : 
    6742        13833948 :         JS_ASSERT(dn->isDefn());
    6743        13833948 :         LinkUseToDef(node, dn, tc);
    6744                 : 
    6745                 :         /* Here we handle the backward function reference case. */
    6746        13833948 :         if (tokenStream.peekToken() != TOK_LP)
    6747        12831178 :             dn->pn_dflags |= PND_FUNARG;
    6748                 : 
    6749        13833948 :         node->pn_dflags |= (dn->pn_dflags & PND_FUNARG);
    6750        13833948 :         if (stmt && stmt->type == STMT_WITH)
    6751             702 :             node->pn_dflags |= PND_DEOPTIMIZED;
    6752                 :     }
    6753                 : 
    6754                 : #if JS_HAS_XML_SUPPORT
    6755        13876124 :     if (!tc->inStrictMode() && tokenStream.matchToken(TOK_DBLCOLON)) {
    6756               9 :         if (afterDoubleDot) {
    6757               0 :             if (!checkForFunctionNode(name, node))
    6758               0 :                 return NULL;
    6759                 :         }
    6760               9 :         node = qualifiedSuffix(node);
    6761               9 :         if (!node)
    6762               0 :             return NULL;
    6763                 :     }
    6764                 : #endif
    6765                 : 
    6766        13876124 :     return node;
    6767                 : }
    6768                 : 
    6769                 : #if JS_HAS_XML_SUPPORT
    6770                 : ParseNode *
    6771              72 : Parser::starOrAtPropertyIdentifier(TokenKind tt)
    6772                 : {
    6773              72 :     JS_ASSERT(tt == TOK_AT || tt == TOK_STAR);
    6774              72 :     if (tc->inStrictMode()) {
    6775              18 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
    6776              18 :         return NULL;
    6777                 :     }
    6778              54 :     return (tt == TOK_AT) ? attributeIdentifier() : qualifiedIdentifier();
    6779                 : }
    6780                 : #endif
    6781                 : 
    6782                 : ParseNode *
    6783        34210845 : Parser::primaryExpr(TokenKind tt, bool afterDoubleDot)
    6784                 : {
    6785        34210845 :     JS_ASSERT(tokenStream.isCurrentTokenType(tt));
    6786                 : 
    6787                 :     ParseNode *pn, *pn2, *pn3;
    6788                 :     JSOp op;
    6789                 : 
    6790        34210845 :     JS_CHECK_RECURSION(context, return NULL);
    6791                 : 
    6792        34210845 :     switch (tt) {
    6793                 :       case TOK_FUNCTION:
    6794                 : #if JS_HAS_XML_SUPPORT
    6795          683853 :         if (!tc->inStrictMode() && tokenStream.matchToken(TOK_DBLCOLON, TSF_KEYWORD_IS_NAME)) {
    6796              27 :             pn2 = NullaryNode::create(PNK_FUNCTION, tc);
    6797              27 :             if (!pn2)
    6798               0 :                 return NULL;
    6799              27 :             pn = qualifiedSuffix(pn2);
    6800              27 :             if (!pn)
    6801               0 :                 return NULL;
    6802              27 :             break;
    6803                 :         }
    6804                 : #endif
    6805          683826 :         pn = functionExpr();
    6806          683826 :         if (!pn)
    6807               9 :             return NULL;
    6808          683817 :         break;
    6809                 : 
    6810                 :       case TOK_LB:
    6811                 :       {
    6812                 :         JSBool matched;
    6813                 :         unsigned index;
    6814                 : 
    6815          249940 :         pn = ListNode::create(PNK_RB, tc);
    6816          249940 :         if (!pn)
    6817               0 :             return NULL;
    6818          249940 :         pn->setOp(JSOP_NEWINIT);
    6819          249940 :         pn->makeEmpty();
    6820                 : 
    6821                 : #if JS_HAS_GENERATORS
    6822          249940 :         pn->pn_blockid = tc->blockidGen;
    6823                 : #endif
    6824                 : 
    6825          249940 :         matched = tokenStream.matchToken(TOK_RB, TSF_OPERAND);
    6826          249940 :         if (!matched) {
    6827         5360518 :             for (index = 0; ; index++) {
    6828         5360518 :                 if (index == StackSpace::ARGS_LENGTH_MAX) {
    6829               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG);
    6830               0 :                     return NULL;
    6831                 :                 }
    6832                 : 
    6833         5360518 :                 tt = tokenStream.peekToken(TSF_OPERAND);
    6834         5360518 :                 if (tt == TOK_RB) {
    6835            3321 :                     pn->pn_xflags |= PNX_ENDCOMMA;
    6836            3321 :                     break;
    6837                 :                 }
    6838                 : 
    6839         5357197 :                 if (tt == TOK_COMMA) {
    6840                 :                     /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */
    6841            5941 :                     tokenStream.matchToken(TOK_COMMA);
    6842            5941 :                     pn2 = NullaryNode::create(PNK_COMMA, tc);
    6843            5941 :                     pn->pn_xflags |= PNX_HOLEY | PNX_NONCONST;
    6844                 :                 } else {
    6845         5351256 :                     pn2 = assignExpr();
    6846         5351256 :                     if (pn2 && !pn2->isConstant())
    6847          125669 :                         pn->pn_xflags |= PNX_NONCONST;
    6848                 :                 }
    6849         5357197 :                 if (!pn2)
    6850               0 :                     return NULL;
    6851         5357197 :                 pn->append(pn2);
    6852                 : 
    6853         5357197 :                 if (tt != TOK_COMMA) {
    6854                 :                     /* If we didn't already match TOK_COMMA in above case. */
    6855         5351256 :                     if (!tokenStream.matchToken(TOK_COMMA))
    6856          158931 :                         break;
    6857                 :                 }
    6858                 :             }
    6859                 : 
    6860                 : #if JS_HAS_GENERATORS
    6861                 :             /*
    6862                 :              * At this point, (index == 0 && pn->pn_count != 0) implies one
    6863                 :              * element initialiser was parsed.
    6864                 :              *
    6865                 :              * An array comprehension of the form:
    6866                 :              *
    6867                 :              *   [i * j for (i in o) for (j in p) if (i != j)]
    6868                 :              *
    6869                 :              * translates to roughly the following let expression:
    6870                 :              *
    6871                 :              *   let (array = new Array, i, j) {
    6872                 :              *     for (i in o) let {
    6873                 :              *       for (j in p)
    6874                 :              *         if (i != j)
    6875                 :              *           array.push(i * j)
    6876                 :              *     }
    6877                 :              *     array
    6878                 :              *   }
    6879                 :              *
    6880                 :              * where array is a nameless block-local variable. The "roughly"
    6881                 :              * means that an implementation may optimize away the array.push.
    6882                 :              * An array comprehension opens exactly one block scope, no matter
    6883                 :              * how many for heads it contains.
    6884                 :              *
    6885                 :              * Each let () {...} or for (let ...) ... compiles to:
    6886                 :              *
    6887                 :              *   JSOP_ENTERBLOCK <o> ... JSOP_LEAVEBLOCK <n>
    6888                 :              *
    6889                 :              * where <o> is a literal object representing the block scope,
    6890                 :              * with <n> properties, naming each var declared in the block.
    6891                 :              *
    6892                 :              * Each var declaration in a let-block binds a name in <o> at
    6893                 :              * compile time, and allocates a slot on the operand stack at
    6894                 :              * runtime via JSOP_ENTERBLOCK. A block-local var is accessed by
    6895                 :              * the JSOP_GETLOCAL and JSOP_SETLOCAL ops. These ops have an
    6896                 :              * immediate operand, the local slot's stack index from fp->spbase.
    6897                 :              *
    6898                 :              * The array comprehension iteration step, array.push(i * j) in
    6899                 :              * the example above, is done by <i * j>; JSOP_ARRAYCOMP <array>,
    6900                 :              * where <array> is the index of array's stack slot.
    6901                 :              */
    6902          162252 :             if (index == 0 && pn->pn_count != 0 && tokenStream.matchToken(TOK_FOR)) {
    6903                 :                 ParseNode *pnexp, *pntop;
    6904                 : 
    6905                 :                 /* Relabel pn as an array comprehension node. */
    6906           12858 :                 pn->setKind(PNK_ARRAYCOMP);
    6907                 : 
    6908                 :                 /*
    6909                 :                  * Remove the comprehension expression from pn's linked list
    6910                 :                  * and save it via pnexp.  We'll re-install it underneath the
    6911                 :                  * ARRAYPUSH node after we parse the rest of the comprehension.
    6912                 :                  */
    6913           12858 :                 pnexp = pn->last();
    6914           12858 :                 JS_ASSERT(pn->pn_count == 1);
    6915           12858 :                 pn->pn_count = 0;
    6916           12858 :                 pn->pn_tail = &pn->pn_head;
    6917           12858 :                 *pn->pn_tail = NULL;
    6918                 : 
    6919                 :                 pntop = comprehensionTail(pnexp, pn->pn_blockid, false,
    6920           12858 :                                           PNK_ARRAYPUSH, JSOP_ARRAYPUSH);
    6921           12858 :                 if (!pntop)
    6922             135 :                     return NULL;
    6923           12723 :                 pn->append(pntop);
    6924                 :             }
    6925                 : #endif /* JS_HAS_GENERATORS */
    6926                 : 
    6927          162117 :             MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST);
    6928                 :         }
    6929          249805 :         pn->pn_pos.end = tokenStream.currentToken().pos.end;
    6930          249805 :         return pn;
    6931                 :       }
    6932                 : 
    6933                 :       case TOK_LC:
    6934                 :       {
    6935                 :         ParseNode *pnval;
    6936                 : 
    6937                 :         /*
    6938                 :          * A map from property names we've seen thus far to a mask of property
    6939                 :          * assignment types, stored and retrieved with ALE_SET_INDEX/ALE_INDEX.
    6940                 :          */
    6941          437688 :         AtomIndexMap seen(context);
    6942                 : 
    6943                 :         enum AssignmentType {
    6944                 :             GET     = 0x1,
    6945                 :             SET     = 0x2,
    6946                 :             VALUE   = 0x4 | GET | SET
    6947                 :         };
    6948                 : 
    6949          218844 :         pn = ListNode::create(PNK_RC, tc);
    6950          218844 :         if (!pn)
    6951               0 :             return NULL;
    6952          218844 :         pn->setOp(JSOP_NEWINIT);
    6953          218844 :         pn->makeEmpty();
    6954                 : 
    6955          735855 :         for (;;) {
    6956                 :             JSAtom *atom;
    6957          954699 :             TokenKind ltok = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
    6958          954699 :             TokenPtr begin = tokenStream.currentToken().pos.begin;
    6959          954699 :             switch (ltok) {
    6960                 :               case TOK_NUMBER:
    6961            4003 :                 pn3 = NullaryNode::create(PNK_NUMBER, tc);
    6962            4003 :                 if (!pn3)
    6963               0 :                     return NULL;
    6964            4003 :                 pn3->pn_dval = tokenStream.currentToken().number();
    6965            4003 :                 if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom))
    6966               0 :                     return NULL;
    6967            4003 :                 break;
    6968                 :               case TOK_NAME:
    6969                 :                 {
    6970          848181 :                     atom = tokenStream.currentToken().name();
    6971          848181 :                     if (atom == context->runtime->atomState.getAtom) {
    6972           56355 :                         op = JSOP_GETTER;
    6973          791826 :                     } else if (atom == context->runtime->atomState.setAtom) {
    6974           13749 :                         op = JSOP_SETTER;
    6975                 :                     } else {
    6976          778077 :                         pn3 = NullaryNode::create(PNK_NAME, tc);
    6977          778077 :                         if (!pn3)
    6978               0 :                             return NULL;
    6979          778077 :                         pn3->pn_atom = atom;
    6980          778077 :                         break;
    6981                 :                     }
    6982                 : 
    6983           70104 :                     tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
    6984           70104 :                     if (tt == TOK_NAME) {
    6985           67597 :                         atom = tokenStream.currentToken().name();
    6986           67597 :                         pn3 = NameNode::create(PNK_NAME, atom, tc);
    6987           67597 :                         if (!pn3)
    6988               0 :                             return NULL;
    6989            2507 :                     } else if (tt == TOK_STRING) {
    6990               0 :                         atom = tokenStream.currentToken().atom();
    6991                 : 
    6992                 :                         uint32_t index;
    6993               0 :                         if (atom->isIndex(&index)) {
    6994               0 :                             pn3 = NullaryNode::create(PNK_NUMBER, tc);
    6995               0 :                             if (!pn3)
    6996               0 :                                 return NULL;
    6997               0 :                             pn3->pn_dval = index;
    6998               0 :                             if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom))
    6999               0 :                                 return NULL;
    7000                 :                         } else {
    7001               0 :                             pn3 = NameNode::create(PNK_STRING, atom, tc);
    7002               0 :                             if (!pn3)
    7003               0 :                                 return NULL;
    7004                 :                         }
    7005            2507 :                     } else if (tt == TOK_NUMBER) {
    7006               0 :                         pn3 = NullaryNode::create(PNK_NUMBER, tc);
    7007               0 :                         if (!pn3)
    7008               0 :                             return NULL;
    7009               0 :                         pn3->pn_dval = tokenStream.currentToken().number();
    7010               0 :                         if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom))
    7011               0 :                             return NULL;
    7012                 :                     } else {
    7013            2507 :                         tokenStream.ungetToken();
    7014            2507 :                         pn3 = NullaryNode::create(PNK_NAME, tc);
    7015            2507 :                         if (!pn3)
    7016               0 :                             return NULL;
    7017            2507 :                         pn3->pn_atom = atom;
    7018            2507 :                         break;
    7019                 :                     }
    7020                 : 
    7021           67597 :                     pn->pn_xflags |= PNX_NONCONST;
    7022                 : 
    7023                 :                     /* NB: Getter function in { get x(){} } is unnamed. */
    7024           67597 :                     pn2 = functionDef(NULL, op == JSOP_GETTER ? Getter : Setter, Expression);
    7025           67597 :                     if (!pn2)
    7026               0 :                         return NULL;
    7027           67597 :                     TokenPos pos = {begin, pn2->pn_pos.end};
    7028           67597 :                     pn2 = new_<BinaryNode>(PNK_COLON, op, pos, pn3, pn2);
    7029           67597 :                     goto skip;
    7030                 :                 }
    7031                 :               case TOK_STRING: {
    7032           24221 :                 atom = tokenStream.currentToken().atom();
    7033                 :                 uint32_t index;
    7034           24221 :                 if (atom->isIndex(&index)) {
    7035             508 :                     pn3 = NullaryNode::create(PNK_NUMBER, tc);
    7036             508 :                     if (!pn3)
    7037               0 :                         return NULL;
    7038             508 :                     pn3->pn_dval = index;
    7039                 :                 } else {
    7040           23713 :                     pn3 = NullaryNode::create(PNK_STRING, tc);
    7041           23713 :                     if (!pn3)
    7042               0 :                         return NULL;
    7043           23713 :                     pn3->pn_atom = atom;
    7044                 :                 }
    7045           24221 :                 break;
    7046                 :               }
    7047                 :               case TOK_RC:
    7048           78294 :                 goto end_obj_init;
    7049                 :               default:
    7050               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_PROP_ID);
    7051               0 :                 return NULL;
    7052                 :             }
    7053                 : 
    7054          808808 :             op = JSOP_INITPROP;
    7055          808808 :             tt = tokenStream.getToken();
    7056          808808 :             if (tt == TOK_COLON) {
    7057          808610 :                 pnval = assignExpr();
    7058          808610 :                 if (!pnval)
    7059               9 :                     return NULL;
    7060                 : 
    7061                 :                 /*
    7062                 :                  * Treat initializers which mutate __proto__ as non-constant,
    7063                 :                  * so that we can later assume singleton objects delegate to
    7064                 :                  * the default Object.prototype.
    7065                 :                  */
    7066          808601 :                 if (!pnval->isConstant() || atom == context->runtime->atomState.protoAtom)
    7067          586426 :                     pn->pn_xflags |= PNX_NONCONST;
    7068                 :             }
    7069                 : #if JS_HAS_DESTRUCTURING_SHORTHAND
    7070             198 :             else if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) {
    7071                 :                 /*
    7072                 :                  * Support, e.g., |var {x, y} = o| as destructuring shorthand
    7073                 :                  * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
    7074                 :                  */
    7075             198 :                 tokenStream.ungetToken();
    7076             198 :                 if (!tokenStream.checkForKeyword(atom->charsZ(), atom->length(), NULL, NULL))
    7077               0 :                     return NULL;
    7078             198 :                 pn->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST;
    7079             198 :                 pnval = pn3;
    7080             198 :                 JS_ASSERT(pnval->isKind(PNK_NAME));
    7081             198 :                 pnval->setArity(PN_NAME);
    7082             198 :                 ((NameNode *)pnval)->initCommon(tc);
    7083                 :             }
    7084                 : #endif
    7085                 :             else {
    7086               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_COLON_AFTER_ID);
    7087               0 :                 return NULL;
    7088                 :             }
    7089                 : 
    7090                 :             {
    7091          808799 :                 TokenPos pos = {begin, pnval->pn_pos.end};
    7092          808799 :                 pn2 = new_<BinaryNode>(PNK_COLON, op, pos, pn3, pnval);
    7093                 :             }
    7094                 :           skip:
    7095          876396 :             if (!pn2)
    7096               0 :                 return NULL;
    7097          876396 :             pn->append(pn2);
    7098                 : 
    7099                 :             /*
    7100                 :              * Check for duplicate property names.  Duplicate data properties
    7101                 :              * only conflict in strict mode.  Duplicate getter or duplicate
    7102                 :              * setter halves always conflict.  A data property conflicts with
    7103                 :              * any part of an accessor property.
    7104                 :              */
    7105                 :             AssignmentType assignType;
    7106          876396 :             if (op == JSOP_INITPROP) {
    7107          808799 :                 assignType = VALUE;
    7108           67597 :             } else if (op == JSOP_GETTER) {
    7109           54484 :                 assignType = GET;
    7110           13113 :             } else if (op == JSOP_SETTER) {
    7111           13113 :                 assignType = SET;
    7112                 :             } else {
    7113               0 :                 JS_NOT_REACHED("bad opcode in object initializer");
    7114                 :                 assignType = VALUE; /* try to error early */
    7115                 :             }
    7116                 : 
    7117          876396 :             AtomIndexAddPtr p = seen.lookupForAdd(atom);
    7118          876396 :             if (p) {
    7119           13017 :                 jsatomid index = p.value();
    7120           13017 :                 AssignmentType oldAssignType = AssignmentType(index);
    7121           13114 :                 if ((oldAssignType & assignType) &&
    7122              97 :                     (oldAssignType != VALUE || assignType != VALUE || tc->needStrictChecks()))
    7123                 :                 {
    7124              12 :                     JSAutoByteString name;
    7125               6 :                     if (!js_AtomToPrintableString(context, atom, &name))
    7126               0 :                         return NULL;
    7127                 : 
    7128                 :                     unsigned flags = (oldAssignType == VALUE &&
    7129                 :                                    assignType == VALUE &&
    7130               6 :                                    !tc->inStrictMode())
    7131                 :                                   ? JSREPORT_WARNING
    7132              12 :                                   : JSREPORT_ERROR;
    7133               6 :                     if (!ReportCompileErrorNumber(context, &tokenStream, NULL, flags,
    7134               6 :                                                   JSMSG_DUPLICATE_PROPERTY, name.ptr()))
    7135                 :                     {
    7136               0 :                         return NULL;
    7137                 :                     }
    7138                 :                 }
    7139           13017 :                 p.value() = assignType | oldAssignType;
    7140                 :             } else {
    7141          863379 :                 if (!seen.add(p, atom, assignType))
    7142               0 :                     return NULL;
    7143                 :             }
    7144                 : 
    7145          876396 :             tt = tokenStream.getToken();
    7146          876396 :             if (tt == TOK_RC)
    7147          140541 :                 goto end_obj_init;
    7148          735855 :             if (tt != TOK_COMMA) {
    7149               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CURLY_AFTER_LIST);
    7150               0 :                 return NULL;
    7151                 :             }
    7152                 :         }
    7153                 : 
    7154                 :       end_obj_init:
    7155          218835 :         pn->pn_pos.end = tokenStream.currentToken().pos.end;
    7156          218835 :         return pn;
    7157                 :       }
    7158                 : 
    7159                 : #if JS_HAS_BLOCK_SCOPE
    7160                 :       case TOK_LET:
    7161            1826 :         pn = letBlock(LetExpresion);
    7162            1826 :         if (!pn)
    7163               0 :             return NULL;
    7164            1826 :         break;
    7165                 : #endif
    7166                 : 
    7167                 :       case TOK_LP:
    7168                 :       {
    7169                 :         JSBool genexp;
    7170                 : 
    7171          376323 :         pn = parenExpr(&genexp);
    7172          376323 :         if (!pn)
    7173              27 :             return NULL;
    7174          376296 :         pn->setInParens(true);
    7175          376296 :         if (!genexp)
    7176          376110 :             MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
    7177          376296 :         break;
    7178                 :       }
    7179                 : 
    7180                 :       case TOK_STRING:
    7181        10473530 :         pn = atomNode(PNK_STRING, JSOP_STRING);
    7182        10473530 :         if (!pn)
    7183               0 :             return NULL;
    7184        10473530 :         break;
    7185                 : 
    7186                 : #if JS_HAS_XML_SUPPORT
    7187                 :       case TOK_AT:
    7188                 :       case TOK_STAR:
    7189              72 :         pn = starOrAtPropertyIdentifier(tt);
    7190              72 :         break;
    7191                 : 
    7192                 :       case TOK_XMLSTAGO:
    7193             326 :         pn = xmlElementOrListRoot(JS_TRUE);
    7194             326 :         if (!pn)
    7195               0 :             return NULL;
    7196             326 :         break;
    7197                 : 
    7198                 :       case TOK_XMLCDATA:
    7199              27 :         JS_ASSERT(!tc->inStrictMode());
    7200              27 :         pn = atomNode(PNK_XMLCDATA, JSOP_XMLCDATA);
    7201              27 :         if (!pn)
    7202               0 :             return NULL;
    7203              27 :         break;
    7204                 : 
    7205                 :       case TOK_XMLCOMMENT:
    7206               0 :         JS_ASSERT(!tc->inStrictMode());
    7207               0 :         pn = atomNode(PNK_XMLCOMMENT, JSOP_XMLCOMMENT);
    7208               0 :         if (!pn)
    7209               0 :             return NULL;
    7210               0 :         break;
    7211                 : 
    7212                 :       case TOK_XMLPI: {
    7213               0 :         JS_ASSERT(!tc->inStrictMode());
    7214               0 :         const Token &tok = tokenStream.currentToken();
    7215               0 :         pn = new_<XMLProcessingInstruction>(tok.xmlPITarget(), tok.xmlPIData(), tok.pos);
    7216               0 :         if (!pn)
    7217               0 :             return NULL;
    7218               0 :         break;
    7219                 :       }
    7220                 : #endif
    7221                 : 
    7222                 :       case TOK_NAME:
    7223        13876124 :         pn = identifierName(afterDoubleDot);
    7224        13876124 :         break;
    7225                 : 
    7226                 :       case TOK_REGEXP:
    7227                 :       {
    7228           34059 :         pn = NullaryNode::create(PNK_REGEXP, tc);
    7229           34059 :         if (!pn)
    7230               0 :             return NULL;
    7231                 : 
    7232           34059 :         const jschar *chars = tokenStream.getTokenbuf().begin();
    7233           34059 :         size_t length = tokenStream.getTokenbuf().length();
    7234           34059 :         RegExpFlag flags = tokenStream.currentToken().regExpFlags();
    7235           34059 :         RegExpStatics *res = context->regExpStatics();
    7236                 : 
    7237                 :         RegExpObject *reobj;
    7238           34059 :         if (context->hasfp())
    7239            6150 :             reobj = RegExpObject::create(context, res, chars, length, flags, &tokenStream);
    7240                 :         else
    7241           27909 :             reobj = RegExpObject::createNoStatics(context, chars, length, flags, &tokenStream);
    7242                 : 
    7243           34059 :         if (!reobj)
    7244               9 :             return NULL;
    7245                 : 
    7246           34050 :         if (!tc->compileAndGo()) {
    7247           30411 :             if (!reobj->clearParent(context))
    7248               0 :                 return NULL;
    7249           30411 :             if (!reobj->clearType(context))
    7250               0 :                 return NULL;
    7251                 :         }
    7252                 : 
    7253           34050 :         pn->pn_objbox = tc->parser->newObjectBox(reobj);
    7254           34050 :         if (!pn->pn_objbox)
    7255               0 :             return NULL;
    7256                 : 
    7257           34050 :         pn->setOp(JSOP_REGEXP);
    7258           34050 :         break;
    7259                 :       }
    7260                 : 
    7261                 :       case TOK_NUMBER:
    7262         5907885 :         pn = NullaryNode::create(PNK_NUMBER, tc);
    7263         5907885 :         if (!pn)
    7264               0 :             return NULL;
    7265         5907885 :         pn->setOp(JSOP_DOUBLE);
    7266         5907885 :         pn->pn_dval = tokenStream.currentToken().number();
    7267         5907885 :         break;
    7268                 : 
    7269                 :       case TOK_TRUE:
    7270          178968 :         return new_<BooleanLiteral>(true, tokenStream.currentToken().pos);
    7271                 :       case TOK_FALSE:
    7272          210635 :         return new_<BooleanLiteral>(false, tokenStream.currentToken().pos);
    7273                 :       case TOK_THIS:
    7274         1673696 :         return new_<ThisLiteral>(tokenStream.currentToken().pos);
    7275                 :       case TOK_NULL:
    7276          324714 :         return new_<NullLiteral>(tokenStream.currentToken().pos);
    7277                 : 
    7278                 :       case TOK_ERROR:
    7279                 :         /* The scanner or one of its subroutines reported the error. */
    7280               0 :         return NULL;
    7281                 : 
    7282                 :       default:
    7283              23 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
    7284              23 :         return NULL;
    7285                 :     }
    7286        31353980 :     return pn;
    7287                 : }
    7288                 : 
    7289                 : ParseNode *
    7290         1396113 : Parser::parenExpr(JSBool *genexp)
    7291                 : {
    7292                 :     TokenPtr begin;
    7293                 :     ParseNode *pn;
    7294                 : 
    7295         1396113 :     JS_ASSERT(tokenStream.currentToken().type == TOK_LP);
    7296         1396113 :     begin = tokenStream.currentToken().pos.begin;
    7297                 : 
    7298         1396113 :     if (genexp)
    7299          376323 :         *genexp = JS_FALSE;
    7300                 : 
    7301         1396113 :     GenexpGuard guard(tc);
    7302                 : 
    7303         1396113 :     pn = bracketedExpr();
    7304         1396113 :     if (!pn)
    7305              18 :         return NULL;
    7306         1396095 :     guard.endBody();
    7307                 : 
    7308                 : #if JS_HAS_GENERATOR_EXPRS
    7309         1396095 :     if (tokenStream.matchToken(TOK_FOR)) {
    7310             195 :         if (!guard.checkValidBody(pn))
    7311               9 :             return NULL;
    7312             186 :         JS_ASSERT(!pn->isKind(PNK_YIELD));
    7313             186 :         if (pn->isKind(PNK_COMMA) && !pn->isInParens()) {
    7314                 :             reportErrorNumber(pn->last(), JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX,
    7315               0 :                               js_generator_str);
    7316               0 :             return NULL;
    7317                 :         }
    7318             186 :         pn = generatorExpr(pn);
    7319             186 :         if (!pn)
    7320               0 :             return NULL;
    7321             186 :         pn->pn_pos.begin = begin;
    7322             186 :         if (genexp) {
    7323             186 :             if (tokenStream.getToken() != TOK_RP) {
    7324                 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX,
    7325               0 :                                   js_generator_str);
    7326               0 :                 return NULL;
    7327                 :             }
    7328             186 :             pn->pn_pos.end = tokenStream.currentToken().pos.end;
    7329             186 :             *genexp = JS_TRUE;
    7330                 :         }
    7331                 :     } else
    7332                 : #endif /* JS_HAS_GENERATOR_EXPRS */
    7333                 : 
    7334         1395900 :     if (!guard.maybeNoteGenerator(pn))
    7335               0 :         return NULL;
    7336                 : 
    7337         1396086 :     return pn;
    7338                 : }

Generated by: LCOV version 1.7