LCOV - code coverage report
Current view: directory - js/src/frontend - BytecodeEmitter.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 3359 2602 77.5 %
Date: 2012-04-07 Functions: 141 137 97.2 %

       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 bytecode generation.
      43                 :  */
      44                 : #ifdef HAVE_MEMORY_H
      45                 : #include <memory.h>
      46                 : #endif
      47                 : #include <new>
      48                 : #include <string.h>
      49                 : 
      50                 : #include "jstypes.h"
      51                 : #include "jsutil.h"
      52                 : #include "jsprf.h"
      53                 : #include "jsapi.h"
      54                 : #include "jsatom.h"
      55                 : #include "jsbool.h"
      56                 : #include "jscntxt.h"
      57                 : #include "jsversion.h"
      58                 : #include "jsfun.h"
      59                 : #include "jsnum.h"
      60                 : #include "jsopcode.h"
      61                 : #include "jsscope.h"
      62                 : #include "jsscript.h"
      63                 : #include "jsautooplen.h"        // generated headers last
      64                 : 
      65                 : #include "ds/LifoAlloc.h"
      66                 : #include "frontend/BytecodeCompiler.h"
      67                 : #include "frontend/BytecodeEmitter.h"
      68                 : #include "frontend/Parser.h"
      69                 : #include "frontend/TokenStream.h"
      70                 : #include "vm/RegExpObject.h"
      71                 : 
      72                 : #include "jsatominlines.h"
      73                 : #include "jsscopeinlines.h"
      74                 : #include "jsscriptinlines.h"
      75                 : 
      76                 : #include "frontend/BytecodeEmitter-inl.h"
      77                 : #include "frontend/ParseMaps-inl.h"
      78                 : 
      79                 : /* Allocation chunk counts, must be powers of two in general. */
      80                 : #define BYTECODE_CHUNK_LENGTH  1024    /* initial bytecode chunk length */
      81                 : #define SRCNOTE_CHUNK_LENGTH   1024    /* initial srcnote chunk length */
      82                 : 
      83                 : /* Macros to compute byte sizes from typed element counts. */
      84                 : #define BYTECODE_SIZE(n)        ((n) * sizeof(jsbytecode))
      85                 : #define SRCNOTE_SIZE(n)         ((n) * sizeof(jssrcnote))
      86                 : 
      87                 : using namespace js;
      88                 : using namespace js::gc;
      89                 : using namespace js::frontend;
      90                 : 
      91                 : static JSBool
      92                 : NewTryNote(JSContext *cx, BytecodeEmitter *bce, JSTryNoteKind kind, unsigned stackDepth,
      93                 :            size_t start, size_t end);
      94                 : 
      95                 : static JSBool
      96                 : SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, unsigned index, unsigned which, ptrdiff_t offset);
      97                 : 
      98                 : void
      99               6 : TreeContext::trace(JSTracer *trc)
     100                 : {
     101               6 :     bindings.trace(trc);
     102               6 : }
     103                 : 
     104          259599 : BytecodeEmitter::BytecodeEmitter(Parser *parser, unsigned lineno)
     105                 :   : TreeContext(parser),
     106                 :     atomIndices(parser->context),
     107                 :     stackDepth(0), maxStackDepth(0),
     108                 :     ntrynotes(0), lastTryNode(NULL),
     109                 :     arrayCompDepth(0),
     110                 :     emitLevel(0),
     111                 :     constMap(parser->context),
     112                 :     constList(parser->context),
     113                 :     globalScope(NULL),
     114                 :     globalUses(parser->context),
     115                 :     globalMap(parser->context),
     116                 :     closedArgs(parser->context),
     117                 :     closedVars(parser->context),
     118          259599 :     typesetCount(0)
     119                 : {
     120          259599 :     flags = TCF_COMPILING;
     121          259599 :     memset(&prolog, 0, sizeof prolog);
     122          259599 :     memset(&main, 0, sizeof main);
     123          259599 :     current = &main;
     124          259599 :     firstLine = prolog.currentLine = main.currentLine = lineno;
     125          259599 : }
     126                 : 
     127                 : bool
     128          259599 : BytecodeEmitter::init(JSContext *cx, TreeContext::InitBehavior ib)
     129                 : {
     130          259599 :     roLexdeps.init();
     131          259599 :     return TreeContext::init(cx, ib) && constMap.init() && atomIndices.ensureMap(cx);
     132                 : }
     133                 : 
     134          519198 : BytecodeEmitter::~BytecodeEmitter()
     135                 : {
     136          259599 :     JSContext *cx = parser->context;
     137                 : 
     138          259599 :     cx->free_(prolog.base);
     139          259599 :     cx->free_(prolog.notes);
     140          259599 :     cx->free_(main.base);
     141          259599 :     cx->free_(main.notes);
     142          259599 : }
     143                 : 
     144                 : static ptrdiff_t
     145         9217984 : EmitCheck(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t delta)
     146                 : {
     147         9217984 :     jsbytecode *base = bce->base();
     148                 :     jsbytecode *newbase;
     149         9217984 :     jsbytecode *next = bce->next();
     150         9217984 :     jsbytecode *limit = bce->limit();
     151         9217984 :     ptrdiff_t offset = next - base;
     152         9217984 :     size_t minlength = offset + delta;
     153                 : 
     154         9217984 :     if (next + delta > limit) {
     155                 :         size_t newlength;
     156          284891 :         if (!base) {
     157          282911 :             JS_ASSERT(!next && !limit);
     158          282911 :             newlength = BYTECODE_CHUNK_LENGTH;
     159          282911 :             if (newlength < minlength)     /* make it bigger if necessary */
     160               0 :                 newlength = RoundUpPow2(minlength);
     161          282911 :             newbase = (jsbytecode *) cx->malloc_(BYTECODE_SIZE(newlength));
     162                 :         } else {
     163            1980 :             JS_ASSERT(base <= next && next <= limit);
     164            1980 :             newlength = (limit - base) * 2;
     165            1980 :             if (newlength < minlength)     /* make it bigger if necessary */
     166               0 :                 newlength = RoundUpPow2(minlength);
     167            1980 :             newbase = (jsbytecode *) cx->realloc_(base, BYTECODE_SIZE(newlength));
     168                 :         }
     169          284891 :         if (!newbase) {
     170               0 :             js_ReportOutOfMemory(cx);
     171               0 :             return -1;
     172                 :         }
     173          284891 :         JS_ASSERT(newlength >= size_t(offset + delta));
     174          284891 :         bce->current->base = newbase;
     175          284891 :         bce->current->limit = newbase + newlength;
     176          284891 :         bce->current->next = newbase + offset;
     177                 :     }
     178         9217984 :     return offset;
     179                 : }
     180                 : 
     181                 : static StaticBlockObject &
     182           98335 : CurrentBlock(BytecodeEmitter *bce)
     183                 : {
     184           98335 :     JS_ASSERT(bce->topStmt->type == STMT_BLOCK || bce->topStmt->type == STMT_SWITCH);
     185           98335 :     JS_ASSERT(bce->topStmt->blockObj->isStaticBlock());
     186           98335 :     return *bce->topStmt->blockObj;
     187                 : }
     188                 : 
     189                 : static void
     190         9217984 : UpdateDepth(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t target)
     191                 : {
     192         9217984 :     jsbytecode *pc = bce->code(target);
     193         9217984 :     JSOp op = (JSOp) *pc;
     194         9217984 :     const JSCodeSpec *cs = &js_CodeSpec[op];
     195                 : 
     196                 : 
     197         9217984 :     if (cs->format & JOF_TMPSLOT_MASK) {
     198                 :         /*
     199                 :          * An opcode may temporarily consume stack space during execution.
     200                 :          * Account for this in maxStackDepth separately from uses/defs here.
     201                 :          */
     202                 :         unsigned depth = (unsigned) bce->stackDepth +
     203          102425 :                       ((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT);
     204          102425 :         if (depth > bce->maxStackDepth)
     205           40228 :             bce->maxStackDepth = depth;
     206                 :     }
     207                 : 
     208                 :     /*
     209                 :      * Specially handle any case that would call js_GetIndexFromBytecode since
     210                 :      * it requires a well-formed script. This allows us to safely pass NULL as
     211                 :      * the 'script' parameter.
     212                 :      */
     213                 :     int nuses, ndefs;
     214         9217984 :     if (op == JSOP_ENTERBLOCK) {
     215           88677 :         nuses = 0;
     216           88677 :         ndefs = CurrentBlock(bce).slotCount();
     217         9129307 :     } else if (op == JSOP_ENTERLET0) {
     218            8416 :         nuses = ndefs = CurrentBlock(bce).slotCount();
     219         9120891 :     } else if (op == JSOP_ENTERLET1) {
     220            1242 :         nuses = ndefs = CurrentBlock(bce).slotCount() + 1;
     221                 :     } else {
     222         9119649 :         nuses = StackUses(NULL, pc);
     223         9119649 :         ndefs = StackDefs(NULL, pc);
     224                 :     }
     225                 : 
     226         9217984 :     bce->stackDepth -= nuses;
     227         9217984 :     JS_ASSERT(bce->stackDepth >= 0);
     228         9217984 :     bce->stackDepth += ndefs;
     229         9217984 :     if ((unsigned)bce->stackDepth > bce->maxStackDepth)
     230          625545 :         bce->maxStackDepth = bce->stackDepth;
     231         9217984 : }
     232                 : 
     233                 : static inline void
     234            8283 : UpdateDecomposeLength(BytecodeEmitter *bce, unsigned start)
     235                 : {
     236            8283 :     unsigned end = bce->offset();
     237            8283 :     JS_ASSERT(unsigned(end - start) < 256);
     238            8283 :     bce->code(start)[-1] = end - start;
     239            8283 : }
     240                 : 
     241                 : ptrdiff_t
     242         4433891 : frontend::Emit1(JSContext *cx, BytecodeEmitter *bce, JSOp op)
     243                 : {
     244         4433891 :     JS_ASSERT_IF(op == JSOP_ARGUMENTS, !bce->mayOverwriteArguments());
     245                 : 
     246         4433891 :     ptrdiff_t offset = EmitCheck(cx, bce, 1);
     247                 : 
     248         4433891 :     if (offset >= 0) {
     249         4433891 :         *bce->current->next++ = (jsbytecode)op;
     250         4433891 :         UpdateDepth(cx, bce, offset);
     251                 :     }
     252         4433891 :     return offset;
     253                 : }
     254                 : 
     255                 : ptrdiff_t
     256          216438 : frontend::Emit2(JSContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1)
     257                 : {
     258          216438 :     ptrdiff_t offset = EmitCheck(cx, bce, 2);
     259                 : 
     260          216438 :     if (offset >= 0) {
     261          216438 :         jsbytecode *next = bce->next();
     262          216438 :         next[0] = (jsbytecode)op;
     263          216438 :         next[1] = op1;
     264          216438 :         bce->current->next = next + 2;
     265          216438 :         UpdateDepth(cx, bce, offset);
     266                 :     }
     267          216438 :     return offset;
     268                 : }
     269                 : 
     270                 : ptrdiff_t
     271         1216984 : frontend::Emit3(JSContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1,
     272                 :                     jsbytecode op2)
     273                 : {
     274         1216984 :     ptrdiff_t offset = EmitCheck(cx, bce, 3);
     275                 : 
     276         1216984 :     if (offset >= 0) {
     277         1216984 :         jsbytecode *next = bce->next();
     278         1216984 :         next[0] = (jsbytecode)op;
     279         1216984 :         next[1] = op1;
     280         1216984 :         next[2] = op2;
     281         1216984 :         bce->current->next = next + 3;
     282         1216984 :         UpdateDepth(cx, bce, offset);
     283                 :     }
     284         1216984 :     return offset;
     285                 : }
     286                 : 
     287                 : ptrdiff_t
     288           17485 : frontend::EmitN(JSContext *cx, BytecodeEmitter *bce, JSOp op, size_t extra)
     289                 : {
     290           17485 :     ptrdiff_t length = 1 + (ptrdiff_t)extra;
     291           17485 :     ptrdiff_t offset = EmitCheck(cx, bce, length);
     292                 : 
     293           17485 :     if (offset >= 0) {
     294           17485 :         jsbytecode *next = bce->next();
     295           17485 :         *next = (jsbytecode)op;
     296           17485 :         memset(next + 1, 0, BYTECODE_SIZE(extra));
     297           17485 :         bce->current->next = next + length;
     298                 : 
     299                 :         /*
     300                 :          * Don't UpdateDepth if op's use-count comes from the immediate
     301                 :          * operand yet to be stored in the extra bytes after op.
     302                 :          */
     303           17485 :         if (js_CodeSpec[op].nuses >= 0)
     304           17485 :             UpdateDepth(cx, bce, offset);
     305                 :     }
     306           17485 :     return offset;
     307                 : }
     308                 : 
     309                 : static ptrdiff_t
     310          356387 : EmitJump(JSContext *cx, BytecodeEmitter *bce, JSOp op, ptrdiff_t off)
     311                 : {
     312          356387 :     ptrdiff_t offset = EmitCheck(cx, bce, 5);
     313                 : 
     314          356387 :     if (offset >= 0) {
     315          356387 :         jsbytecode *next = bce->next();
     316          356387 :         next[0] = (jsbytecode)op;
     317          356387 :         SET_JUMP_OFFSET(next, off);
     318          356387 :         bce->current->next = next + 5;
     319          356387 :         UpdateDepth(cx, bce, offset);
     320                 :     }
     321          356387 :     return offset;
     322                 : }
     323                 : 
     324                 : /* XXX too many "... statement" L10N gaffes below -- fix via js.msg! */
     325                 : const char js_with_statement_str[] = "with statement";
     326                 : const char js_finally_block_str[]  = "finally block";
     327                 : const char js_script_str[]         = "script";
     328                 : 
     329                 : static const char *statementName[] = {
     330                 :     "label statement",       /* LABEL */
     331                 :     "if statement",          /* IF */
     332                 :     "else statement",        /* ELSE */
     333                 :     "destructuring body",    /* BODY */
     334                 :     "switch statement",      /* SWITCH */
     335                 :     "block",                 /* BLOCK */
     336                 :     js_with_statement_str,   /* WITH */
     337                 :     "catch block",           /* CATCH */
     338                 :     "try block",             /* TRY */
     339                 :     js_finally_block_str,    /* FINALLY */
     340                 :     js_finally_block_str,    /* SUBROUTINE */
     341                 :     "do loop",               /* DO_LOOP */
     342                 :     "for loop",              /* FOR_LOOP */
     343                 :     "for/in loop",           /* FOR_IN_LOOP */
     344                 :     "while loop",            /* WHILE_LOOP */
     345                 : };
     346                 : 
     347                 : JS_STATIC_ASSERT(JS_ARRAY_LENGTH(statementName) == STMT_LIMIT);
     348                 : 
     349                 : static const char *
     350               0 : StatementName(BytecodeEmitter *bce)
     351                 : {
     352               0 :     if (!bce->topStmt)
     353               0 :         return js_script_str;
     354               0 :     return statementName[bce->topStmt->type];
     355                 : }
     356                 : 
     357                 : static void
     358               0 : ReportStatementTooLarge(JSContext *cx, BytecodeEmitter *bce)
     359                 : {
     360                 :     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET,
     361               0 :                          StatementName(bce));
     362               0 : }
     363                 : 
     364                 : bool
     365            4284 : TreeContext::inStatement(StmtType type)
     366                 : {
     367           11133 :     for (StmtInfo *stmt = topStmt; stmt; stmt = stmt->down) {
     368            6849 :         if (stmt->type == type)
     369               0 :             return true;
     370                 :     }
     371            4284 :     return false;
     372                 : }
     373                 : 
     374                 : bool
     375               0 : TreeContext::skipSpansGenerator(unsigned skip)
     376                 : {
     377               0 :     TreeContext *tc = this;
     378               0 :     for (unsigned i = 0; i < skip; ++i, tc = tc->parent) {
     379               0 :         if (!tc)
     380               0 :             return false;
     381               0 :         if (tc->flags & TCF_FUN_IS_GENERATOR)
     382               0 :             return true;
     383                 :     }
     384               0 :     return false;
     385                 : }
     386                 : 
     387                 : bool
     388          251616 : frontend::SetStaticLevel(TreeContext *tc, unsigned staticLevel)
     389                 : {
     390                 :     /*
     391                 :      * This is a lot simpler than error-checking every UpvarCookie::set, and
     392                 :      * practically speaking it leaves more than enough room for upvars.
     393                 :      */
     394          251616 :     if (UpvarCookie::isLevelReserved(staticLevel)) {
     395                 :         JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL,
     396               0 :                              JSMSG_TOO_DEEP, js_function_str);
     397               0 :         return false;
     398                 :     }
     399          251616 :     tc->staticLevel = staticLevel;
     400          251616 :     return true;
     401                 : }
     402                 : 
     403                 : bool
     404          551422 : frontend::GenerateBlockId(TreeContext *tc, uint32_t &blockid)
     405                 : {
     406          551422 :     if (tc->blockidGen == JS_BIT(20)) {
     407                 :         JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL,
     408               0 :                              JSMSG_NEED_DIET, "program");
     409               0 :         return false;
     410                 :     }
     411          551422 :     blockid = tc->blockidGen++;
     412          551422 :     return true;
     413                 : }
     414                 : 
     415                 : void
     416         1331960 : frontend::PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top)
     417                 : {
     418         1331960 :     stmt->type = type;
     419         1331960 :     stmt->flags = 0;
     420         1331960 :     stmt->blockid = tc->blockid();
     421         1331960 :     SET_STATEMENT_TOP(stmt, top);
     422         1331960 :     stmt->label = NULL;
     423         1331960 :     JS_ASSERT(!stmt->blockObj);
     424         1331960 :     stmt->down = tc->topStmt;
     425         1331960 :     tc->topStmt = stmt;
     426         1331960 :     if (STMT_LINKS_SCOPE(stmt)) {
     427            1368 :         stmt->downScope = tc->topScopeStmt;
     428            1368 :         tc->topScopeStmt = stmt;
     429                 :     } else {
     430         1330592 :         stmt->downScope = NULL;
     431                 :     }
     432         1331960 : }
     433                 : 
     434                 : void
     435          197273 : frontend::PushBlockScope(TreeContext *tc, StmtInfo *stmt, StaticBlockObject &blockObj, ptrdiff_t top)
     436                 : {
     437          197273 :     PushStatement(tc, stmt, STMT_BLOCK, top);
     438          197273 :     stmt->flags |= SIF_SCOPE;
     439          197273 :     blockObj.setEnclosingBlock(tc->blockChain);
     440          197273 :     stmt->downScope = tc->topScopeStmt;
     441          197273 :     tc->topScopeStmt = stmt;
     442          197273 :     tc->blockChain = &blockObj;
     443          197273 :     stmt->blockObj = &blockObj;
     444          197273 : }
     445                 : 
     446                 : /*
     447                 :  * Emit a backpatch op with offset pointing to the previous jump of this type,
     448                 :  * so that we can walk back up the chain fixing up the op and jump offset.
     449                 :  */
     450                 : static ptrdiff_t
     451          179470 : EmitBackPatchOp(JSContext *cx, BytecodeEmitter *bce, JSOp op, ptrdiff_t *lastp)
     452                 : {
     453                 :     ptrdiff_t offset, delta;
     454                 : 
     455          179470 :     offset = bce->offset();
     456          179470 :     delta = offset - *lastp;
     457          179470 :     *lastp = offset;
     458          179470 :     JS_ASSERT(delta > 0);
     459          179470 :     return EmitJump(cx, bce, op, delta);
     460                 : }
     461                 : 
     462                 : /* A macro for inlining at the top of EmitTree (whence it came). */
     463                 : #define UPDATE_LINE_NUMBER_NOTES(cx, bce, line)                               \
     464                 :     JS_BEGIN_MACRO                                                            \
     465                 :         unsigned line_ = (line);                                                 \
     466                 :         unsigned delta_ = line_ - bce->currentLine();                            \
     467                 :         if (delta_ != 0) {                                                    \
     468                 :             /*                                                                \
     469                 :              * Encode any change in the current source line number by using   \
     470                 :              * either several SRC_NEWLINE notes or just one SRC_SETLINE note, \
     471                 :              * whichever consumes less space.                                 \
     472                 :              *                                                                \
     473                 :              * NB: We handle backward line number deltas (possible with for   \
     474                 :              * loops where the update part is emitted after the body, but its \
     475                 :              * line number is <= any line number in the body) here by letting \
     476                 :              * unsigned delta_ wrap to a very large number, which triggers a  \
     477                 :              * SRC_SETLINE.                                                   \
     478                 :              */                                                               \
     479                 :             bce->current->currentLine = line_;                                \
     480                 :             if (delta_ >= (unsigned)(2 + ((line_ > SN_3BYTE_OFFSET_MASK)<<1))) { \
     481                 :                 if (NewSrcNote2(cx, bce, SRC_SETLINE, (ptrdiff_t)line_) < 0)  \
     482                 :                     return JS_FALSE;                                          \
     483                 :             } else {                                                          \
     484                 :                 do {                                                          \
     485                 :                     if (NewSrcNote(cx, bce, SRC_NEWLINE) < 0)                 \
     486                 :                         return JS_FALSE;                                      \
     487                 :                 } while (--delta_ != 0);                                      \
     488                 :             }                                                                 \
     489                 :         }                                                                     \
     490                 :     JS_END_MACRO
     491                 : 
     492                 : /* A function, so that we avoid macro-bloating all the other callsites. */
     493                 : static JSBool
     494          590807 : UpdateLineNumberNotes(JSContext *cx, BytecodeEmitter *bce, unsigned line)
     495                 : {
     496          590807 :     UPDATE_LINE_NUMBER_NOTES(cx, bce, line);
     497          590807 :     return JS_TRUE;
     498                 : }
     499                 : 
     500                 : static ptrdiff_t
     501           31957 : EmitLoopHead(JSContext *cx, BytecodeEmitter *bce, ParseNode *nextpn)
     502                 : {
     503           31957 :     if (nextpn) {
     504                 :         /*
     505                 :          * Try to give the JSOP_LOOPHEAD the same line number as the next
     506                 :          * instruction. nextpn is often a block, in which case the next
     507                 :          * instruction typically comes from the first statement inside.
     508                 :          */
     509           27276 :         JS_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
     510           27276 :         if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
     511           11615 :             nextpn = nextpn->pn_head;
     512           27276 :         if (!UpdateLineNumberNotes(cx, bce, nextpn->pn_pos.begin.lineno))
     513               0 :             return -1;
     514                 :     }
     515                 : 
     516           31957 :     return Emit1(cx, bce, JSOP_LOOPHEAD);
     517                 : }
     518                 : 
     519                 : static bool
     520           31957 : EmitLoopEntry(JSContext *cx, BytecodeEmitter *bce, ParseNode *nextpn)
     521                 : {
     522           31957 :     if (nextpn) {
     523                 :         /* Update the line number, as for LOOPHEAD. */
     524           27015 :         JS_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
     525           27015 :         if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
     526             252 :             nextpn = nextpn->pn_head;
     527           27015 :         if (!UpdateLineNumberNotes(cx, bce, nextpn->pn_pos.begin.lineno))
     528               0 :             return false;
     529                 :     }
     530                 : 
     531           31957 :     return Emit1(cx, bce, JSOP_LOOPENTRY) >= 0;
     532                 : }
     533                 : 
     534                 : /*
     535                 :  * If op is JOF_TYPESET (see the type barriers comment in jsinfer.h), reserve
     536                 :  * a type set to store its result.
     537                 :  */
     538                 : static inline void
     539         4249988 : CheckTypeSet(JSContext *cx, BytecodeEmitter *bce, JSOp op)
     540                 : {
     541         4249988 :     if (js_CodeSpec[op].format & JOF_TYPESET) {
     542         2226939 :         if (bce->typesetCount < UINT16_MAX)
     543         2226939 :             bce->typesetCount++;
     544                 :     }
     545         4249988 : }
     546                 : 
     547                 : /*
     548                 :  * Macro to emit a bytecode followed by a uint16_t immediate operand stored in
     549                 :  * big-endian order, used for arg and var numbers as well as for atomIndexes.
     550                 :  * NB: We use cx and bce from our caller's lexical environment, and return
     551                 :  * false on error.
     552                 :  */
     553                 : #define EMIT_UINT16_IMM_OP(op, i)                                             \
     554                 :     JS_BEGIN_MACRO                                                            \
     555                 :         if (Emit3(cx, bce, op, UINT16_HI(i), UINT16_LO(i)) < 0)               \
     556                 :             return JS_FALSE;                                                  \
     557                 :         CheckTypeSet(cx, bce, op);                                            \
     558                 :     JS_END_MACRO
     559                 : 
     560                 : #define EMIT_UINT16PAIR_IMM_OP(op, i, j)                                      \
     561                 :     JS_BEGIN_MACRO                                                            \
     562                 :         ptrdiff_t off_ = EmitN(cx, bce, op, 2 * UINT16_LEN);                  \
     563                 :         if (off_ < 0)                                                         \
     564                 :             return JS_FALSE;                                                  \
     565                 :         jsbytecode *pc_ = bce->code(off_);                                    \
     566                 :         SET_UINT16(pc_, i);                                                   \
     567                 :         pc_ += UINT16_LEN;                                                    \
     568                 :         SET_UINT16(pc_, j);                                                   \
     569                 :     JS_END_MACRO
     570                 : 
     571                 : #define EMIT_UINT16_IN_PLACE(offset, op, i)                                   \
     572                 :     JS_BEGIN_MACRO                                                            \
     573                 :         bce->code(offset)[0] = op;                                            \
     574                 :         bce->code(offset)[1] = UINT16_HI(i);                                  \
     575                 :         bce->code(offset)[2] = UINT16_LO(i);                                  \
     576                 :     JS_END_MACRO
     577                 : 
     578                 : #define EMIT_UINT32_IN_PLACE(offset, op, i)                                   \
     579                 :     JS_BEGIN_MACRO                                                            \
     580                 :         bce->code(offset)[0] = op;                                            \
     581                 :         bce->code(offset)[1] = jsbytecode(i >> 24);                           \
     582                 :         bce->code(offset)[2] = jsbytecode(i >> 16);                           \
     583                 :         bce->code(offset)[3] = jsbytecode(i >> 8);                            \
     584                 :         bce->code(offset)[4] = jsbytecode(i);                                 \
     585                 :     JS_END_MACRO
     586                 : 
     587                 : static JSBool
     588              18 : FlushPops(JSContext *cx, BytecodeEmitter *bce, int *npops)
     589                 : {
     590              18 :     JS_ASSERT(*npops != 0);
     591              18 :     if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
     592               0 :         return JS_FALSE;
     593              18 :     EMIT_UINT16_IMM_OP(JSOP_POPN, *npops);
     594              18 :     *npops = 0;
     595              18 :     return JS_TRUE;
     596                 : }
     597                 : 
     598                 : static bool
     599             459 : PopIterator(JSContext *cx, BytecodeEmitter *bce)
     600                 : {
     601             459 :     if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
     602               0 :         return false;
     603             459 :     if (Emit1(cx, bce, JSOP_ENDITER) < 0)
     604               0 :         return false;
     605             459 :     return true;
     606                 : }
     607                 : 
     608                 : /*
     609                 :  * Emit additional bytecode(s) for non-local jumps.
     610                 :  */
     611                 : static JSBool
     612           42895 : EmitNonLocalJumpFixup(JSContext *cx, BytecodeEmitter *bce, StmtInfo *toStmt)
     613                 : {
     614                 :     /*
     615                 :      * The non-local jump fixup we emit will unbalance bce->stackDepth, because
     616                 :      * the fixup replicates balanced code such as JSOP_LEAVEWITH emitted at the
     617                 :      * end of a with statement, so we save bce->stackDepth here and restore it
     618                 :      * just before a successful return.
     619                 :      */
     620           42895 :     int depth = bce->stackDepth;
     621           42895 :     int npops = 0;
     622                 : 
     623                 : #define FLUSH_POPS() if (npops && !FlushPops(cx, bce, &npops)) return JS_FALSE
     624                 : 
     625          107030 :     for (StmtInfo *stmt = bce->topStmt; stmt != toStmt; stmt = stmt->down) {
     626           64225 :         switch (stmt->type) {
     627                 :           case STMT_FINALLY:
     628              27 :             FLUSH_POPS();
     629              27 :             if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
     630               0 :                 return JS_FALSE;
     631              27 :             if (EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, &GOSUBS(*stmt)) < 0)
     632               0 :                 return JS_FALSE;
     633              27 :             break;
     634                 : 
     635                 :           case STMT_WITH:
     636                 :             /* There's a With object on the stack that we need to pop. */
     637              54 :             FLUSH_POPS();
     638              54 :             if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
     639               0 :                 return JS_FALSE;
     640              54 :             if (Emit1(cx, bce, JSOP_LEAVEWITH) < 0)
     641               0 :                 return JS_FALSE;
     642              54 :             break;
     643                 : 
     644                 :           case STMT_FOR_IN_LOOP:
     645             171 :             FLUSH_POPS();
     646             171 :             if (!PopIterator(cx, bce))
     647               0 :                 return JS_FALSE;
     648             171 :             break;
     649                 : 
     650                 :           case STMT_SUBROUTINE:
     651                 :             /*
     652                 :              * There's a [exception or hole, retsub pc-index] pair on the
     653                 :              * stack that we need to pop.
     654                 :              */
     655              18 :             npops += 2;
     656              18 :             break;
     657                 : 
     658                 :           default:;
     659                 :         }
     660                 : 
     661           64225 :         if (stmt->flags & SIF_SCOPE) {
     662            4360 :             FLUSH_POPS();
     663            4360 :             unsigned blockObjCount = stmt->blockObj->slotCount();
     664            4360 :             if (stmt->flags & SIF_FOR_BLOCK) {
     665                 :                 /*
     666                 :                  * For a for-let-in statement, pushing/popping the block is
     667                 :                  * interleaved with JSOP_(END)ITER. Just handle both together
     668                 :                  * here and skip over the enclosing STMT_FOR_IN_LOOP.
     669                 :                  */
     670             378 :                 JS_ASSERT(stmt->down->type == STMT_FOR_IN_LOOP);
     671             378 :                 stmt = stmt->down;
     672             378 :                 if (stmt == toStmt)
     673              90 :                     break;
     674             288 :                 if (Emit1(cx, bce, JSOP_LEAVEFORLETIN) < 0)
     675               0 :                     return JS_FALSE;
     676             288 :                 if (!PopIterator(cx, bce))
     677               0 :                     return JS_FALSE;
     678             288 :                 if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
     679               0 :                     return JS_FALSE;
     680             288 :                 EMIT_UINT16_IMM_OP(JSOP_POPN, blockObjCount);
     681                 :             } else {
     682                 :                 /* There is a Block object with locals on the stack to pop. */
     683            3982 :                 if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
     684               0 :                     return JS_FALSE;
     685            3982 :                 EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObjCount);
     686                 :             }
     687                 :         }
     688                 :     }
     689                 : 
     690           42895 :     FLUSH_POPS();
     691           42895 :     bce->stackDepth = depth;
     692           42895 :     return JS_TRUE;
     693                 : 
     694                 : #undef FLUSH_POPS
     695                 : }
     696                 : 
     697                 : static const jsatomid INVALID_ATOMID = -1;
     698                 : 
     699                 : static ptrdiff_t
     700            5113 : EmitGoto(JSContext *cx, BytecodeEmitter *bce, StmtInfo *toStmt, ptrdiff_t *lastp,
     701                 :          jsatomid labelIndex = INVALID_ATOMID, SrcNoteType noteType = SRC_NULL)
     702                 : {
     703                 :     int index;
     704                 : 
     705            5113 :     if (!EmitNonLocalJumpFixup(cx, bce, toStmt))
     706               0 :         return -1;
     707                 : 
     708            5113 :     if (labelIndex != INVALID_ATOMID)
     709             126 :         index = NewSrcNote2(cx, bce, noteType, ptrdiff_t(labelIndex));
     710            4987 :     else if (noteType != SRC_NULL)
     711            1683 :         index = NewSrcNote(cx, bce, noteType);
     712                 :     else
     713            3304 :         index = 0;
     714            5113 :     if (index < 0)
     715               0 :         return -1;
     716                 : 
     717            5113 :     return EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, lastp);
     718                 : }
     719                 : 
     720                 : static JSBool
     721         1415946 : BackPatch(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t last, jsbytecode *target, jsbytecode op)
     722                 : {
     723                 :     jsbytecode *pc, *stop;
     724                 :     ptrdiff_t delta, span;
     725                 : 
     726         1415946 :     pc = bce->code(last);
     727         1415946 :     stop = bce->code(-1);
     728         3011362 :     while (pc != stop) {
     729          179470 :         delta = GET_JUMP_OFFSET(pc);
     730          179470 :         span = target - pc;
     731          179470 :         SET_JUMP_OFFSET(pc, span);
     732          179470 :         *pc = op;
     733          179470 :         pc -= delta;
     734                 :     }
     735         1415946 :     return JS_TRUE;
     736                 : }
     737                 : 
     738                 : void
     739         1331184 : frontend::PopStatementTC(TreeContext *tc)
     740                 : {
     741         1331184 :     StmtInfo *stmt = tc->topStmt;
     742         1331184 :     tc->topStmt = stmt->down;
     743         1331184 :     if (STMT_LINKS_SCOPE(stmt)) {
     744          200378 :         tc->topScopeStmt = stmt->downScope;
     745          200378 :         if (stmt->flags & SIF_SCOPE)
     746          199010 :             tc->blockChain = stmt->blockObj->enclosingBlock();
     747                 :     }
     748         1331184 : }
     749                 : 
     750                 : JSBool
     751          751443 : frontend::PopStatementBCE(JSContext *cx, BytecodeEmitter *bce)
     752                 : {
     753          751443 :     StmtInfo *stmt = bce->topStmt;
     754         2080089 :     if (!STMT_IS_TRYING(stmt) &&
     755          664323 :         (!BackPatch(cx, bce, stmt->breaks, bce->next(), JSOP_GOTO) ||
     756          664323 :          !BackPatch(cx, bce, stmt->continues, bce->code(stmt->update), JSOP_GOTO)))
     757                 :     {
     758               0 :         return JS_FALSE;
     759                 :     }
     760          751443 :     PopStatementTC(bce);
     761          751443 :     return JS_TRUE;
     762                 : }
     763                 : 
     764                 : JSBool
     765           56178 : frontend::DefineCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom *atom, ParseNode *pn)
     766                 : {
     767                 :     /* XXX just do numbers for now */
     768           56178 :     if (pn->isKind(PNK_NUMBER)) {
     769             144 :         if (!bce->constMap.put(atom, NumberValue(pn->pn_dval)))
     770               0 :             return JS_FALSE;
     771                 :     }
     772           56178 :     return JS_TRUE;
     773                 : }
     774                 : 
     775                 : StmtInfo *
     776         2715998 : frontend::LexicalLookup(TreeContext *tc, JSAtom *atom, int *slotp, StmtInfo *stmt)
     777                 : {
     778         2715998 :     if (!stmt)
     779         2715998 :         stmt = tc->topScopeStmt;
     780         2896953 :     for (; stmt; stmt = stmt->downScope) {
     781          206133 :         if (stmt->type == STMT_WITH)
     782             801 :             break;
     783                 : 
     784                 :         /* Skip "maybe scope" statements that don't contain let bindings. */
     785          205332 :         if (!(stmt->flags & SIF_SCOPE))
     786               0 :             continue;
     787                 : 
     788          205332 :         StaticBlockObject &blockObj = *stmt->blockObj;
     789          205332 :         const Shape *shape = blockObj.nativeLookup(tc->parser->context, ATOM_TO_JSID(atom));
     790          205332 :         if (shape) {
     791           24377 :             JS_ASSERT(shape->hasShortID());
     792                 : 
     793           24377 :             if (slotp)
     794               0 :                 *slotp = blockObj.stackDepth() + shape->shortid();
     795           24377 :             return stmt;
     796                 :         }
     797                 :     }
     798                 : 
     799         2691621 :     if (slotp)
     800               0 :         *slotp = -1;
     801         2691621 :     return stmt;
     802                 : }
     803                 : 
     804                 : /*
     805                 :  * The function sets vp to NO_CONSTANT when the atom does not corresponds to a
     806                 :  * name defining a constant.
     807                 :  */
     808                 : static JSBool
     809              81 : LookupCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom *atom, Value *constp)
     810                 : {
     811                 :     /*
     812                 :      * Chase down the bce stack, but only until we reach the outermost bce.
     813                 :      * This enables propagating consts from top-level into switch cases in a
     814                 :      * function compiled along with the top-level script.
     815                 :      */
     816              81 :     constp->setMagic(JS_NO_CONSTANT);
     817             162 :     do {
     818             135 :         if (bce->inFunction() || bce->compileAndGo()) {
     819                 :             /* XXX this will need revising if 'const' becomes block-scoped. */
     820             135 :             StmtInfo *stmt = LexicalLookup(bce, atom, NULL);
     821             135 :             if (stmt)
     822               0 :                 return JS_TRUE;
     823                 : 
     824             135 :             if (BytecodeEmitter::ConstMap::Ptr p = bce->constMap.lookup(atom)) {
     825               9 :                 JS_ASSERT(!p->value.isMagic(JS_NO_CONSTANT));
     826               9 :                 *constp = p->value;
     827               9 :                 return JS_TRUE;
     828                 :             }
     829                 : 
     830                 :             /*
     831                 :              * Try looking in the variable object for a direct property that
     832                 :              * is readonly and permanent.  We know such a property can't be
     833                 :              * shadowed by another property on obj's prototype chain, or a
     834                 :              * with object or catch variable; nor can prop's value be changed,
     835                 :              * nor can prop be deleted.
     836                 :              */
     837             126 :             if (bce->inFunction()) {
     838              72 :                 if (bce->bindings.hasBinding(cx, atom))
     839               9 :                     break;
     840                 :             } else {
     841              54 :                 JS_ASSERT(bce->compileAndGo());
     842              54 :                 JSObject *obj = bce->scopeChain();
     843                 : 
     844              54 :                 const Shape *shape = obj->nativeLookup(cx, ATOM_TO_JSID(atom));
     845              54 :                 if (shape) {
     846                 :                     /*
     847                 :                      * We're compiling code that will be executed immediately,
     848                 :                      * not re-executed against a different scope chain and/or
     849                 :                      * variable object.  Therefore we can get constant values
     850                 :                      * from our variable object here.
     851                 :                      */
     852              27 :                     if (!shape->writable() && !shape->configurable() &&
     853              18 :                         shape->hasDefaultGetter() && shape->hasSlot()) {
     854               9 :                         *constp = obj->nativeGetSlot(shape->slot());
     855                 :                     }
     856                 :                 }
     857                 : 
     858              54 :                 if (shape)
     859               9 :                     break;
     860                 :             }
     861                 :         }
     862              54 :     } while (bce->parent && (bce = bce->parent->asBytecodeEmitter()));
     863              72 :     return JS_TRUE;
     864                 : }
     865                 : 
     866                 : static bool
     867          424253 : EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
     868                 : {
     869          424253 :     const size_t len = 1 + UINT32_INDEX_LEN;
     870          424253 :     JS_ASSERT(len == size_t(js_CodeSpec[op].length));
     871          424253 :     ptrdiff_t offset = EmitCheck(cx, bce, len);
     872          424253 :     if (offset < 0)
     873               0 :         return false;
     874                 : 
     875          424253 :     jsbytecode *next = bce->next();
     876          424253 :     next[0] = jsbytecode(op);
     877          424253 :     SET_UINT32_INDEX(next, index);
     878          424253 :     bce->current->next = next + len;
     879          424253 :     UpdateDepth(cx, bce, offset);
     880          424253 :     CheckTypeSet(cx, bce, op);
     881          424253 :     return true;
     882                 : }
     883                 : 
     884                 : static bool
     885         2533314 : EmitIndexOp(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
     886                 : {
     887         2533314 :     const size_t len = js_CodeSpec[op].length;
     888         2533314 :     JS_ASSERT(len >= 1 + UINT32_INDEX_LEN);
     889         2533314 :     ptrdiff_t offset = EmitCheck(cx, bce, len);
     890         2533314 :     if (offset < 0)
     891               0 :         return false;
     892                 : 
     893         2533314 :     jsbytecode *next = bce->next();
     894         2533314 :     next[0] = jsbytecode(op);
     895         2533314 :     SET_UINT32_INDEX(next, index);
     896         2533314 :     bce->current->next = next + len;
     897         2533314 :     UpdateDepth(cx, bce, offset);
     898         2533314 :     CheckTypeSet(cx, bce, op);
     899         2533314 :     return true;
     900                 : }
     901                 : 
     902                 : static bool
     903         2232093 : EmitAtomOp(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce)
     904                 : {
     905         2232093 :     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
     906                 : 
     907         2232093 :     if (op == JSOP_GETPROP && atom == cx->runtime->atomState.lengthAtom) {
     908                 :         /* Specialize length accesses for the interpreter. */
     909           15410 :         op = JSOP_LENGTH;
     910                 :     }
     911                 : 
     912                 :     jsatomid index;
     913         2232093 :     if (!bce->makeAtomIndex(atom, &index))
     914               0 :         return false;
     915                 : 
     916         2232093 :     return EmitIndexOp(cx, op, index, bce);
     917                 : }
     918                 : 
     919                 : static bool
     920         2231967 : EmitAtomOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
     921                 : {
     922         2231967 :     JS_ASSERT(pn->pn_atom != NULL);
     923         2231967 :     return EmitAtomOp(cx, pn->pn_atom, op, bce);
     924                 : }
     925                 : 
     926                 : static bool
     927            7392 : EmitAtomIncDec(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce)
     928                 : {
     929            7392 :     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
     930            7392 :     JS_ASSERT(js_CodeSpec[op].format & (JOF_INC | JOF_DEC));
     931                 : 
     932                 :     jsatomid index;
     933            7392 :     if (!bce->makeAtomIndex(atom, &index))
     934               0 :         return false;
     935                 : 
     936            7392 :     const size_t len = 1 + UINT32_INDEX_LEN + 1;
     937            7392 :     JS_ASSERT(size_t(js_CodeSpec[op].length) == len);
     938            7392 :     ptrdiff_t offset = EmitCheck(cx, bce, len);
     939            7392 :     if (offset < 0)
     940               0 :         return false;
     941                 : 
     942            7392 :     jsbytecode *next = bce->next();
     943            7392 :     next[0] = jsbytecode(op);
     944            7392 :     SET_UINT32_INDEX(next, index);
     945            7392 :     bce->current->next = next + len;
     946            7392 :     UpdateDepth(cx, bce, offset);
     947            7392 :     CheckTypeSet(cx, bce, op);
     948            7392 :     return true;
     949                 : }
     950                 : 
     951                 : static bool
     952          128558 : EmitFunctionOp(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
     953                 : {
     954          128558 :     return EmitIndex32(cx, op, index, bce);
     955                 : }
     956                 : 
     957                 : static bool
     958          103235 : EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
     959                 : {
     960          103235 :     JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
     961          103235 :     return EmitIndex32(cx, op, bce->objectList.index(objbox), bce);
     962                 : }
     963                 : 
     964                 : static bool
     965            3677 : EmitRegExp(JSContext *cx, uint32_t index, BytecodeEmitter *bce)
     966                 : {
     967            3677 :     return EmitIndex32(cx, JSOP_REGEXP, index, bce);
     968                 : }
     969                 : 
     970                 : static bool
     971            4212 : EmitArguments(JSContext *cx, BytecodeEmitter *bce)
     972                 : {
     973            4212 :     if (!bce->mayOverwriteArguments())
     974            4086 :         return Emit1(cx, bce, JSOP_ARGUMENTS) >= 0;
     975             126 :     return EmitAtomOp(cx, cx->runtime->atomState.argumentsAtom, JSOP_NAME, bce);
     976                 : }
     977                 : 
     978                 : bool
     979          347423 : BytecodeEmitter::shouldNoteClosedName(ParseNode *pn)
     980                 : {
     981          347423 :     return !callsEval() && pn->isDefn() && pn->isClosed();
     982                 : }
     983                 : 
     984                 : /*
     985                 :  * Adjust the slot for a block local to account for the number of variables
     986                 :  * that share the same index space with locals. Due to the incremental code
     987                 :  * generation for top-level script, we do the adjustment via code patching in
     988                 :  * js::frontend::CompileScript; see comments there.
     989                 :  *
     990                 :  * The function returns -1 on failures.
     991                 :  */
     992                 : static int
     993           99235 : AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, int slot)
     994                 : {
     995           99235 :     JS_ASSERT((unsigned) slot < bce->maxStackDepth);
     996           99235 :     if (bce->inFunction()) {
     997           79898 :         slot += bce->bindings.countVars();
     998           79898 :         if ((unsigned) slot >= SLOTNO_LIMIT) {
     999                 :             ReportCompileErrorNumber(cx, bce->tokenStream(), NULL, JSREPORT_ERROR,
    1000               0 :                                      JSMSG_TOO_MANY_LOCALS);
    1001               0 :             slot = -1;
    1002                 :         }
    1003                 :     }
    1004           99235 :     return slot;
    1005                 : }
    1006                 : 
    1007                 : static bool
    1008           98335 : EmitEnterBlock(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
    1009                 : {
    1010           98335 :     JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
    1011           98335 :     if (!EmitObjectOp(cx, pn->pn_objbox, op, bce))
    1012               0 :         return false;
    1013                 : 
    1014           98335 :     StaticBlockObject &blockObj = pn->pn_objbox->object->asStaticBlock();
    1015                 : 
    1016                 :     int depth = bce->stackDepth -
    1017           98335 :                 (blockObj.slotCount() + ((op == JSOP_ENTERLET1) ? 1 : 0));
    1018           98335 :     JS_ASSERT(depth >= 0);
    1019                 : 
    1020           98335 :     blockObj.setStackDepth(depth);
    1021                 : 
    1022           98335 :     int depthPlusFixed = AdjustBlockSlot(cx, bce, depth);
    1023           98335 :     if (depthPlusFixed < 0)
    1024               0 :         return false;
    1025                 : 
    1026          422589 :     for (unsigned i = 0; i < blockObj.slotCount(); i++) {
    1027          324254 :         Definition *dn = blockObj.maybeDefinitionParseNode(i);
    1028          324254 :         blockObj.poisonDefinitionParseNode(i);
    1029                 : 
    1030                 :         /* Beware the empty destructuring dummy. */
    1031          324254 :         if (!dn) {
    1032            3942 :             JS_ASSERT(i + 1 <= blockObj.slotCount());
    1033            3942 :             continue;
    1034                 :         }
    1035                 : 
    1036          320312 :         JS_ASSERT(dn->isDefn());
    1037          320312 :         JS_ASSERT(unsigned(dn->frameSlot() + depthPlusFixed) < JS_BIT(16));
    1038          320312 :         dn->pn_cookie.set(dn->pn_cookie.level(), uint16_t(dn->frameSlot() + depthPlusFixed));
    1039                 : #ifdef DEBUG
    1040          345870 :         for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
    1041           25558 :             JS_ASSERT(pnu->pn_lexdef == dn);
    1042           25558 :             JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
    1043           25558 :             JS_ASSERT(pnu->pn_cookie.isFree());
    1044                 :         }
    1045                 : #endif
    1046                 :     }
    1047                 : 
    1048                 :     /*
    1049                 :      * If clones of this block will have any extensible parents, then the
    1050                 :      * clones must get unique shapes; see the comments for
    1051                 :      * js::Bindings::extensibleParents.
    1052                 :      */
    1053          195445 :     if ((bce->flags & TCF_FUN_EXTENSIBLE_SCOPE) ||
    1054           97110 :         bce->bindings.extensibleParents()) {
    1055            1225 :         Shape *newShape = Shape::setExtensibleParents(cx, blockObj.lastProperty());
    1056            1225 :         if (!newShape)
    1057               0 :             return false;
    1058            1225 :         blockObj.setLastPropertyInfallible(newShape);
    1059                 :     }
    1060                 : 
    1061           98335 :     return true;
    1062                 : }
    1063                 : 
    1064                 : /*
    1065                 :  * Try to convert a *NAME op to a *GNAME op, which optimizes access to
    1066                 :  * undeclared globals. Return true if a conversion was made.
    1067                 :  *
    1068                 :  * This conversion is not made if we are in strict mode.  In eval code nested
    1069                 :  * within (strict mode) eval code, access to an undeclared "global" might
    1070                 :  * merely be to a binding local to that outer eval:
    1071                 :  *
    1072                 :  *   "use strict";
    1073                 :  *   var x = "global";
    1074                 :  *   eval('var x = "eval"; eval("x");'); // 'eval', not 'global'
    1075                 :  *
    1076                 :  * Outside eval code, access to an undeclared global is a strict mode error:
    1077                 :  *
    1078                 :  *   "use strict";
    1079                 :  *   function foo()
    1080                 :  *   {
    1081                 :  *     undeclared = 17; // throws ReferenceError
    1082                 :  *   }
    1083                 :  *   foo();
    1084                 :  */
    1085                 : static bool
    1086         1957305 : TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op)
    1087                 : {
    1088         7803216 :     if (bce->compileAndGo() && 
    1089                 :         bce->globalScope->globalObj &&
    1090         1949783 :         !bce->mightAliasLocals() &&
    1091         1948064 :         !pn->isDeoptimized() &&
    1092         1948064 :         !(bce->flags & TCF_STRICT_MODE_CODE)) { 
    1093         1947293 :         switch (*op) {
    1094         1726745 :           case JSOP_NAME:     *op = JSOP_GETGNAME; break;
    1095          157007 :           case JSOP_SETNAME:  *op = JSOP_SETGNAME; break;
    1096            1579 :           case JSOP_INCNAME:  *op = JSOP_INCGNAME; break;
    1097            4776 :           case JSOP_NAMEINC:  *op = JSOP_GNAMEINC; break;
    1098              81 :           case JSOP_DECNAME:  *op = JSOP_DECGNAME; break;
    1099             144 :           case JSOP_NAMEDEC:  *op = JSOP_GNAMEDEC; break;
    1100                 :           case JSOP_SETCONST:
    1101                 :           case JSOP_DELNAME:
    1102                 :             /* Not supported. */
    1103           56961 :             return false;
    1104               0 :           default: JS_NOT_REACHED("gname");
    1105                 :         }
    1106         1890332 :         return true;
    1107                 :     }
    1108           10012 :     return false;
    1109                 : }
    1110                 : 
    1111                 : // Binds a global, given a |dn| that is known to have the PND_GVAR bit, and a pn
    1112                 : // that is |dn| or whose definition is |dn|. |pn->pn_cookie| is an outparam
    1113                 : // that will be free (meaning no binding), or a slot number.
    1114                 : static bool
    1115           23991 : BindKnownGlobal(JSContext *cx, BytecodeEmitter *bce, ParseNode *dn, ParseNode *pn, JSAtom *atom)
    1116                 : {
    1117                 :     // Cookie is an outparam; make sure caller knew to clear it.
    1118           23991 :     JS_ASSERT(pn->pn_cookie.isFree());
    1119                 : 
    1120           23991 :     if (bce->mightAliasLocals())
    1121              54 :         return true;
    1122                 : 
    1123           23937 :     GlobalScope *globalScope = bce->globalScope;
    1124                 : 
    1125                 :     jsatomid index;
    1126           23937 :     if (dn->pn_cookie.isFree()) {
    1127                 :         // The definition wasn't bound, so find its atom's index in the
    1128                 :         // mapping of defined globals.
    1129           23937 :         AtomIndexPtr p = globalScope->names.lookup(atom);
    1130           23937 :         JS_ASSERT(!!p);
    1131           23937 :         index = p.value();
    1132                 :     } else {
    1133               0 :         BytecodeEmitter *globalbce = globalScope->bce;
    1134                 : 
    1135                 :         // If the definition is bound, and we're in the same bce, we can re-use
    1136                 :         // its cookie.
    1137               0 :         if (globalbce == bce) {
    1138               0 :             pn->pn_cookie = dn->pn_cookie;
    1139               0 :             pn->pn_dflags |= PND_BOUND;
    1140               0 :             return true;
    1141                 :         }
    1142                 : 
    1143                 :         // Otherwise, find the atom's index by using the originating bce's
    1144                 :         // global use table.
    1145               0 :         index = globalbce->globalUses[dn->pn_cookie.slot()].slot;
    1146                 :     }
    1147                 : 
    1148           23937 :     if (!bce->addGlobalUse(atom, index, &pn->pn_cookie))
    1149               0 :         return false;
    1150                 : 
    1151           23937 :     if (!pn->pn_cookie.isFree())
    1152           23937 :         pn->pn_dflags |= PND_BOUND;
    1153                 : 
    1154           23937 :     return true;
    1155                 : }
    1156                 : 
    1157                 : // See BindKnownGlobal()'s comment.
    1158                 : static bool
    1159           46514 : BindGlobal(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSAtom *atom)
    1160                 : {
    1161           46514 :     pn->pn_cookie.makeFree();
    1162                 : 
    1163                 :     Definition *dn;
    1164           46514 :     if (pn->isUsed()) {
    1165           22015 :         dn = pn->pn_lexdef;
    1166                 :     } else {
    1167           24499 :         if (!pn->isDefn())
    1168               0 :             return true;
    1169           24499 :         dn = (Definition *)pn;
    1170                 :     }
    1171                 : 
    1172                 :     // Only optimize for defined globals.
    1173           46514 :     if (!dn->isGlobal())
    1174           22523 :         return true;
    1175                 : 
    1176           23991 :     return BindKnownGlobal(cx, bce, dn, pn, atom);
    1177                 : }
    1178                 : 
    1179                 : /*
    1180                 :  * BindNameToSlot attempts to optimize name gets and sets to stack slot loads
    1181                 :  * and stores, given the compile-time information in bce and a PNK_NAME node pn.
    1182                 :  * It returns false on error, true on success.
    1183                 :  *
    1184                 :  * The caller can inspect pn->pn_cookie for FREE_UPVAR_COOKIE to tell whether
    1185                 :  * optimization occurred, in which case BindNameToSlot also updated pn->pn_op.
    1186                 :  * If pn->pn_cookie is still FREE_UPVAR_COOKIE on return, pn->pn_op still may
    1187                 :  * have been optimized, e.g., from JSOP_NAME to JSOP_CALLEE.  Whether or not
    1188                 :  * pn->pn_op was modified, if this function finds an argument or local variable
    1189                 :  * name, PND_CONST will be set in pn_dflags for read-only properties after a
    1190                 :  * successful return.
    1191                 :  *
    1192                 :  * NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget
    1193                 :  * to update the special cases in EmitFor (for-in) and EmitAssignment (= and
    1194                 :  * op=, e.g. +=).
    1195                 :  */
    1196                 : static JSBool
    1197         3638807 : BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    1198                 : {
    1199                 :     Definition *dn;
    1200                 :     JSOp op;
    1201                 :     JSAtom *atom;
    1202                 :     Definition::Kind dn_kind;
    1203                 : 
    1204         3638807 :     JS_ASSERT(pn->isKind(PNK_NAME));
    1205                 : 
    1206                 :     /* Idempotency tests come first, since we may be called more than once. */
    1207         3638807 :     if (pn->pn_dflags & PND_BOUND)
    1208         1044255 :         return JS_TRUE;
    1209                 : 
    1210                 :     /* No cookie initialized for these two, they're pre-bound by definition. */
    1211         2594552 :     JS_ASSERT(!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE));
    1212                 : 
    1213                 :     /*
    1214                 :      * The parser linked all uses (including forward references) to their
    1215                 :      * definitions, unless a with statement or direct eval intervened.
    1216                 :      */
    1217         2594552 :     if (pn->isUsed()) {
    1218         2489674 :         JS_ASSERT(pn->pn_cookie.isFree());
    1219         2489674 :         dn = pn->pn_lexdef;
    1220         2489674 :         JS_ASSERT(dn->isDefn());
    1221         2489674 :         if (pn->isDeoptimized())
    1222            6092 :             return JS_TRUE;
    1223         2483582 :         pn->pn_dflags |= (dn->pn_dflags & PND_CONST);
    1224                 :     } else {
    1225          104878 :         if (!pn->isDefn())
    1226             153 :             return JS_TRUE;
    1227          104725 :         dn = (Definition *) pn;
    1228                 :     }
    1229                 : 
    1230         2588307 :     op = pn->getOp();
    1231         2588307 :     if (op == JSOP_NOP)
    1232               0 :         return JS_TRUE;
    1233                 : 
    1234         2588307 :     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
    1235         2588307 :     atom = pn->pn_atom;
    1236         2588307 :     UpvarCookie cookie = dn->pn_cookie;
    1237         2588307 :     dn_kind = dn->kind();
    1238                 : 
    1239                 :     /*
    1240                 :      * Turn attempts to mutate const-declared bindings into get ops (for
    1241                 :      * pre-increment and pre-decrement ops, our caller will have to emit
    1242                 :      * JSOP_POS, JSOP_ONE, and JSOP_ADD as well).
    1243                 :      *
    1244                 :      * Turn JSOP_DELNAME into JSOP_FALSE if dn is known, as all declared
    1245                 :      * bindings visible to the compiler are permanent in JS unless the
    1246                 :      * declaration originates at top level in eval code.
    1247                 :      */
    1248         2588307 :     switch (op) {
    1249                 :       case JSOP_NAME:
    1250                 :       case JSOP_SETCONST:
    1251         2134917 :         break;
    1252                 :       case JSOP_DELNAME:
    1253             891 :         if (dn_kind != Definition::UNKNOWN) {
    1254              18 :             if (bce->parser->callerFrame && dn->isTopLevel())
    1255               0 :                 JS_ASSERT(bce->compileAndGo());
    1256                 :             else
    1257              18 :                 pn->setOp(JSOP_FALSE);
    1258              18 :             pn->pn_dflags |= PND_BOUND;
    1259              18 :             return JS_TRUE;
    1260                 :         }
    1261             873 :         break;
    1262                 :       default:
    1263          452499 :         if (pn->isConst()) {
    1264               9 :             if (bce->needStrictChecks()) {
    1265               0 :                 JSAutoByteString name;
    1266               0 :                 if (!js_AtomToPrintableString(cx, atom, &name) ||
    1267                 :                     !ReportStrictModeError(cx, bce->tokenStream(), bce, pn, JSMSG_READ_ONLY,
    1268               0 :                                            name.ptr())) {
    1269               0 :                     return JS_FALSE;
    1270                 :                 }
    1271                 :             }
    1272               9 :             pn->setOp(op = JSOP_NAME);
    1273                 :         }
    1274                 :     }
    1275                 : 
    1276         2588289 :     if (dn->isGlobal()) {
    1277          188670 :         if (op == JSOP_NAME) {
    1278                 :             /*
    1279                 :              * If the definition is a defined global, not potentially aliased
    1280                 :              * by a local variable, and not mutating the variable, try and
    1281                 :              * optimize to a fast, unguarded global access.
    1282                 :              */
    1283          131444 :             if (!pn->pn_cookie.isFree()) {
    1284               0 :                 pn->setOp(JSOP_GETGNAME);
    1285               0 :                 pn->pn_dflags |= PND_BOUND;
    1286               0 :                 return JS_TRUE;
    1287                 :             }
    1288                 :         }
    1289                 : 
    1290                 :         /*
    1291                 :          * The locally stored cookie here should really come from |pn|, not
    1292                 :          * |dn|. For example, we could have a SETGNAME op's lexdef be a
    1293                 :          * GETGNAME op, and their cookies have very different meanings. As
    1294                 :          * a workaround, just make the cookie free.
    1295                 :          */
    1296          188670 :         cookie.makeFree();
    1297                 :     }
    1298                 : 
    1299         2588289 :     if (cookie.isFree()) {
    1300         1979552 :         StackFrame *caller = bce->parser->callerFrame;
    1301         1979552 :         if (caller) {
    1302           24834 :             JS_ASSERT(bce->compileAndGo());
    1303                 : 
    1304                 :             /*
    1305                 :              * Don't generate upvars on the left side of a for loop. See
    1306                 :              * bug 470758.
    1307                 :              */
    1308           24834 :             if (bce->flags & TCF_IN_FOR_INIT)
    1309             117 :                 return JS_TRUE;
    1310                 : 
    1311           24717 :             JS_ASSERT(caller->isScriptFrame());
    1312                 : 
    1313                 :             /*
    1314                 :              * If this is an eval in the global scope, then unbound variables
    1315                 :              * must be globals, so try to use GNAME ops.
    1316                 :              */
    1317           24717 :             if (caller->isGlobalFrame() && TryConvertToGname(bce, pn, &op)) {
    1318            2029 :                 pn->setOp(op);
    1319            2029 :                 pn->pn_dflags |= PND_BOUND;
    1320            2029 :                 return JS_TRUE;
    1321                 :             }
    1322                 : 
    1323                 :             /*
    1324                 :              * Out of tricks, so we must rely on PICs to optimize named
    1325                 :              * accesses from direct eval called from function code.
    1326                 :              */
    1327           22688 :             return JS_TRUE;
    1328                 :         }
    1329                 : 
    1330                 :         /* Optimize accesses to undeclared globals. */
    1331         1954718 :         if (!TryConvertToGname(bce, pn, &op))
    1332           66415 :             return JS_TRUE;
    1333                 : 
    1334         1888303 :         pn->setOp(op);
    1335         1888303 :         pn->pn_dflags |= PND_BOUND;
    1336                 : 
    1337         1888303 :         return JS_TRUE;
    1338                 :     }
    1339                 : 
    1340          608737 :     uint16_t level = cookie.level();
    1341          608737 :     JS_ASSERT(bce->staticLevel >= level);
    1342                 : 
    1343          608737 :     const unsigned skip = bce->staticLevel - level;
    1344          608737 :     if (skip != 0)
    1345           23753 :         return JS_TRUE;
    1346                 : 
    1347                 :     /*
    1348                 :      * We are compiling a function body and may be able to optimize name
    1349                 :      * to stack slot. Look for an argument or variable in the function and
    1350                 :      * rewrite pn_op and update pn accordingly.
    1351                 :      */
    1352          584984 :     switch (dn_kind) {
    1353                 :       case Definition::UNKNOWN:
    1354               0 :         return JS_TRUE;
    1355                 : 
    1356                 :       case Definition::LET:
    1357           24791 :         switch (op) {
    1358           17636 :           case JSOP_NAME:     op = JSOP_GETLOCAL; break;
    1359            1872 :           case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
    1360             459 :           case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
    1361            4815 :           case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
    1362               0 :           case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
    1363               9 :           case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
    1364               0 :           default: JS_NOT_REACHED("let");
    1365                 :         }
    1366           24791 :         break;
    1367                 : 
    1368                 :       case Definition::ARG:
    1369          127108 :         switch (op) {
    1370          124489 :           case JSOP_NAME:     op = JSOP_GETARG; break;
    1371            2061 :           case JSOP_SETNAME:  op = JSOP_SETARG; break;
    1372             126 :           case JSOP_INCNAME:  op = JSOP_INCARG; break;
    1373             162 :           case JSOP_NAMEINC:  op = JSOP_ARGINC; break;
    1374             162 :           case JSOP_DECNAME:  op = JSOP_DECARG; break;
    1375             108 :           case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;
    1376               0 :           default: JS_NOT_REACHED("arg");
    1377                 :         }
    1378          127108 :         JS_ASSERT(!pn->isConst());
    1379          127108 :         break;
    1380                 : 
    1381                 :       case Definition::VAR:
    1382          427811 :         if (dn->isOp(JSOP_CALLEE)) {
    1383             450 :             JS_ASSERT(op != JSOP_CALLEE);
    1384             450 :             JS_ASSERT((bce->fun()->flags & JSFUN_LAMBDA) && atom == bce->fun()->atom);
    1385                 : 
    1386                 :             /*
    1387                 :              * Leave pn->isOp(JSOP_NAME) if bce->fun is heavyweight to
    1388                 :              * address two cases: a new binding introduced by eval, and
    1389                 :              * assignment to the name in strict mode.
    1390                 :              *
    1391                 :              *   var fun = (function f(s) { eval(s); return f; });
    1392                 :              *   assertEq(fun("var f = 42"), 42);
    1393                 :              *
    1394                 :              * ECMAScript specifies that a function expression's name is bound
    1395                 :              * in a lexical environment distinct from that used to bind its
    1396                 :              * named parameters, the arguments object, and its variables.  The
    1397                 :              * new binding for "var f = 42" shadows the binding for the
    1398                 :              * function itself, so the name of the function will not refer to
    1399                 :              * the function.
    1400                 :              *
    1401                 :              *    (function f() { "use strict"; f = 12; })();
    1402                 :              *
    1403                 :              * Outside strict mode, assignment to a function expression's name
    1404                 :              * has no effect.  But in strict mode, this attempt to mutate an
    1405                 :              * immutable binding must throw a TypeError.  We implement this by
    1406                 :              * not optimizing such assignments and by marking such functions as
    1407                 :              * heavyweight, ensuring that the function name is represented in
    1408                 :              * the scope chain so that assignment will throw a TypeError.
    1409                 :              */
    1410             450 :             JS_ASSERT(op != JSOP_DELNAME);
    1411             450 :             if (!(bce->flags & TCF_FUN_HEAVYWEIGHT)) {
    1412             414 :                 op = JSOP_CALLEE;
    1413             414 :                 pn->pn_dflags |= PND_CONST;
    1414                 :             }
    1415                 : 
    1416             450 :             pn->setOp(op);
    1417             450 :             pn->pn_dflags |= PND_BOUND;
    1418             450 :             return JS_TRUE;
    1419                 :         }
    1420                 :         /* FALL THROUGH */
    1421                 : 
    1422                 :       default:
    1423               0 :         JS_ASSERT_IF(dn_kind != Definition::FUNCTION,
    1424                 :                      dn_kind == Definition::VAR ||
    1425          432635 :                      dn_kind == Definition::CONST);
    1426          432635 :         switch (op) {
    1427          158649 :           case JSOP_NAME:     op = JSOP_GETLOCAL; break;
    1428          258204 :           case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
    1429               0 :           case JSOP_SETCONST: op = JSOP_SETLOCAL; break;
    1430            3791 :           case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
    1431           11369 :           case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
    1432             307 :           case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
    1433             315 :           case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
    1434               0 :           default: JS_NOT_REACHED("local");
    1435                 :         }
    1436          432635 :         JS_ASSERT_IF(dn_kind == Definition::CONST, pn->pn_dflags & PND_CONST);
    1437          432635 :         break;
    1438                 :     }
    1439                 : 
    1440          584534 :     JS_ASSERT(!pn->isOp(op));
    1441          584534 :     pn->setOp(op);
    1442          584534 :     pn->pn_cookie.set(0, cookie.slot());
    1443          584534 :     pn->pn_dflags |= PND_BOUND;
    1444          584534 :     return JS_TRUE;
    1445                 : }
    1446                 : 
    1447                 : bool
    1448           23937 : BytecodeEmitter::addGlobalUse(JSAtom *atom, uint32_t slot, UpvarCookie *cookie)
    1449                 : {
    1450           23937 :     if (!globalMap.ensureMap(context()))
    1451               0 :         return false;
    1452                 : 
    1453           47874 :     AtomIndexAddPtr p = globalMap->lookupForAdd(atom);
    1454           23937 :     if (p) {
    1455             360 :         jsatomid index = p.value();
    1456             360 :         cookie->set(0, index);
    1457             360 :         return true;
    1458                 :     }
    1459                 : 
    1460                 :     /* Don't bother encoding indexes >= uint16_t */
    1461           23577 :     if (globalUses.length() >= UINT16_LIMIT) {
    1462               0 :         cookie->makeFree();
    1463               0 :         return true;
    1464                 :     }
    1465                 : 
    1466                 :     /* Find or add an existing atom table entry. */
    1467                 :     jsatomid allAtomIndex;
    1468           23577 :     if (!makeAtomIndex(atom, &allAtomIndex))
    1469               0 :         return false;
    1470                 : 
    1471           23577 :     jsatomid globalUseIndex = globalUses.length();
    1472           23577 :     cookie->set(0, globalUseIndex);
    1473                 : 
    1474           23577 :     GlobalSlotArray::Entry entry = { allAtomIndex, slot };
    1475           23577 :     if (!globalUses.append(entry))
    1476               0 :         return false;
    1477                 : 
    1478           23577 :     return globalMap->add(p, atom, globalUseIndex);
    1479                 : }
    1480                 : 
    1481                 : /*
    1482                 :  * If pn contains a useful expression, return true with *answer set to true.
    1483                 :  * If pn contains a useless expression, return true with *answer set to false.
    1484                 :  * Return false on error.
    1485                 :  *
    1486                 :  * The caller should initialize *answer to false and invoke this function on
    1487                 :  * an expression statement or similar subtree to decide whether the tree could
    1488                 :  * produce code that has any side effects.  For an expression statement, we
    1489                 :  * define useless code as code with no side effects, because the main effect,
    1490                 :  * the value left on the stack after the code executes, will be discarded by a
    1491                 :  * pop bytecode.
    1492                 :  */
    1493                 : static JSBool
    1494          938658 : CheckSideEffects(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSBool *answer)
    1495                 : {
    1496                 :     JSBool ok;
    1497                 :     ParseNode *pn2;
    1498                 : 
    1499          938658 :     ok = JS_TRUE;
    1500          938658 :     if (!pn || *answer)
    1501           53879 :         return ok;
    1502                 : 
    1503          884779 :     switch (pn->getArity()) {
    1504                 :       case PN_FUNC:
    1505                 :         /*
    1506                 :          * A named function, contrary to ES3, is no longer useful, because we
    1507                 :          * bind its name lexically (using JSOP_CALLEE) instead of creating an
    1508                 :          * Object instance and binding a readonly, permanent property in it
    1509                 :          * (the object and binding can be detected and hijacked or captured).
    1510                 :          * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
    1511                 :          */
    1512           75609 :         *answer = JS_FALSE;
    1513           75609 :         break;
    1514                 : 
    1515                 :       case PN_LIST:
    1516          381000 :         if (pn->isOp(JSOP_NOP) || pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) ||
    1517          253838 :             pn->isOp(JSOP_STRICTEQ) || pn->isOp(JSOP_STRICTNE)) {
    1518                 :             /*
    1519                 :              * Non-operators along with ||, &&, ===, and !== never invoke
    1520                 :              * toString or valueOf.
    1521                 :              */
    1522             792 :             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
    1523             549 :                 ok &= CheckSideEffects(cx, bce, pn2, answer);
    1524                 :         } else {
    1525                 :             /*
    1526                 :              * All invocation operations (construct: PNK_NEW, call: PNK_LP)
    1527                 :              * are presumed to be useful, because they may have side effects
    1528                 :              * even if their main effect (their return value) is discarded.
    1529                 :              *
    1530                 :              * PNK_LB binary trees of 3 or more nodes are flattened into lists
    1531                 :              * to avoid too much recursion.  All such lists must be presumed
    1532                 :              * to be useful because each index operation could invoke a getter
    1533                 :              * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,
    1534                 :              * does not apply here: arguments[i][j] might invoke a getter).
    1535                 :              *
    1536                 :              * Likewise, array and object initialisers may call prototype
    1537                 :              * setters (the __defineSetter__ built-in, and writable __proto__
    1538                 :              * on Array.prototype create this hazard). Initialiser list nodes
    1539                 :              * have JSOP_NEWINIT in their pn_op.
    1540                 :              */
    1541          126919 :             *answer = JS_TRUE;
    1542                 :         }
    1543          127162 :         break;
    1544                 : 
    1545                 :       case PN_TERNARY:
    1546             261 :         ok = CheckSideEffects(cx, bce, pn->pn_kid1, answer) &&
    1547             261 :              CheckSideEffects(cx, bce, pn->pn_kid2, answer) &&
    1548             522 :              CheckSideEffects(cx, bce, pn->pn_kid3, answer);
    1549             261 :         break;
    1550                 : 
    1551                 :       case PN_BINARY:
    1552          418694 :         if (pn->isAssignment()) {
    1553                 :             /*
    1554                 :              * Assignment is presumed to be useful, even if the next operation
    1555                 :              * is another assignment overwriting this one's ostensible effect,
    1556                 :              * because the left operand may be a property with a setter that
    1557                 :              * has side effects.
    1558                 :              *
    1559                 :              * The only exception is assignment of a useless value to a const
    1560                 :              * declared in the function currently being compiled.
    1561                 :              */
    1562          393673 :             pn2 = pn->pn_left;
    1563          393673 :             if (!pn2->isKind(PNK_NAME)) {
    1564           29034 :                 *answer = JS_TRUE;
    1565                 :             } else {
    1566          364639 :                 if (!BindNameToSlot(cx, bce, pn2))
    1567               0 :                     return JS_FALSE;
    1568          364639 :                 if (!CheckSideEffects(cx, bce, pn->pn_right, answer))
    1569               0 :                     return JS_FALSE;
    1570          364639 :                 if (!*answer && (!pn->isOp(JSOP_NOP) || !pn2->isConst()))
    1571          327034 :                     *answer = JS_TRUE;
    1572                 :             }
    1573                 :         } else {
    1574           49907 :             if (pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) || pn->isOp(JSOP_STRICTEQ) ||
    1575           24886 :                 pn->isOp(JSOP_STRICTNE)) {
    1576                 :                 /*
    1577                 :                  * ||, &&, ===, and !== do not convert their operands via
    1578                 :                  * toString or valueOf method calls.
    1579                 :                  */
    1580             162 :                 ok = CheckSideEffects(cx, bce, pn->pn_left, answer) &&
    1581             162 :                      CheckSideEffects(cx, bce, pn->pn_right, answer);
    1582                 :             } else {
    1583                 :                 /*
    1584                 :                  * We can't easily prove that neither operand ever denotes an
    1585                 :                  * object with a toString or valueOf method.
    1586                 :                  */
    1587           24859 :                 *answer = JS_TRUE;
    1588                 :             }
    1589                 :         }
    1590          418694 :         break;
    1591                 : 
    1592                 :       case PN_UNARY:
    1593            5710 :         switch (pn->getKind()) {
    1594                 :           case PNK_DELETE:
    1595            1188 :             pn2 = pn->pn_kid;
    1596            1188 :             switch (pn2->getKind()) {
    1597                 :               case PNK_NAME:
    1598             459 :                 if (!BindNameToSlot(cx, bce, pn2))
    1599               0 :                     return JS_FALSE;
    1600             459 :                 if (pn2->isConst()) {
    1601               0 :                     *answer = JS_FALSE;
    1602               0 :                     break;
    1603                 :                 }
    1604                 :                 /* FALL THROUGH */
    1605                 :               case PNK_DOT:
    1606                 : #if JS_HAS_XML_SUPPORT
    1607                 :               case PNK_DBLDOT:
    1608             801 :                 JS_ASSERT_IF(pn2->getKind() == PNK_DBLDOT, !bce->inStrictMode());
    1609                 :                 /* FALL THROUGH */
    1610                 : 
    1611                 : #endif
    1612                 :               case PNK_LP:
    1613                 :               case PNK_LB:
    1614                 :                 /* All these delete addressing modes have effects too. */
    1615            1188 :                 *answer = JS_TRUE;
    1616            1188 :                 break;
    1617                 :               default:
    1618               0 :                 ok = CheckSideEffects(cx, bce, pn2, answer);
    1619               0 :                 break;
    1620                 :             }
    1621            1188 :             break;
    1622                 : 
    1623                 :           case PNK_TYPEOF:
    1624                 :           case PNK_VOID:
    1625                 :           case PNK_NOT:
    1626                 :           case PNK_BITNOT:
    1627              45 :             if (pn->isOp(JSOP_NOT)) {
    1628                 :                 /* ! does not convert its operand via toString or valueOf. */
    1629               0 :                 ok = CheckSideEffects(cx, bce, pn->pn_kid, answer);
    1630               0 :                 break;
    1631                 :             }
    1632                 :             /* FALL THROUGH */
    1633                 : 
    1634                 :           default:
    1635                 :             /*
    1636                 :              * All of PNK_INC, PNK_DEC, PNK_THROW, and PNK_YIELD have direct
    1637                 :              * effects. Of the remaining unary-arity node types, we can't
    1638                 :              * easily prove that the operand never denotes an object with a
    1639                 :              * toString or valueOf method.
    1640                 :              */
    1641            4522 :             *answer = JS_TRUE;
    1642            4522 :             break;
    1643                 :         }
    1644            5710 :         break;
    1645                 : 
    1646                 :       case PN_NAME:
    1647                 :         /*
    1648                 :          * Take care to avoid trying to bind a label name (labels, both for
    1649                 :          * statements and property values in object initialisers, have pn_op
    1650                 :          * defaulted to JSOP_NOP).
    1651                 :          */
    1652           53033 :         if (pn->isKind(PNK_NAME) && !pn->isOp(JSOP_NOP)) {
    1653           50438 :             if (!BindNameToSlot(cx, bce, pn))
    1654               0 :                 return JS_FALSE;
    1655          100759 :             if (!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE) &&
    1656           50321 :                 pn->pn_cookie.isFree()) {
    1657                 :                 /*
    1658                 :                  * Not an argument or local variable use, and not a use of a
    1659                 :                  * unshadowed named function expression's given name, so this
    1660                 :                  * expression could invoke a getter that has side effects.
    1661                 :                  */
    1662            2466 :                 *answer = JS_TRUE;
    1663                 :             }
    1664                 :         }
    1665           53033 :         pn2 = pn->maybeExpr();
    1666           53033 :         if (pn->isKind(PNK_DOT)) {
    1667            2595 :             if (pn2->isKind(PNK_NAME) && !BindNameToSlot(cx, bce, pn2))
    1668               0 :                 return JS_FALSE;
    1669            5181 :             if (!(pn2->isOp(JSOP_ARGUMENTS) &&
    1670               9 :                   pn->pn_atom == cx->runtime->atomState.lengthAtom)) {
    1671                 :                 /*
    1672                 :                  * Any dotted property reference could call a getter, except
    1673                 :                  * for arguments.length where arguments is unambiguous.
    1674                 :                  */
    1675            2586 :                 *answer = JS_TRUE;
    1676                 :             }
    1677                 :         }
    1678           53033 :         ok = CheckSideEffects(cx, bce, pn2, answer);
    1679           53033 :         break;
    1680                 : 
    1681                 :       case PN_NAMESET:
    1682               0 :         ok = CheckSideEffects(cx, bce, pn->pn_tree, answer);
    1683               0 :         break;
    1684                 : 
    1685                 :       case PN_NULLARY:
    1686          204310 :         if (pn->isKind(PNK_DEBUGGER))
    1687               0 :             *answer = JS_TRUE;
    1688          204310 :         break;
    1689                 :     }
    1690          884779 :     return ok;
    1691                 : }
    1692                 : 
    1693                 : bool
    1694           10639 : BytecodeEmitter::needsImplicitThis()
    1695                 : {
    1696           10639 :     if (!compileAndGo())
    1697            4945 :         return true;
    1698            5694 :     if (!inFunction()) {
    1699            1656 :         JSObject *scope = scopeChain();
    1700            6093 :         while (scope) {
    1701            2781 :             if (scope->isWith())
    1702               0 :                 return true;
    1703            2781 :             scope = scope->enclosingScope();
    1704                 :         }
    1705                 :     }
    1706           14484 :     for (const FunctionBox *funbox = this->funbox; funbox; funbox = funbox->parent) {
    1707            8826 :         if (funbox->tcflags & TCF_IN_WITH)
    1708              36 :             return true;
    1709                 :     }
    1710           15105 :     for (StmtInfo *stmt = topStmt; stmt; stmt = stmt->down) {
    1711            9636 :         if (stmt->type == STMT_WITH)
    1712             189 :             return true;
    1713                 :     }
    1714            5469 :     return false;
    1715                 : }
    1716                 : 
    1717                 : static JSBool
    1718         2080793 : EmitNameOp(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSBool callContext)
    1719                 : {
    1720                 :     JSOp op;
    1721                 : 
    1722         2080793 :     if (!BindNameToSlot(cx, bce, pn))
    1723               0 :         return JS_FALSE;
    1724         2080793 :     op = pn->getOp();
    1725                 : 
    1726         2080793 :     if (callContext) {
    1727          120090 :         switch (op) {
    1728                 :           case JSOP_NAME:
    1729           10639 :             op = JSOP_CALLNAME;
    1730           10639 :             break;
    1731                 :           case JSOP_GETGNAME:
    1732          102120 :             op = JSOP_CALLGNAME;
    1733          102120 :             break;
    1734                 :           case JSOP_GETARG:
    1735            2111 :             op = JSOP_CALLARG;
    1736            2111 :             break;
    1737                 :           case JSOP_GETLOCAL:
    1738            4995 :             op = JSOP_CALLLOCAL;
    1739            4995 :             break;
    1740                 :           default:
    1741             225 :             JS_ASSERT(op == JSOP_ARGUMENTS || op == JSOP_CALLEE);
    1742             225 :             break;
    1743                 :         }
    1744                 :     }
    1745                 : 
    1746         2080793 :     if (op == JSOP_ARGUMENTS) {
    1747            4212 :         if (!EmitArguments(cx, bce))
    1748               0 :             return JS_FALSE;
    1749         2076581 :     } else if (op == JSOP_CALLEE) {
    1750             414 :         if (Emit1(cx, bce, op) < 0)
    1751               0 :             return JS_FALSE;
    1752                 :     } else {
    1753         2076167 :         if (!pn->pn_cookie.isFree()) {
    1754          300665 :             JS_ASSERT(JOF_OPTYPE(op) != JOF_ATOM);
    1755          300665 :             EMIT_UINT16_IMM_OP(op, pn->pn_cookie.slot());
    1756                 :         } else {
    1757         1775502 :             if (!EmitAtomOp(cx, pn, op, bce))
    1758               0 :                 return JS_FALSE;
    1759                 :         }
    1760                 :     }
    1761                 : 
    1762                 :     /* Need to provide |this| value for call */
    1763         2080793 :     if (callContext) {
    1764          120090 :         if (op == JSOP_CALLNAME && bce->needsImplicitThis()) {
    1765            5170 :             if (!EmitAtomOp(cx, pn, JSOP_IMPLICITTHIS, bce))
    1766               0 :                 return false;
    1767                 :         } else {
    1768          114920 :             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    1769               0 :                 return false;
    1770                 :         }
    1771                 :     }
    1772                 : 
    1773         2080793 :     return JS_TRUE;
    1774                 : }
    1775                 : 
    1776                 : #if JS_HAS_XML_SUPPORT
    1777                 : static bool
    1778              63 : EmitXMLName(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
    1779                 : {
    1780              63 :     JS_ASSERT(!bce->inStrictMode());
    1781              63 :     JS_ASSERT(pn->isKind(PNK_XMLUNARY));
    1782              63 :     JS_ASSERT(pn->isOp(JSOP_XMLNAME));
    1783              63 :     JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME);
    1784                 : 
    1785              63 :     ParseNode *pn2 = pn->pn_kid;
    1786              63 :     unsigned oldflags = bce->flags;
    1787              63 :     bce->flags &= ~TCF_IN_FOR_INIT;
    1788              63 :     if (!EmitTree(cx, bce, pn2))
    1789               0 :         return false;
    1790              63 :     bce->flags |= oldflags & TCF_IN_FOR_INIT;
    1791              63 :     if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pn2->pn_offset) < 0)
    1792               0 :         return false;
    1793                 : 
    1794              63 :     if (Emit1(cx, bce, op) < 0)
    1795               0 :         return false;
    1796                 : 
    1797              63 :     return true;
    1798                 : }
    1799                 : #endif
    1800                 : 
    1801                 : static inline bool
    1802           43688 : EmitElemOpBase(JSContext *cx, BytecodeEmitter *bce, JSOp op)
    1803                 : {
    1804           43688 :     if (Emit1(cx, bce, op) < 0)
    1805               0 :         return false;
    1806           43688 :     CheckTypeSet(cx, bce, op);
    1807           43688 :     if (op == JSOP_CALLELEM)
    1808             558 :         return Emit1(cx, bce, JSOP_SWAP) >= 0;
    1809           43130 :     return true;
    1810                 : }
    1811                 : 
    1812                 : static bool
    1813             360 : EmitSpecialPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
    1814                 : {
    1815                 :     /*
    1816                 :      * Special case for obj.__proto__ to deoptimize away from fast paths in the
    1817                 :      * interpreter and trace recorder, which skip dense array instances by
    1818                 :      * going up to Array.prototype before looking up the property name.
    1819                 :      */
    1820             360 :     if (op == JSOP_CALLELEM && Emit1(cx, bce, JSOP_DUP) < 0)
    1821               0 :         return false;
    1822                 : 
    1823                 :     jsatomid index;
    1824             360 :     if (!bce->makeAtomIndex(pn->pn_atom, &index))
    1825               0 :         return false;
    1826             360 :     if (!EmitIndex32(cx, JSOP_QNAMEPART, index, bce))
    1827               0 :         return false;
    1828                 : 
    1829             360 :     return EmitElemOpBase(cx, bce, op);
    1830                 : }
    1831                 : 
    1832                 : static bool
    1833          115463 : EmitPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce,
    1834                 :            JSBool callContext)
    1835                 : {
    1836                 :     ParseNode *pn2, *pndot, *pnup, *pndown;
    1837                 :     ptrdiff_t top;
    1838                 : 
    1839          115463 :     JS_ASSERT(pn->isArity(PN_NAME));
    1840          115463 :     pn2 = pn->maybeExpr();
    1841                 : 
    1842                 :     /* Special case deoptimization for __proto__. */
    1843          115463 :     if ((op == JSOP_GETPROP || op == JSOP_CALLPROP) &&
    1844                 :         pn->pn_atom == cx->runtime->atomState.protoAtom) {
    1845             306 :         if (pn2 && !EmitTree(cx, bce, pn2))
    1846               0 :             return false;
    1847             306 :         return EmitSpecialPropOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, bce);
    1848                 :     }
    1849                 : 
    1850          115157 :     if (callContext) {
    1851           62206 :         JS_ASSERT(pn->isKind(PNK_DOT));
    1852           62206 :         JS_ASSERT(op == JSOP_GETPROP);
    1853           62206 :         op = JSOP_CALLPROP;
    1854           52951 :     } else if (op == JSOP_GETPROP && pn->isKind(PNK_DOT)) {
    1855           52150 :         if (pn2->isKind(PNK_NAME)) {
    1856           40093 :             if (!BindNameToSlot(cx, bce, pn2))
    1857               0 :                 return false;
    1858                 :         }
    1859                 :     }
    1860                 : 
    1861                 :     /*
    1862                 :      * If the object operand is also a dotted property reference, reverse the
    1863                 :      * list linked via pn_expr temporarily so we can iterate over it from the
    1864                 :      * bottom up (reversing again as we go), to avoid excessive recursion.
    1865                 :      */
    1866          115157 :     if (pn2->isKind(PNK_DOT)) {
    1867            7039 :         pndot = pn2;
    1868            7039 :         pnup = NULL;
    1869            7039 :         top = bce->offset();
    1870            2520 :         for (;;) {
    1871                 :             /* Reverse pndot->pn_expr to point up, not down. */
    1872            9559 :             pndot->pn_offset = top;
    1873            9559 :             JS_ASSERT(!pndot->isUsed());
    1874            9559 :             pndown = pndot->pn_expr;
    1875            9559 :             pndot->pn_expr = pnup;
    1876            9559 :             if (!pndown->isKind(PNK_DOT))
    1877                 :                 break;
    1878            2520 :             pnup = pndot;
    1879            2520 :             pndot = pndown;
    1880                 :         }
    1881                 : 
    1882                 :         /* pndown is a primary expression, not a dotted property reference. */
    1883            7039 :         if (!EmitTree(cx, bce, pndown))
    1884               0 :             return false;
    1885                 : 
    1886            9559 :         do {
    1887                 :             /* Walk back up the list, emitting annotated name ops. */
    1888            9559 :             if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pndown->pn_offset) < 0)
    1889               0 :                 return false;
    1890                 : 
    1891                 :             /* Special case deoptimization on __proto__, as above. */
    1892            9559 :             if (pndot->isArity(PN_NAME) && pndot->pn_atom == cx->runtime->atomState.protoAtom) {
    1893              54 :                 if (!EmitSpecialPropOp(cx, pndot, JSOP_GETELEM, bce))
    1894               0 :                     return false;
    1895            9505 :             } else if (!EmitAtomOp(cx, pndot, pndot->getOp(), bce)) {
    1896               0 :                 return false;
    1897                 :             }
    1898                 : 
    1899                 :             /* Reverse the pn_expr link again. */
    1900            9559 :             pnup = pndot->pn_expr;
    1901            9559 :             pndot->pn_expr = pndown;
    1902            9559 :             pndown = pndot;
    1903                 :         } while ((pndot = pnup) != NULL);
    1904                 :     } else {
    1905          108118 :         if (!EmitTree(cx, bce, pn2))
    1906               0 :             return false;
    1907                 :     }
    1908                 : 
    1909          115157 :     if (op == JSOP_CALLPROP && Emit1(cx, bce, JSOP_DUP) < 0)
    1910               0 :         return false;
    1911                 : 
    1912          115157 :     if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pn2->pn_offset) < 0)
    1913               0 :         return false;
    1914                 : 
    1915          115157 :     if (!EmitAtomOp(cx, pn, op, bce))
    1916               0 :         return false;
    1917                 : 
    1918          115157 :     if (op == JSOP_CALLPROP && Emit1(cx, bce, JSOP_SWAP) < 0)
    1919               0 :         return false;
    1920                 : 
    1921          115157 :     return true;
    1922                 : }
    1923                 : 
    1924                 : static bool
    1925             423 : EmitPropIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
    1926                 : {
    1927             423 :     if (!EmitPropOp(cx, pn, op, bce, false))
    1928               0 :         return false;
    1929                 : 
    1930                 :     /*
    1931                 :      * The stack is the same depth before/after INCPROP, so no balancing to do
    1932                 :      * before the decomposed version.
    1933                 :      */
    1934             423 :     int start = bce->offset();
    1935                 : 
    1936             423 :     const JSCodeSpec *cs = &js_CodeSpec[op];
    1937             423 :     JS_ASSERT(cs->format & JOF_PROP);
    1938             423 :     JS_ASSERT(cs->format & (JOF_INC | JOF_DEC));
    1939                 : 
    1940             423 :     bool post = (cs->format & JOF_POST);
    1941             423 :     JSOp binop = (cs->format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
    1942                 : 
    1943                 :                                                     // OBJ
    1944             423 :     if (Emit1(cx, bce, JSOP_DUP) < 0)               // OBJ OBJ
    1945               0 :         return false;
    1946             423 :     if (!EmitAtomOp(cx, pn, JSOP_GETPROP, bce))     // OBJ V
    1947               0 :         return false;
    1948             423 :     if (Emit1(cx, bce, JSOP_POS) < 0)               // OBJ N
    1949               0 :         return false;
    1950             423 :     if (post && Emit1(cx, bce, JSOP_DUP) < 0)       // OBJ N? N
    1951               0 :         return false;
    1952             423 :     if (Emit1(cx, bce, JSOP_ONE) < 0)               // OBJ N? N 1
    1953               0 :         return false;
    1954             423 :     if (Emit1(cx, bce, binop) < 0)                  // OBJ N? N+1
    1955               0 :         return false;
    1956                 : 
    1957             423 :     if (post) {
    1958             351 :         if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)   // N? N+1 OBJ
    1959               0 :             return false;
    1960             351 :         if (Emit1(cx, bce, JSOP_SWAP) < 0)                  // N? OBJ N+1
    1961               0 :             return false;
    1962                 :     }
    1963                 : 
    1964             423 :     if (!EmitAtomOp(cx, pn, JSOP_SETPROP, bce))     // N? N+1
    1965               0 :         return false;
    1966             423 :     if (post && Emit1(cx, bce, JSOP_POP) < 0)       // RESULT
    1967               0 :         return false;
    1968                 : 
    1969             423 :     UpdateDecomposeLength(bce, start);
    1970                 : 
    1971             423 :     return true;
    1972                 : }
    1973                 : 
    1974                 : static bool
    1975            7392 : EmitNameIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
    1976                 : {
    1977                 :     /* Emit the composite op, including the slack byte at the end. */
    1978            7392 :     if (!EmitAtomIncDec(cx, pn->pn_atom, op, bce))
    1979               0 :         return false;
    1980                 : 
    1981                 :     /* Remove the result to restore the stack depth before the INCNAME. */
    1982            7392 :     bce->stackDepth--;
    1983                 : 
    1984            7392 :     int start = bce->offset();
    1985                 : 
    1986            7392 :     const JSCodeSpec *cs = &js_CodeSpec[op];
    1987            7392 :     JS_ASSERT((cs->format & JOF_NAME) || (cs->format & JOF_GNAME));
    1988            7392 :     JS_ASSERT(cs->format & (JOF_INC | JOF_DEC));
    1989                 : 
    1990            7392 :     bool global = (cs->format & JOF_GNAME);
    1991            7392 :     bool post = (cs->format & JOF_POST);
    1992            7392 :     JSOp binop = (cs->format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
    1993                 : 
    1994            7392 :     if (!EmitAtomOp(cx, pn, global ? JSOP_BINDGNAME : JSOP_BINDNAME, bce))  // OBJ
    1995               0 :         return false;
    1996            7392 :     if (!EmitAtomOp(cx, pn, global ? JSOP_GETGNAME : JSOP_NAME, bce))       // OBJ V
    1997               0 :         return false;
    1998            7392 :     if (Emit1(cx, bce, JSOP_POS) < 0)               // OBJ N
    1999               0 :         return false;
    2000            7392 :     if (post && Emit1(cx, bce, JSOP_DUP) < 0)       // OBJ N? N
    2001               0 :         return false;
    2002            7392 :     if (Emit1(cx, bce, JSOP_ONE) < 0)               // OBJ N? N 1
    2003               0 :         return false;
    2004            7392 :     if (Emit1(cx, bce, binop) < 0)                  // OBJ N? N+1
    2005               0 :         return false;
    2006                 : 
    2007            7392 :     if (post) {
    2008            5334 :         if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)   // N? N+1 OBJ
    2009               0 :             return false;
    2010            5334 :         if (Emit1(cx, bce, JSOP_SWAP) < 0)                  // N? OBJ N+1
    2011               0 :             return false;
    2012                 :     }
    2013                 : 
    2014            7392 :     if (!EmitAtomOp(cx, pn, global ? JSOP_SETGNAME : JSOP_SETNAME, bce))    // N? N+1
    2015               0 :         return false;
    2016            7392 :     if (post && Emit1(cx, bce, JSOP_POP) < 0)       // RESULT
    2017               0 :         return false;
    2018                 : 
    2019            7392 :     UpdateDecomposeLength(bce, start);
    2020                 : 
    2021            7392 :     return true;
    2022                 : }
    2023                 : 
    2024                 : static JSBool
    2025           37271 : EmitElemOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
    2026                 : {
    2027                 :     ParseNode *left, *right;
    2028                 : 
    2029           37271 :     ptrdiff_t top = bce->offset();
    2030                 : 
    2031           37271 :     if (pn->isArity(PN_NAME)) {
    2032                 :         /*
    2033                 :          * Set left and right so pn appears to be a PNK_LB node, instead
    2034                 :          * of a PNK_DOT node.  See the PNK_FOR/IN case in EmitTree, and
    2035                 :          * EmitDestructuringOps nearer below.  In the destructuring case,
    2036                 :          * the base expression (pn_expr) of the name may be null, which
    2037                 :          * means we have to emit a JSOP_BINDNAME.
    2038                 :          */
    2039             261 :         left = pn->maybeExpr();
    2040             261 :         if (!left) {
    2041             261 :             left = NullaryNode::create(PNK_STRING, bce);
    2042             261 :             if (!left)
    2043               0 :                 return false;
    2044             261 :             left->setOp(JSOP_BINDNAME);
    2045             261 :             left->pn_pos = pn->pn_pos;
    2046             261 :             left->pn_atom = pn->pn_atom;
    2047                 :         }
    2048             261 :         right = NullaryNode::create(PNK_STRING, bce);
    2049             261 :         if (!right)
    2050               0 :             return false;
    2051             261 :         right->setOp(IsIdentifier(pn->pn_atom) ? JSOP_QNAMEPART : JSOP_STRING);
    2052             261 :         right->pn_pos = pn->pn_pos;
    2053             261 :         right->pn_atom = pn->pn_atom;
    2054                 :     } else {
    2055           37010 :         JS_ASSERT(pn->isArity(PN_BINARY));
    2056           37010 :         left = pn->pn_left;
    2057           37010 :         right = pn->pn_right;
    2058                 :     }
    2059                 : 
    2060           37271 :     if (op == JSOP_GETELEM && left->isKind(PNK_NAME) && right->isKind(PNK_NUMBER)) {
    2061            8082 :         if (!BindNameToSlot(cx, bce, left))
    2062               0 :             return false;
    2063                 :     }
    2064                 : 
    2065           37271 :     if (!EmitTree(cx, bce, left))
    2066               0 :         return false;
    2067                 : 
    2068           37271 :     if (op == JSOP_CALLELEM && Emit1(cx, bce, JSOP_DUP) < 0)
    2069               0 :         return false;
    2070                 : 
    2071                 :     /* The right side of the descendant operator is implicitly quoted. */
    2072              18 :     JS_ASSERT(op != JSOP_DESCENDANTS || !right->isKind(PNK_STRING) ||
    2073           37289 :               right->isOp(JSOP_QNAMEPART));
    2074           37271 :     if (!EmitTree(cx, bce, right))
    2075               0 :         return false;
    2076           37271 :     if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - top) < 0)
    2077               0 :         return false;
    2078           37271 :     return EmitElemOpBase(cx, bce, op);
    2079                 : }
    2080                 : 
    2081                 : static bool
    2082             468 : EmitElemIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
    2083                 : {
    2084             468 :     if (pn) {
    2085             459 :         if (!EmitElemOp(cx, pn, op, bce))
    2086               0 :             return false;
    2087                 :     } else {
    2088               9 :         if (!EmitElemOpBase(cx, bce, op))
    2089               0 :             return false;
    2090                 :     }
    2091             468 :     if (Emit1(cx, bce, JSOP_NOP) < 0)
    2092               0 :         return false;
    2093                 : 
    2094                 :     /* INCELEM pops two values and pushes one, so restore the initial depth. */
    2095             468 :     bce->stackDepth++;
    2096                 : 
    2097             468 :     int start = bce->offset();
    2098                 : 
    2099             468 :     const JSCodeSpec *cs = &js_CodeSpec[op];
    2100             468 :     JS_ASSERT(cs->format & JOF_ELEM);
    2101             468 :     JS_ASSERT(cs->format & (JOF_INC | JOF_DEC));
    2102                 : 
    2103             468 :     bool post = (cs->format & JOF_POST);
    2104             468 :     JSOp binop = (cs->format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
    2105                 : 
    2106                 :     /*
    2107                 :      * We need to convert the key to an object id first, so that we do not do
    2108                 :      * it inside both the GETELEM and the SETELEM.
    2109                 :      */
    2110                 :                                                     // OBJ KEY*
    2111             468 :     if (Emit1(cx, bce, JSOP_TOID) < 0)              // OBJ KEY
    2112               0 :         return false;
    2113             468 :     if (Emit1(cx, bce, JSOP_DUP2) < 0)              // OBJ KEY OBJ KEY
    2114               0 :         return false;
    2115             468 :     if (!EmitElemOpBase(cx, bce, JSOP_GETELEM))     // OBJ KEY V
    2116               0 :         return false;
    2117             468 :     if (Emit1(cx, bce, JSOP_POS) < 0)               // OBJ KEY N
    2118               0 :         return false;
    2119             468 :     if (post && Emit1(cx, bce, JSOP_DUP) < 0)       // OBJ KEY N? N
    2120               0 :         return false;
    2121             468 :     if (Emit1(cx, bce, JSOP_ONE) < 0)               // OBJ KEY N? N 1
    2122               0 :         return false;
    2123             468 :     if (Emit1(cx, bce, binop) < 0)                  // OBJ KEY N? N+1
    2124               0 :         return false;
    2125                 : 
    2126             468 :     if (post) {
    2127             351 :         if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)3) < 0)   // KEY N N+1 OBJ
    2128               0 :             return false;
    2129             351 :         if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)3) < 0)   // N N+1 OBJ KEY
    2130               0 :             return false;
    2131             351 :         if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)   // N OBJ KEY N+1
    2132               0 :             return false;
    2133                 :     }
    2134                 : 
    2135             468 :     if (!EmitElemOpBase(cx, bce, JSOP_SETELEM))     // N? N+1
    2136               0 :         return false;
    2137             468 :     if (post && Emit1(cx, bce, JSOP_POP) < 0)       // RESULT
    2138               0 :         return false;
    2139                 : 
    2140             468 :     UpdateDecomposeLength(bce, start);
    2141                 : 
    2142             468 :     return true;
    2143                 : }
    2144                 : 
    2145                 : static JSBool
    2146          426066 : EmitNumberOp(JSContext *cx, double dval, BytecodeEmitter *bce)
    2147                 : {
    2148                 :     int32_t ival;
    2149                 :     uint32_t u;
    2150                 :     ptrdiff_t off;
    2151                 :     jsbytecode *pc;
    2152                 : 
    2153          426066 :     if (JSDOUBLE_IS_INT32(dval, &ival)) {
    2154          416344 :         if (ival == 0)
    2155           89843 :             return Emit1(cx, bce, JSOP_ZERO) >= 0;
    2156          326501 :         if (ival == 1)
    2157          114938 :             return Emit1(cx, bce, JSOP_ONE) >= 0;
    2158          211563 :         if ((int)(int8_t)ival == ival)
    2159          198952 :             return Emit2(cx, bce, JSOP_INT8, (jsbytecode)(int8_t)ival) >= 0;
    2160                 : 
    2161           12611 :         u = (uint32_t)ival;
    2162           12611 :         if (u < JS_BIT(16)) {
    2163            8516 :             EMIT_UINT16_IMM_OP(JSOP_UINT16, u);
    2164            4095 :         } else if (u < JS_BIT(24)) {
    2165             558 :             off = EmitN(cx, bce, JSOP_UINT24, 3);
    2166             558 :             if (off < 0)
    2167               0 :                 return JS_FALSE;
    2168             558 :             pc = bce->code(off);
    2169             558 :             SET_UINT24(pc, u);
    2170                 :         } else {
    2171            3537 :             off = EmitN(cx, bce, JSOP_INT32, 4);
    2172            3537 :             if (off < 0)
    2173               0 :                 return JS_FALSE;
    2174            3537 :             pc = bce->code(off);
    2175            3537 :             SET_INT32(pc, ival);
    2176                 :         }
    2177           12611 :         return JS_TRUE;
    2178                 :     }
    2179                 : 
    2180            9722 :     if (!bce->constList.append(DoubleValue(dval)))
    2181               0 :         return JS_FALSE;
    2182                 : 
    2183            9722 :     return EmitIndex32(cx, JSOP_DOUBLE, bce->constList.length() - 1, bce);
    2184                 : }
    2185                 : 
    2186                 : /*
    2187                 :  * To avoid bloating all parse nodes for the special case of switch, values are
    2188                 :  * allocated in the temp pool and pointed to by the parse node. These values
    2189                 :  * are not currently recycled (like parse nodes) and the temp pool is only
    2190                 :  * flushed at the end of compiling a script, so these values are technically
    2191                 :  * leaked. This would only be a problem for scripts containing a large number
    2192                 :  * of large switches, which seems unlikely.
    2193                 :  */
    2194                 : static Value *
    2195            2754 : AllocateSwitchConstant(JSContext *cx)
    2196                 : {
    2197            2754 :     return cx->tempLifoAlloc().new_<Value>();
    2198                 : }
    2199                 : 
    2200                 : static inline void
    2201          138048 : SetJumpOffsetAt(BytecodeEmitter *bce, ptrdiff_t off)
    2202                 : {
    2203          138048 :     SET_JUMP_OFFSET(bce->code(off), bce->offset() - off);
    2204          138048 : }
    2205                 : 
    2206                 : /*
    2207                 :  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr12127.
    2208                 :  * LLVM is deciding to inline this function which uses a lot of stack space
    2209                 :  * into EmitTree which is recursive and uses relatively little stack space.
    2210                 :  */
    2211                 : MOZ_NEVER_INLINE static JSBool
    2212             873 : EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    2213                 : {
    2214                 :     JSOp switchOp;
    2215                 :     JSBool ok, hasDefault, constPropagated;
    2216                 :     ptrdiff_t top, off, defaultOffset;
    2217                 :     ParseNode *pn2, *pn3, *pn4;
    2218                 :     uint32_t caseCount, tableLength;
    2219                 :     ParseNode **table;
    2220                 :     int32_t i, low, high;
    2221                 :     int noteIndex;
    2222                 :     size_t switchSize, tableSize;
    2223                 :     jsbytecode *pc, *savepc;
    2224                 :     StmtInfo stmtInfo;
    2225                 : 
    2226                 :     /* Try for most optimal, fall back if not dense ints, and per ECMAv2. */
    2227             873 :     switchOp = JSOP_TABLESWITCH;
    2228             873 :     ok = JS_TRUE;
    2229             873 :     hasDefault = constPropagated = JS_FALSE;
    2230             873 :     defaultOffset = -1;
    2231                 : 
    2232             873 :     pn2 = pn->pn_right;
    2233                 : #if JS_HAS_BLOCK_SCOPE
    2234                 :     /*
    2235                 :      * If there are hoisted let declarations, their stack slots go under the
    2236                 :      * discriminant's value so push their slots now and enter the block later.
    2237                 :      */
    2238             873 :     uint32_t blockObjCount = 0;
    2239             873 :     if (pn2->isKind(PNK_LEXICALSCOPE)) {
    2240             108 :         blockObjCount = pn2->pn_objbox->object->asStaticBlock().slotCount();
    2241             261 :         for (uint32_t i = 0; i < blockObjCount; ++i) {
    2242             153 :             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    2243               0 :                 return JS_FALSE;
    2244                 :         }
    2245                 :     }
    2246                 : #endif
    2247                 : 
    2248                 :     /* Push the discriminant. */
    2249             873 :     if (!EmitTree(cx, bce, pn->pn_left))
    2250               0 :         return JS_FALSE;
    2251                 : 
    2252                 : #if JS_HAS_BLOCK_SCOPE
    2253             873 :     if (pn2->isKind(PNK_LEXICALSCOPE)) {
    2254             108 :         PushBlockScope(bce, &stmtInfo, pn2->pn_objbox->object->asStaticBlock(), -1);
    2255             108 :         stmtInfo.type = STMT_SWITCH;
    2256             108 :         if (!EmitEnterBlock(cx, bce, pn2, JSOP_ENTERLET1))
    2257               0 :             return JS_FALSE;
    2258                 :     }
    2259                 : #endif
    2260                 : 
    2261                 :     /* Switch bytecodes run from here till end of final case. */
    2262             873 :     top = bce->offset();
    2263                 : #if !JS_HAS_BLOCK_SCOPE
    2264                 :     PushStatement(bce, &stmtInfo, STMT_SWITCH, top);
    2265                 : #else
    2266             873 :     if (pn2->isKind(PNK_STATEMENTLIST)) {
    2267             765 :         PushStatement(bce, &stmtInfo, STMT_SWITCH, top);
    2268                 :     } else {
    2269                 :         /*
    2270                 :          * Set the statement info record's idea of top. Reset top too, since
    2271                 :          * repushBlock emits code.
    2272                 :          */
    2273             108 :         stmtInfo.update = top = bce->offset();
    2274                 : 
    2275                 :         /* Advance pn2 to refer to the switch case list. */
    2276             108 :         pn2 = pn2->expr();
    2277                 :     }
    2278                 : #endif
    2279                 : 
    2280             873 :     caseCount = pn2->pn_count;
    2281             873 :     tableLength = 0;
    2282             873 :     table = NULL;
    2283                 : 
    2284             999 :     if (caseCount == 0 ||
    2285                 :         (caseCount == 1 &&
    2286             126 :          (hasDefault = (pn2->pn_head->isKind(PNK_DEFAULT))))) {
    2287              81 :         caseCount = 0;
    2288              81 :         low = 0;
    2289              81 :         high = -1;
    2290                 :     } else {
    2291                 : #define INTMAP_LENGTH   256
    2292                 :         jsbitmap intmap_space[INTMAP_LENGTH];
    2293             792 :         jsbitmap *intmap = NULL;
    2294             792 :         int32_t intmap_bitlen = 0;
    2295                 : 
    2296             792 :         low  = JSVAL_INT_MAX;
    2297             792 :         high = JSVAL_INT_MIN;
    2298                 : 
    2299            4329 :         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    2300            3537 :             if (pn3->isKind(PNK_DEFAULT)) {
    2301             486 :                 hasDefault = JS_TRUE;
    2302             486 :                 caseCount--;    /* one of the "cases" was the default */
    2303             486 :                 continue;
    2304                 :             }
    2305                 : 
    2306            3051 :             JS_ASSERT(pn3->isKind(PNK_CASE));
    2307            3051 :             if (switchOp == JSOP_CONDSWITCH)
    2308             153 :                 continue;
    2309                 : 
    2310            2898 :             pn4 = pn3->pn_left;
    2311            5796 :             while (pn4->isKind(PNK_RP))
    2312               0 :                 pn4 = pn4->pn_kid;
    2313                 : 
    2314                 :             Value constVal;
    2315            2898 :             switch (pn4->getKind()) {
    2316                 :               case PNK_NUMBER:
    2317            1575 :                 constVal.setNumber(pn4->pn_dval);
    2318            1575 :                 break;
    2319                 :               case PNK_STRING:
    2320            1161 :                 constVal.setString(pn4->pn_atom);
    2321            1161 :                 break;
    2322                 :               case PNK_TRUE:
    2323               0 :                 constVal.setBoolean(true);
    2324               0 :                 break;
    2325                 :               case PNK_FALSE:
    2326               0 :                 constVal.setBoolean(false);
    2327               0 :                 break;
    2328                 :               case PNK_NULL:
    2329               0 :                 constVal.setNull();
    2330               0 :                 break;
    2331                 :               case PNK_NAME:
    2332              81 :                 if (!pn4->maybeExpr()) {
    2333              81 :                     ok = LookupCompileTimeConstant(cx, bce, pn4->pn_atom, &constVal);
    2334              81 :                     if (!ok)
    2335               0 :                         goto release;
    2336              81 :                     if (!constVal.isMagic(JS_NO_CONSTANT)) {
    2337              18 :                         if (constVal.isObject()) {
    2338                 :                             /*
    2339                 :                              * XXX JSOP_LOOKUPSWITCH does not support const-
    2340                 :                              * propagated object values, see bug 407186.
    2341                 :                              */
    2342               0 :                             switchOp = JSOP_CONDSWITCH;
    2343               0 :                             continue;
    2344                 :                         }
    2345              18 :                         constPropagated = JS_TRUE;
    2346              18 :                         break;
    2347                 :                     }
    2348                 :                 }
    2349                 :                 /* FALL THROUGH */
    2350                 :               default:
    2351             144 :                 switchOp = JSOP_CONDSWITCH;
    2352             144 :                 continue;
    2353                 :             }
    2354            2754 :             JS_ASSERT(constVal.isPrimitive());
    2355                 : 
    2356            2754 :             pn3->pn_pval = AllocateSwitchConstant(cx);
    2357            2754 :             if (!pn3->pn_pval) {
    2358               0 :                 ok = JS_FALSE;
    2359               0 :                 goto release;
    2360                 :             }
    2361                 : 
    2362            2754 :             *pn3->pn_pval = constVal;
    2363                 : 
    2364            2754 :             if (switchOp != JSOP_TABLESWITCH)
    2365             963 :                 continue;
    2366            1791 :             if (!pn3->pn_pval->isInt32()) {
    2367             198 :                 switchOp = JSOP_LOOKUPSWITCH;
    2368             198 :                 continue;
    2369                 :             }
    2370            1593 :             i = pn3->pn_pval->toInt32();
    2371            1593 :             if ((unsigned)(i + (int)JS_BIT(15)) >= (unsigned)JS_BIT(16)) {
    2372               0 :                 switchOp = JSOP_LOOKUPSWITCH;
    2373               0 :                 continue;
    2374                 :             }
    2375            1593 :             if (i < low)
    2376             576 :                 low = i;
    2377            1593 :             if (high < i)
    2378            1287 :                 high = i;
    2379                 : 
    2380                 :             /*
    2381                 :              * Check for duplicates, which require a JSOP_LOOKUPSWITCH.
    2382                 :              * We bias i by 65536 if it's negative, and hope that's a rare
    2383                 :              * case (because it requires a malloc'd bitmap).
    2384                 :              */
    2385            1593 :             if (i < 0)
    2386              45 :                 i += JS_BIT(16);
    2387            1593 :             if (i >= intmap_bitlen) {
    2388             504 :                 if (!intmap &&
    2389                 :                     i < (INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2)) {
    2390             477 :                     intmap = intmap_space;
    2391             477 :                     intmap_bitlen = INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2;
    2392                 :                 } else {
    2393                 :                     /* Just grab 8K for the worst-case bitmap. */
    2394              27 :                     intmap_bitlen = JS_BIT(16);
    2395                 :                     intmap = (jsbitmap *)
    2396                 :                         cx->malloc_((JS_BIT(16) >> JS_BITS_PER_WORD_LOG2)
    2397              27 :                                    * sizeof(jsbitmap));
    2398              27 :                     if (!intmap) {
    2399               0 :                         JS_ReportOutOfMemory(cx);
    2400               0 :                         return JS_FALSE;
    2401                 :                     }
    2402                 :                 }
    2403             504 :                 memset(intmap, 0, intmap_bitlen >> JS_BITS_PER_BYTE_LOG2);
    2404                 :             }
    2405            1593 :             if (JS_TEST_BIT(intmap, i)) {
    2406               0 :                 switchOp = JSOP_LOOKUPSWITCH;
    2407               0 :                 continue;
    2408                 :             }
    2409            1593 :             JS_SET_BIT(intmap, i);
    2410                 :         }
    2411                 : 
    2412                 :       release:
    2413             792 :         if (intmap && intmap != intmap_space)
    2414              27 :             cx->free_(intmap);
    2415             792 :         if (!ok)
    2416               0 :             return JS_FALSE;
    2417                 : 
    2418                 :         /*
    2419                 :          * Compute table length and select lookup instead if overlarge or
    2420                 :          * more than half-sparse.
    2421                 :          */
    2422             792 :         if (switchOp == JSOP_TABLESWITCH) {
    2423             468 :             tableLength = (uint32_t)(high - low + 1);
    2424             468 :             if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount)
    2425              36 :                 switchOp = JSOP_LOOKUPSWITCH;
    2426             324 :         } else if (switchOp == JSOP_LOOKUPSWITCH) {
    2427                 :             /*
    2428                 :              * Lookup switch supports only atom indexes below 64K limit.
    2429                 :              * Conservatively estimate the maximum possible index during
    2430                 :              * switch generation and use conditional switch if it exceeds
    2431                 :              * the limit.
    2432                 :              */
    2433             180 :             if (caseCount + bce->constList.length() > JS_BIT(16))
    2434               0 :                 switchOp = JSOP_CONDSWITCH;
    2435                 :         }
    2436                 :     }
    2437                 : 
    2438                 :     /*
    2439                 :      * Emit a note with two offsets: first tells total switch code length,
    2440                 :      * second tells offset to first JSOP_CASE if condswitch.
    2441                 :      */
    2442             873 :     noteIndex = NewSrcNote3(cx, bce, SRC_SWITCH, 0, 0);
    2443             873 :     if (noteIndex < 0)
    2444               0 :         return JS_FALSE;
    2445                 : 
    2446             873 :     if (switchOp == JSOP_CONDSWITCH) {
    2447                 :         /*
    2448                 :          * 0 bytes of immediate for unoptimized ECMAv2 switch.
    2449                 :          */
    2450             144 :         switchSize = 0;
    2451             729 :     } else if (switchOp == JSOP_TABLESWITCH) {
    2452                 :         /*
    2453                 :          * 3 offsets (len, low, high) before the table, 1 per entry.
    2454                 :          */
    2455             513 :         switchSize = (size_t)(JUMP_OFFSET_LEN * (3 + tableLength));
    2456                 :     } else {
    2457                 :         /*
    2458                 :          * JSOP_LOOKUPSWITCH:
    2459                 :          * 1 offset (len) and 1 atom index (npairs) before the table,
    2460                 :          * 1 atom index and 1 jump offset per entry.
    2461                 :          */
    2462                 :         switchSize = (size_t)(JUMP_OFFSET_LEN + UINT16_LEN +
    2463             216 :                               (UINT32_INDEX_LEN + JUMP_OFFSET_LEN) * caseCount);
    2464                 :     }
    2465                 : 
    2466                 :     /* Emit switchOp followed by switchSize bytes of jump or lookup table. */
    2467             873 :     if (EmitN(cx, bce, switchOp, switchSize) < 0)
    2468               0 :         return JS_FALSE;
    2469                 : 
    2470             873 :     off = -1;
    2471             873 :     if (switchOp == JSOP_CONDSWITCH) {
    2472             144 :         int caseNoteIndex = -1;
    2473             144 :         JSBool beforeCases = JS_TRUE;
    2474                 : 
    2475                 :         /* Emit code for evaluating cases and jumping to case statements. */
    2476             567 :         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    2477             423 :             pn4 = pn3->pn_left;
    2478             423 :             if (pn4 && !EmitTree(cx, bce, pn4))
    2479               0 :                 return JS_FALSE;
    2480             423 :             if (caseNoteIndex >= 0) {
    2481                 :                 /* off is the previous JSOP_CASE's bytecode offset. */
    2482             252 :                 if (!SetSrcNoteOffset(cx, bce, (unsigned)caseNoteIndex, 0, bce->offset() - off))
    2483               0 :                     return JS_FALSE;
    2484                 :             }
    2485             423 :             if (!pn4) {
    2486              81 :                 JS_ASSERT(pn3->isKind(PNK_DEFAULT));
    2487              81 :                 continue;
    2488                 :             }
    2489             342 :             caseNoteIndex = NewSrcNote2(cx, bce, SRC_PCDELTA, 0);
    2490             342 :             if (caseNoteIndex < 0)
    2491               0 :                 return JS_FALSE;
    2492             342 :             off = EmitJump(cx, bce, JSOP_CASE, 0);
    2493             342 :             if (off < 0)
    2494               0 :                 return JS_FALSE;
    2495             342 :             pn3->pn_offset = off;
    2496             342 :             if (beforeCases) {
    2497                 :                 unsigned noteCount, noteCountDelta;
    2498                 : 
    2499                 :                 /* Switch note's second offset is to first JSOP_CASE. */
    2500             144 :                 noteCount = bce->noteCount();
    2501             144 :                 if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 1, off - top))
    2502               0 :                     return JS_FALSE;
    2503             144 :                 noteCountDelta = bce->noteCount() - noteCount;
    2504             144 :                 if (noteCountDelta != 0)
    2505               0 :                     caseNoteIndex += noteCountDelta;
    2506             144 :                 beforeCases = JS_FALSE;
    2507                 :             }
    2508                 :         }
    2509                 : 
    2510                 :         /*
    2511                 :          * If we didn't have an explicit default (which could fall in between
    2512                 :          * cases, preventing us from fusing this SetSrcNoteOffset with the call
    2513                 :          * in the loop above), link the last case to the implicit default for
    2514                 :          * the decompiler.
    2515                 :          */
    2516             207 :         if (!hasDefault &&
    2517                 :             caseNoteIndex >= 0 &&
    2518              63 :             !SetSrcNoteOffset(cx, bce, (unsigned)caseNoteIndex, 0, bce->offset() - off))
    2519                 :         {
    2520               0 :             return JS_FALSE;
    2521                 :         }
    2522                 : 
    2523                 :         /* Emit default even if no explicit default statement. */
    2524             144 :         defaultOffset = EmitJump(cx, bce, JSOP_DEFAULT, 0);
    2525             144 :         if (defaultOffset < 0)
    2526               0 :             return JS_FALSE;
    2527                 :     } else {
    2528             729 :         pc = bce->code(top + JUMP_OFFSET_LEN);
    2529                 : 
    2530             729 :         if (switchOp == JSOP_TABLESWITCH) {
    2531                 :             /* Fill in switch bounds, which we know fit in 16-bit offsets. */
    2532             513 :             SET_JUMP_OFFSET(pc, low);
    2533             513 :             pc += JUMP_OFFSET_LEN;
    2534             513 :             SET_JUMP_OFFSET(pc, high);
    2535             513 :             pc += JUMP_OFFSET_LEN;
    2536                 : 
    2537                 :             /*
    2538                 :              * Use malloc to avoid arena bloat for programs with many switches.
    2539                 :              * We free table if non-null at label out, so all control flow must
    2540                 :              * exit this function through goto out or goto bad.
    2541                 :              */
    2542             513 :             if (tableLength != 0) {
    2543             432 :                 tableSize = (size_t)tableLength * sizeof *table;
    2544             432 :                 table = (ParseNode **) cx->malloc_(tableSize);
    2545             432 :                 if (!table)
    2546               0 :                     return JS_FALSE;
    2547             432 :                 memset(table, 0, tableSize);
    2548            1971 :                 for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    2549            1539 :                     if (pn3->isKind(PNK_DEFAULT))
    2550             261 :                         continue;
    2551            1278 :                     i = pn3->pn_pval->toInt32();
    2552            1278 :                     i -= low;
    2553            1278 :                     JS_ASSERT((uint32_t)i < tableLength);
    2554            1278 :                     table[i] = pn3;
    2555                 :                 }
    2556                 :             }
    2557                 :         } else {
    2558             216 :             JS_ASSERT(switchOp == JSOP_LOOKUPSWITCH);
    2559                 : 
    2560                 :             /* Fill in the number of cases. */
    2561             216 :             SET_UINT16(pc, caseCount);
    2562             216 :             pc += UINT16_LEN;
    2563                 :         }
    2564                 : 
    2565                 :         /*
    2566                 :          * After this point, all control flow involving JSOP_TABLESWITCH
    2567                 :          * must set ok and goto out to exit this function.  To keep things
    2568                 :          * simple, all switchOp cases exit that way.
    2569                 :          */
    2570                 :         MUST_FLOW_THROUGH("out");
    2571                 : 
    2572             729 :         if (constPropagated) {
    2573                 :             /*
    2574                 :              * Skip switchOp, as we are not setting jump offsets in the two
    2575                 :              * for loops below.  We'll restore bce->next() from savepc after,
    2576                 :              * unless there was an error.
    2577                 :              */
    2578              18 :             savepc = bce->next();
    2579              18 :             bce->current->next = pc + 1;
    2580              18 :             if (switchOp == JSOP_TABLESWITCH) {
    2581              36 :                 for (i = 0; i < (int)tableLength; i++) {
    2582              18 :                     pn3 = table[i];
    2583              36 :                     if (pn3 &&
    2584                 :                         (pn4 = pn3->pn_left) != NULL &&
    2585              18 :                         pn4->isKind(PNK_NAME))
    2586                 :                     {
    2587                 :                         /* Note a propagated constant with the const's name. */
    2588              18 :                         JS_ASSERT(!pn4->maybeExpr());
    2589                 :                         jsatomid index;
    2590              18 :                         if (!bce->makeAtomIndex(pn4->pn_atom, &index))
    2591               0 :                             goto bad;
    2592              18 :                         bce->current->next = pc;
    2593              18 :                         if (NewSrcNote2(cx, bce, SRC_LABEL, ptrdiff_t(index)) < 0)
    2594               0 :                             goto bad;
    2595                 :                     }
    2596              18 :                     pc += JUMP_OFFSET_LEN;
    2597                 :                 }
    2598                 :             } else {
    2599               0 :                 for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    2600               0 :                     pn4 = pn3->pn_left;
    2601               0 :                     if (pn4 && pn4->isKind(PNK_NAME)) {
    2602                 :                         /* Note a propagated constant with the const's name. */
    2603               0 :                         JS_ASSERT(!pn4->maybeExpr());
    2604                 :                         jsatomid index;
    2605               0 :                         if (!bce->makeAtomIndex(pn4->pn_atom, &index))
    2606               0 :                             goto bad;
    2607               0 :                         bce->current->next = pc;
    2608               0 :                         if (NewSrcNote2(cx, bce, SRC_LABEL, ptrdiff_t(index)) < 0)
    2609               0 :                             goto bad;
    2610                 :                     }
    2611               0 :                     pc += UINT32_INDEX_LEN + JUMP_OFFSET_LEN;
    2612                 :                 }
    2613                 :             }
    2614              18 :             bce->current->next = savepc;
    2615                 :         }
    2616                 :     }
    2617                 : 
    2618                 :     /* Emit code for each case's statements, copying pn_offset up to pn3. */
    2619            4446 :     for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    2620            3573 :         if (switchOp == JSOP_CONDSWITCH && !pn3->isKind(PNK_DEFAULT))
    2621             342 :             SetJumpOffsetAt(bce, pn3->pn_offset);
    2622            3573 :         pn4 = pn3->pn_right;
    2623            3573 :         ok = EmitTree(cx, bce, pn4);
    2624            3573 :         if (!ok)
    2625               0 :             goto out;
    2626            3573 :         pn3->pn_offset = pn4->pn_offset;
    2627            3573 :         if (pn3->isKind(PNK_DEFAULT))
    2628             522 :             off = pn3->pn_offset - top;
    2629                 :     }
    2630                 : 
    2631             873 :     if (!hasDefault) {
    2632                 :         /* If no default case, offset for default is to end of switch. */
    2633             351 :         off = bce->offset() - top;
    2634                 :     }
    2635                 : 
    2636                 :     /* We better have set "off" by now. */
    2637             873 :     JS_ASSERT(off != -1);
    2638                 : 
    2639                 :     /* Set the default offset (to end of switch if no default). */
    2640             873 :     if (switchOp == JSOP_CONDSWITCH) {
    2641             144 :         pc = NULL;
    2642             144 :         JS_ASSERT(defaultOffset != -1);
    2643             144 :         SET_JUMP_OFFSET(bce->code(defaultOffset), off - (defaultOffset - top));
    2644                 :     } else {
    2645             729 :         pc = bce->code(top);
    2646             729 :         SET_JUMP_OFFSET(pc, off);
    2647             729 :         pc += JUMP_OFFSET_LEN;
    2648                 :     }
    2649                 : 
    2650                 :     /* Set the SRC_SWITCH note's offset operand to tell end of switch. */
    2651             873 :     off = bce->offset() - top;
    2652             873 :     ok = SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, off);
    2653             873 :     if (!ok)
    2654               0 :         goto out;
    2655                 : 
    2656             873 :     if (switchOp == JSOP_TABLESWITCH) {
    2657                 :         /* Skip over the already-initialized switch bounds. */
    2658             513 :         pc += 2 * JUMP_OFFSET_LEN;
    2659                 : 
    2660                 :         /* Fill in the jump table, if there is one. */
    2661            1872 :         for (i = 0; i < (int)tableLength; i++) {
    2662            1359 :             pn3 = table[i];
    2663            1359 :             off = pn3 ? pn3->pn_offset - top : 0;
    2664            1359 :             SET_JUMP_OFFSET(pc, off);
    2665            1359 :             pc += JUMP_OFFSET_LEN;
    2666                 :         }
    2667             360 :     } else if (switchOp == JSOP_LOOKUPSWITCH) {
    2668                 :         /* Skip over the already-initialized number of cases. */
    2669             216 :         pc += UINT16_LEN;
    2670                 : 
    2671            1791 :         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    2672            1575 :             if (pn3->isKind(PNK_DEFAULT))
    2673             144 :                 continue;
    2674            1431 :             if (!bce->constList.append(*pn3->pn_pval))
    2675               0 :                 goto bad;
    2676            1431 :             SET_UINT32_INDEX(pc, bce->constList.length() - 1);
    2677            1431 :             pc += UINT32_INDEX_LEN;
    2678                 : 
    2679            1431 :             off = pn3->pn_offset - top;
    2680            1431 :             SET_JUMP_OFFSET(pc, off);
    2681            1431 :             pc += JUMP_OFFSET_LEN;
    2682                 :         }
    2683                 :     }
    2684                 : 
    2685                 : out:
    2686             873 :     if (table)
    2687             432 :         cx->free_(table);
    2688             873 :     if (ok) {
    2689             873 :         ok = PopStatementBCE(cx, bce);
    2690                 : 
    2691                 : #if JS_HAS_BLOCK_SCOPE
    2692             873 :         if (ok && pn->pn_right->isKind(PNK_LEXICALSCOPE))
    2693             108 :             EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObjCount);
    2694                 : #endif
    2695                 :     }
    2696             873 :     return ok;
    2697                 : 
    2698                 : bad:
    2699               0 :     ok = JS_FALSE;
    2700               0 :     goto out;
    2701                 : }
    2702                 : 
    2703                 : JSBool
    2704          164453 : frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *body)
    2705                 : {
    2706                 :     /*
    2707                 :      * The decompiler has assumptions about what may occur immediately after
    2708                 :      * script->main (e.g., in the case of destructuring params). Thus, put the
    2709                 :      * following ops into the range [script->code, script->main). Note:
    2710                 :      * execution starts from script->code, so this has no semantic effect.
    2711                 :      */
    2712                 : 
    2713          164453 :     if (bce->flags & TCF_FUN_IS_GENERATOR) {
    2714                 :         /* JSOP_GENERATOR must be the first instruction. */
    2715             684 :         bce->switchToProlog();
    2716             684 :         JS_ASSERT(bce->next() == bce->base());
    2717             684 :         if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
    2718               0 :             return false;
    2719             684 :         bce->switchToMain();
    2720                 :     }
    2721                 : 
    2722          164453 :     return EmitTree(cx, bce, body) &&
    2723          164453 :            Emit1(cx, bce, JSOP_STOP) >= 0 &&
    2724          328906 :            JSScript::NewScriptFromEmitter(cx, bce);
    2725                 : }
    2726                 : 
    2727                 : static bool
    2728          461074 : MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn,
    2729                 :                  jsatomid *result)
    2730                 : {
    2731                 :     jsatomid atomIndex;
    2732                 : 
    2733          461074 :     if (!pn->pn_cookie.isFree()) {
    2734          355377 :         atomIndex = pn->pn_cookie.slot();
    2735                 :     } else {
    2736          105697 :         if (!bce->makeAtomIndex(pn->pn_atom, &atomIndex))
    2737               0 :             return false;
    2738                 :     }
    2739                 : 
    2740          672468 :     if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
    2741          105697 :         (!bce->inFunction() || (bce->flags & TCF_FUN_HEAVYWEIGHT)) &&
    2742          105697 :         !(pn->pn_dflags & PND_GVAR))
    2743                 :     {
    2744           58908 :         bce->switchToProlog();
    2745           58908 :         if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
    2746               0 :             return false;
    2747           58908 :         if (!EmitIndexOp(cx, prologOp, atomIndex, bce))
    2748               0 :             return false;
    2749           58908 :         bce->switchToMain();
    2750                 :     }
    2751                 : 
    2752          997373 :     if (bce->inFunction() &&
    2753          206859 :         JOF_OPTYPE(pn->getOp()) == JOF_LOCAL &&
    2754          206526 :         pn->pn_cookie.slot() < bce->bindings.countVars() &&
    2755          122914 :         bce->shouldNoteClosedName(pn))
    2756                 :     {
    2757            4563 :         if (!bce->closedVars.append(pn->pn_cookie.slot()))
    2758               0 :             return false;
    2759                 :     }
    2760                 : 
    2761          461074 :     if (result)
    2762          459301 :         *result = atomIndex;
    2763          461074 :     return true;
    2764                 : }
    2765                 : 
    2766                 : /*
    2767                 :  * This enum tells EmitVariables and the destructuring functions how emit the
    2768                 :  * given Parser::variables parse tree. In the base case, DefineVars, the caller
    2769                 :  * only wants variables to be defined in the prologue (if necessary). For
    2770                 :  * PushInitialValues, variable initializer expressions are evaluated and left
    2771                 :  * on the stack. For InitializeVars, the initializer expressions values are
    2772                 :  * assigned (to local variables) and popped.
    2773                 :  */
    2774                 : enum VarEmitOption
    2775                 : {
    2776                 :     DefineVars        = 0,
    2777                 :     PushInitialValues = 1,
    2778                 :     InitializeVars    = 2
    2779                 : };
    2780                 : 
    2781                 : #if JS_HAS_DESTRUCTURING
    2782                 : 
    2783                 : typedef JSBool
    2784                 : (*DestructuringDeclEmitter)(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn);
    2785                 : 
    2786                 : static JSBool
    2787            1773 : EmitDestructuringDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
    2788                 : {
    2789            1773 :     JS_ASSERT(pn->isKind(PNK_NAME));
    2790            1773 :     if (!BindNameToSlot(cx, bce, pn))
    2791               0 :         return JS_FALSE;
    2792                 : 
    2793            1773 :     JS_ASSERT(!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE));
    2794            1773 :     return MaybeEmitVarDecl(cx, bce, prologOp, pn, NULL);
    2795                 : }
    2796                 : 
    2797                 : static JSBool
    2798            8118 : EmitDestructuringDecls(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
    2799                 : {
    2800                 :     ParseNode *pn2, *pn3;
    2801                 :     DestructuringDeclEmitter emitter;
    2802                 : 
    2803            8118 :     if (pn->isKind(PNK_RB)) {
    2804           11331 :         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    2805            4095 :             if (pn2->isKind(PNK_COMMA))
    2806             684 :                 continue;
    2807            3411 :             emitter = (pn2->isKind(PNK_NAME))
    2808                 :                       ? EmitDestructuringDecl
    2809            3411 :                       : EmitDestructuringDecls;
    2810            3411 :             if (!emitter(cx, bce, prologOp, pn2))
    2811               0 :                 return JS_FALSE;
    2812                 :         }
    2813                 :     } else {
    2814             882 :         JS_ASSERT(pn->isKind(PNK_RC));
    2815            2034 :         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    2816            1152 :             pn3 = pn2->pn_right;
    2817            1152 :             emitter = pn3->isKind(PNK_NAME) ? EmitDestructuringDecl : EmitDestructuringDecls;
    2818            1152 :             if (!emitter(cx, bce, prologOp, pn3))
    2819               0 :                 return JS_FALSE;
    2820                 :         }
    2821                 :     }
    2822            8118 :     return JS_TRUE;
    2823                 : }
    2824                 : 
    2825                 : static JSBool
    2826                 : EmitDestructuringOpsHelper(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn,
    2827                 :                            VarEmitOption emitOption);
    2828                 : 
    2829                 : /*
    2830                 :  * EmitDestructuringLHS assumes the to-be-destructured value has been pushed on
    2831                 :  * the stack and emits code to destructure a single lhs expression (either a
    2832                 :  * name or a compound []/{} expression).
    2833                 :  *
    2834                 :  * If emitOption is InitializeVars, the to-be-destructured value is assigned to
    2835                 :  * locals and ultimately the initial slot is popped (-1 total depth change).
    2836                 :  *
    2837                 :  * If emitOption is PushInitialValues, the to-be-destructured value is replaced
    2838                 :  * with the initial values of the N (where 0 <= N) variables assigned in the
    2839                 :  * lhs expression. (Same post-condition as EmitDestructuringOpsHelper)
    2840                 :  */
    2841                 : static JSBool
    2842            5859 : EmitDestructuringLHS(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption)
    2843                 : {
    2844            5859 :     JS_ASSERT(emitOption != DefineVars);
    2845                 : 
    2846                 :     /*
    2847                 :      * Now emit the lvalue opcode sequence.  If the lvalue is a nested
    2848                 :      * destructuring initialiser-form, call ourselves to handle it, then
    2849                 :      * pop the matched value.  Otherwise emit an lvalue bytecode sequence
    2850                 :      * ending with a JSOP_ENUMELEM or equivalent op.
    2851                 :      */
    2852            5859 :     if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC)) {
    2853            3141 :         if (!EmitDestructuringOpsHelper(cx, bce, pn, emitOption))
    2854               0 :             return JS_FALSE;
    2855            3141 :         if (emitOption == InitializeVars) {
    2856                 :             /*
    2857                 :              * Per its post-condition, EmitDestructuringOpsHelper has left the
    2858                 :              * to-be-destructured value on top of the stack.
    2859                 :              */
    2860            1593 :             if (Emit1(cx, bce, JSOP_POP) < 0)
    2861               0 :                 return JS_FALSE;
    2862                 :         }
    2863                 :     } else {
    2864            2718 :         if (emitOption == PushInitialValues) {
    2865                 :             /*
    2866                 :              * The lhs is a simple name so the to-be-destructured value is
    2867                 :              * its initial value and there is nothing to do.
    2868                 :              */
    2869            1008 :             JS_ASSERT(pn->getOp() == JSOP_SETLOCAL);
    2870            1008 :             JS_ASSERT(pn->pn_dflags & PND_BOUND);
    2871            1008 :             return JS_TRUE;
    2872                 :         }
    2873                 : 
    2874                 :         /* All paths below must pop after assigning to the lhs. */
    2875                 : 
    2876            1710 :         if (pn->isKind(PNK_NAME)) {
    2877            1692 :             if (!BindNameToSlot(cx, bce, pn))
    2878               0 :                 return JS_FALSE;
    2879            1692 :             if (pn->isConst() && !pn->isInitialized())
    2880               0 :                 return Emit1(cx, bce, JSOP_POP) >= 0;
    2881                 :         }
    2882                 : 
    2883            1710 :         switch (pn->getOp()) {
    2884                 :           case JSOP_SETNAME:
    2885                 :           case JSOP_SETGNAME:
    2886                 :             /*
    2887                 :              * NB: pn is a PN_NAME node, not a PN_BINARY.  Nevertheless,
    2888                 :              * we want to emit JSOP_ENUMELEM, which has format JOF_ELEM.
    2889                 :              * So here and for JSOP_ENUMCONSTELEM, we use EmitElemOp.
    2890                 :              */
    2891             270 :             if (!EmitElemOp(cx, pn, JSOP_ENUMELEM, bce))
    2892               0 :                 return JS_FALSE;
    2893             270 :             break;
    2894                 : 
    2895                 :           case JSOP_SETCONST:
    2896               9 :             if (!EmitElemOp(cx, pn, JSOP_ENUMCONSTELEM, bce))
    2897               0 :                 return JS_FALSE;
    2898               9 :             break;
    2899                 : 
    2900                 :           case JSOP_SETLOCAL:
    2901                 :           {
    2902            1296 :             uint16_t slot = pn->pn_cookie.slot();
    2903            1296 :             EMIT_UINT16_IMM_OP(JSOP_SETLOCAL, slot);
    2904            1296 :             if (Emit1(cx, bce, JSOP_POP) < 0)
    2905               0 :                 return JS_FALSE;
    2906            1296 :             break;
    2907                 :           }
    2908                 : 
    2909                 :           case JSOP_SETARG:
    2910                 :           {
    2911             135 :             uint16_t slot = pn->pn_cookie.slot();
    2912             135 :             EMIT_UINT16_IMM_OP(pn->getOp(), slot);
    2913             135 :             if (Emit1(cx, bce, JSOP_POP) < 0)
    2914               0 :                 return JS_FALSE;
    2915             135 :             break;
    2916                 :           }
    2917                 : 
    2918                 :           default:
    2919                 :           {
    2920                 :             ptrdiff_t top;
    2921                 : 
    2922               0 :             top = bce->offset();
    2923               0 :             if (!EmitTree(cx, bce, pn))
    2924               0 :                 return JS_FALSE;
    2925               0 :             if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - top) < 0)
    2926               0 :                 return JS_FALSE;
    2927               0 :             if (!EmitElemOpBase(cx, bce, JSOP_ENUMELEM))
    2928               0 :                 return JS_FALSE;
    2929               0 :             break;
    2930                 :           }
    2931                 : 
    2932                 :           case JSOP_ENUMELEM:
    2933               0 :             JS_ASSERT(0);
    2934                 :         }
    2935                 :     }
    2936                 : 
    2937            4851 :     return JS_TRUE;
    2938                 : }
    2939                 : 
    2940                 : /*
    2941                 :  * Recursive helper for EmitDestructuringOps.
    2942                 :  * EmitDestructuringOpsHelper assumes the to-be-destructured value has been
    2943                 :  * pushed on the stack and emits code to destructure each part of a [] or {}
    2944                 :  * lhs expression.
    2945                 :  *
    2946                 :  * If emitOption is InitializeVars, the initial to-be-destructured value is
    2947                 :  * left untouched on the stack and the overall depth is not changed.
    2948                 :  *
    2949                 :  * If emitOption is PushInitialValues, the to-be-destructured value is replaced
    2950                 :  * with the initial values of the N (where 0 <= N) variables assigned in the
    2951                 :  * lhs expression. (Same post-condition as EmitDestructuringLHS)
    2952                 :  */
    2953                 : static JSBool
    2954            8721 : EmitDestructuringOpsHelper(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn,
    2955                 :                            VarEmitOption emitOption)
    2956                 : {
    2957            8721 :     JS_ASSERT(emitOption != DefineVars);
    2958                 : 
    2959                 :     unsigned index;
    2960                 :     ParseNode *pn2, *pn3;
    2961                 :     JSBool doElemOp;
    2962                 : 
    2963                 : #ifdef DEBUG
    2964            8721 :     int stackDepth = bce->stackDepth;
    2965            8721 :     JS_ASSERT(stackDepth != 0);
    2966            8721 :     JS_ASSERT(pn->isArity(PN_LIST));
    2967            8721 :     JS_ASSERT(pn->isKind(PNK_RB) || pn->isKind(PNK_RC));
    2968                 : #endif
    2969                 : 
    2970            8721 :     if (pn->pn_count == 0) {
    2971                 :         /* Emit a DUP;POP sequence for the decompiler. */
    2972            4518 :         if (Emit1(cx, bce, JSOP_DUP) < 0 || Emit1(cx, bce, JSOP_POP) < 0)
    2973               0 :             return JS_FALSE;
    2974                 :     }
    2975                 : 
    2976            8721 :     index = 0;
    2977           14643 :     for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    2978                 :         /*
    2979                 :          * Duplicate the value being destructured to use as a reference base.
    2980                 :          * If dup is not the first one, annotate it for the decompiler.
    2981                 :          */
    2982            5922 :         if (pn2 != pn->pn_head && NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
    2983               0 :             return JS_FALSE;
    2984            5922 :         if (Emit1(cx, bce, JSOP_DUP) < 0)
    2985               0 :             return JS_FALSE;
    2986                 : 
    2987                 :         /*
    2988                 :          * Now push the property name currently being matched, which is either
    2989                 :          * the array initialiser's current index, or the current property name
    2990                 :          * "label" on the left of a colon in the object initialiser.  Set pn3
    2991                 :          * to the lvalue node, which is in the value-initializing position.
    2992                 :          */
    2993            5922 :         doElemOp = JS_TRUE;
    2994            5922 :         if (pn->isKind(PNK_RB)) {
    2995            4599 :             if (!EmitNumberOp(cx, index, bce))
    2996               0 :                 return JS_FALSE;
    2997            4599 :             pn3 = pn2;
    2998                 :         } else {
    2999            1323 :             JS_ASSERT(pn->isKind(PNK_RC));
    3000            1323 :             JS_ASSERT(pn2->isKind(PNK_COLON));
    3001            1323 :             pn3 = pn2->pn_left;
    3002            1323 :             if (pn3->isKind(PNK_NUMBER)) {
    3003                 :                 /*
    3004                 :                  * If we are emitting an object destructuring initialiser,
    3005                 :                  * annotate the index op with SRC_INITPROP so we know we are
    3006                 :                  * not decompiling an array initialiser.
    3007                 :                  */
    3008             108 :                 if (NewSrcNote(cx, bce, SRC_INITPROP) < 0)
    3009               0 :                     return JS_FALSE;
    3010             108 :                 if (!EmitNumberOp(cx, pn3->pn_dval, bce))
    3011               0 :                     return JS_FALSE;
    3012                 :             } else {
    3013            1215 :                 JS_ASSERT(pn3->isKind(PNK_STRING) || pn3->isKind(PNK_NAME));
    3014            1215 :                 if (!EmitAtomOp(cx, pn3, JSOP_GETPROP, bce))
    3015               0 :                     return JS_FALSE;
    3016            1215 :                 doElemOp = JS_FALSE;
    3017                 :             }
    3018            1323 :             pn3 = pn2->pn_right;
    3019                 :         }
    3020                 : 
    3021            5922 :         if (doElemOp) {
    3022                 :             /*
    3023                 :              * Ok, get the value of the matching property name.  This leaves
    3024                 :              * that value on top of the value being destructured, so the stack
    3025                 :              * is one deeper than when we started.
    3026                 :              */
    3027            4707 :             if (!EmitElemOpBase(cx, bce, JSOP_GETELEM))
    3028               0 :                 return JS_FALSE;
    3029            4707 :             JS_ASSERT(bce->stackDepth >= stackDepth + 1);
    3030                 :         }
    3031                 : 
    3032                 :         /* Nullary comma node makes a hole in the array destructurer. */
    3033            5922 :         if (pn3->isKind(PNK_COMMA) && pn3->isArity(PN_NULLARY)) {
    3034             693 :             JS_ASSERT(pn->isKind(PNK_RB));
    3035             693 :             JS_ASSERT(pn2 == pn3);
    3036             693 :             if (Emit1(cx, bce, JSOP_POP) < 0)
    3037               0 :                 return JS_FALSE;
    3038                 :         } else {
    3039            5229 :             int depthBefore = bce->stackDepth;
    3040            5229 :             if (!EmitDestructuringLHS(cx, bce, pn3, emitOption))
    3041               0 :                 return JS_FALSE;
    3042                 : 
    3043            5229 :             if (emitOption == PushInitialValues) {
    3044                 :                 /*
    3045                 :                  * After '[x,y]' in 'let ([[x,y], z] = o)', the stack is
    3046                 :                  *   | to-be-decompiled-value | x | y |
    3047                 :                  * The goal is:
    3048                 :                  *   | x | y | z |
    3049                 :                  * so emit a pick to produce the intermediate state
    3050                 :                  *   | x | y | to-be-decompiled-value |
    3051                 :                  * before destructuring z. This gives the loop invariant that
    3052                 :                  * the to-be-compiled-value is always on top of the stack.
    3053                 :                  */
    3054                 :                 JS_ASSERT((bce->stackDepth - bce->stackDepth) >= -1);
    3055            2556 :                 unsigned pickDistance = (unsigned)((bce->stackDepth + 1) - depthBefore);
    3056            2556 :                 if (pickDistance > 0) {
    3057            1386 :                     if (pickDistance > UINT8_MAX) {
    3058                 :                         ReportCompileErrorNumber(cx, bce->tokenStream(), pn3, JSREPORT_ERROR,
    3059               0 :                                                  JSMSG_TOO_MANY_LOCALS);
    3060               0 :                         return JS_FALSE;
    3061                 :                     }
    3062            1386 :                     if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)pickDistance) < 0)
    3063               0 :                         return false;
    3064                 :                 }
    3065                 :             }
    3066                 :         }
    3067                 : 
    3068            5922 :         ++index;
    3069                 :     }
    3070                 : 
    3071            8721 :     if (emitOption == PushInitialValues) {
    3072                 :         /*
    3073                 :          * Per the above loop invariant, to-be-decompiled-value is at the top
    3074                 :          * of the stack. To achieve the post-condition, pop it.
    3075                 :          */
    3076            5814 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    3077               0 :             return JS_FALSE;
    3078                 :     }
    3079                 : 
    3080            8721 :     return JS_TRUE;
    3081                 : }
    3082                 : 
    3083                 : static ptrdiff_t
    3084            2151 : OpToDeclType(JSOp op)
    3085                 : {
    3086            2151 :     switch (op) {
    3087                 :       case JSOP_NOP:
    3088            1548 :         return SRC_DECL_LET;
    3089                 :       case JSOP_DEFCONST:
    3090               9 :         return SRC_DECL_CONST;
    3091                 :       case JSOP_DEFVAR:
    3092             585 :         return SRC_DECL_VAR;
    3093                 :       default:
    3094               9 :         return SRC_DECL_NONE;
    3095                 :     }
    3096                 : }
    3097                 : 
    3098                 : /*
    3099                 :  * This utility accumulates a set of SRC_DESTRUCTLET notes which need to be
    3100                 :  * backpatched with the offset from JSOP_DUP to JSOP_LET0.
    3101                 :  *
    3102                 :  * Also record whether the let head was a group assignment ([x,y] = [a,b])
    3103                 :  * (which implies no SRC_DESTRUCTLET notes).
    3104                 :  */
    3105                 : class LetNotes
    3106                 : {
    3107            9009 :     struct Pair {
    3108                 :         ptrdiff_t dup;
    3109                 :         unsigned index;
    3110            4266 :         Pair(ptrdiff_t dup, unsigned index) : dup(dup), index(index) {}
    3111                 :     };
    3112                 :     Vector<Pair> notes;
    3113                 :     bool groupAssign;
    3114                 :     DebugOnly<bool> updateCalled;
    3115                 : 
    3116                 :   public:
    3117            8416 :     LetNotes(JSContext *cx) : notes(cx), groupAssign(false), updateCalled(false) {}
    3118                 : 
    3119           16832 :     ~LetNotes() {
    3120            8416 :         JS_ASSERT_IF(!notes.allocPolicy().context()->isExceptionPending(), updateCalled);
    3121            8416 :     }
    3122                 : 
    3123             180 :     void setGroupAssign() {
    3124             180 :         JS_ASSERT(notes.empty());
    3125             180 :         groupAssign = true;
    3126             180 :     }
    3127                 : 
    3128            8416 :     bool isGroupAssign() const {
    3129            8416 :         return groupAssign;
    3130                 :     }
    3131                 : 
    3132            4266 :     bool append(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t dup, unsigned index) {
    3133            4266 :         JS_ASSERT(!groupAssign);
    3134            4266 :         JS_ASSERT(SN_TYPE(bce->notes() + index) == SRC_DESTRUCTLET);
    3135            4266 :         if (!notes.append(Pair(dup, index)))
    3136               0 :             return false;
    3137                 : 
    3138                 :         /*
    3139                 :          * Pessimistically inflate each srcnote. That way, there is no danger
    3140                 :          * of inflation during update() (which would invalidate all indices).
    3141                 :          */
    3142            4266 :         if (!SetSrcNoteOffset(cx, bce, index, 0, SN_MAX_OFFSET))
    3143               0 :             return false;
    3144            4266 :         JS_ASSERT(bce->notes()[index + 1] & SN_3BYTE_OFFSET_FLAG);
    3145            4266 :         return true;
    3146                 :     }
    3147                 : 
    3148                 :     /* This should be called exactly once, right before JSOP_ENTERLET0. */
    3149            8416 :     bool update(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t offset) {
    3150            8416 :         JS_ASSERT(!updateCalled);
    3151           12682 :         for (size_t i = 0; i < notes.length(); ++i) {
    3152            4266 :             JS_ASSERT(offset > notes[i].dup);
    3153            4266 :             JS_ASSERT(*bce->code(notes[i].dup) == JSOP_DUP);
    3154            4266 :             JS_ASSERT(bce->notes()[notes[i].index + 1] & SN_3BYTE_OFFSET_FLAG);
    3155            4266 :             if (!SetSrcNoteOffset(cx, bce, notes[i].index, 0, offset - notes[i].dup))
    3156               0 :                 return false;
    3157                 :         }
    3158            8416 :         updateCalled = true;
    3159            8416 :         return true;
    3160                 :     }
    3161                 : };
    3162                 : 
    3163                 : static JSBool
    3164            5580 : EmitDestructuringOps(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t declType, ParseNode *pn,
    3165                 :                      LetNotes *letNotes = NULL)
    3166                 : {
    3167                 :     /*
    3168                 :      * If we're called from a variable declaration, help the decompiler by
    3169                 :      * annotating the first JSOP_DUP that EmitDestructuringOpsHelper emits.
    3170                 :      * If the destructuring initialiser is empty, our helper will emit a
    3171                 :      * JSOP_DUP followed by a JSOP_POP for the decompiler.
    3172                 :      */
    3173            5580 :     if (letNotes) {
    3174            4266 :         ptrdiff_t index = NewSrcNote2(cx, bce, SRC_DESTRUCTLET, 0);
    3175            4266 :         if (index < 0 || !letNotes->append(cx, bce, bce->offset(), (unsigned)index))
    3176               0 :             return JS_FALSE;
    3177                 :     } else {
    3178            1314 :         if (NewSrcNote2(cx, bce, SRC_DESTRUCT, declType) < 0)
    3179               0 :             return JS_FALSE;
    3180                 :     }
    3181                 : 
    3182                 :     /*
    3183                 :      * Call our recursive helper to emit the destructuring assignments and
    3184                 :      * related stack manipulations.
    3185                 :      */
    3186            5580 :     VarEmitOption emitOption = letNotes ? PushInitialValues : InitializeVars;
    3187            5580 :     return EmitDestructuringOpsHelper(cx, bce, pn, emitOption);
    3188                 : }
    3189                 : 
    3190                 : static JSBool
    3191             360 : EmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp,
    3192                 :                     ParseNode *lhs, ParseNode *rhs)
    3193                 : {
    3194                 :     unsigned depth, limit, i, nslots;
    3195                 :     ParseNode *pn;
    3196                 : 
    3197             360 :     depth = limit = (unsigned) bce->stackDepth;
    3198             990 :     for (pn = rhs->pn_head; pn; pn = pn->pn_next) {
    3199             630 :         if (limit == JS_BIT(16)) {
    3200                 :             ReportCompileErrorNumber(cx, bce->tokenStream(), rhs, JSREPORT_ERROR,
    3201               0 :                                      JSMSG_ARRAY_INIT_TOO_BIG);
    3202               0 :             return JS_FALSE;
    3203                 :         }
    3204                 : 
    3205                 :         /* MaybeEmitGroupAssignment won't call us if rhs is holey. */
    3206             630 :         JS_ASSERT(!(pn->isKind(PNK_COMMA) && pn->isArity(PN_NULLARY)));
    3207             630 :         if (!EmitTree(cx, bce, pn))
    3208               0 :             return JS_FALSE;
    3209             630 :         ++limit;
    3210                 :     }
    3211                 : 
    3212             360 :     if (NewSrcNote2(cx, bce, SRC_GROUPASSIGN, OpToDeclType(prologOp)) < 0)
    3213               0 :         return JS_FALSE;
    3214                 : 
    3215             360 :     i = depth;
    3216             990 :     for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) {
    3217                 :         /* MaybeEmitGroupAssignment requires lhs->pn_count <= rhs->pn_count. */
    3218             630 :         JS_ASSERT(i < limit);
    3219             630 :         int slot = AdjustBlockSlot(cx, bce, i);
    3220             630 :         if (slot < 0)
    3221               0 :             return JS_FALSE;
    3222             630 :         EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot);
    3223                 : 
    3224             630 :         if (pn->isKind(PNK_COMMA) && pn->isArity(PN_NULLARY)) {
    3225               0 :             if (Emit1(cx, bce, JSOP_POP) < 0)
    3226               0 :                 return JS_FALSE;
    3227                 :         } else {
    3228             630 :             if (!EmitDestructuringLHS(cx, bce, pn, InitializeVars))
    3229               0 :                 return JS_FALSE;
    3230                 :         }
    3231                 :     }
    3232                 : 
    3233             360 :     nslots = limit - depth;
    3234             360 :     EMIT_UINT16_IMM_OP(JSOP_POPN, nslots);
    3235             360 :     bce->stackDepth = (unsigned) depth;
    3236             360 :     return JS_TRUE;
    3237                 : }
    3238                 : 
    3239                 : /*
    3240                 :  * Helper called with pop out param initialized to a JSOP_POP* opcode.  If we
    3241                 :  * can emit a group assignment sequence, which results in 0 stack depth delta,
    3242                 :  * we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop.
    3243                 :  */
    3244                 : static JSBool
    3245          368948 : MaybeEmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn,
    3246                 :                          JSOp *pop)
    3247                 : {
    3248          368948 :     JS_ASSERT(pn->isKind(PNK_ASSIGN));
    3249          368948 :     JS_ASSERT(pn->isOp(JSOP_NOP));
    3250          368948 :     JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV);
    3251                 : 
    3252          368948 :     ParseNode *lhs = pn->pn_left;
    3253          368948 :     ParseNode *rhs = pn->pn_right;
    3254          369308 :     if (lhs->isKind(PNK_RB) && rhs->isKind(PNK_RB) &&
    3255             360 :         !(rhs->pn_xflags & PNX_HOLEY) &&
    3256                 :         lhs->pn_count <= rhs->pn_count) {
    3257             360 :         if (!EmitGroupAssignment(cx, bce, prologOp, lhs, rhs))
    3258               0 :             return JS_FALSE;
    3259             360 :         *pop = JSOP_NOP;
    3260                 :     }
    3261          368948 :     return JS_TRUE;
    3262                 : }
    3263                 : 
    3264                 : /*
    3265                 :  * Like MaybeEmitGroupAssignment, but for 'let ([x,y] = [a,b]) ...'.
    3266                 :  *
    3267                 :  * Instead of issuing a sequence |dup|eval-rhs|set-lhs|pop| (which doesn't work
    3268                 :  * since the bound vars don't yet have slots), just eval/push each rhs element
    3269                 :  * just like what EmitLet would do for 'let (x = a, y = b) ...'. While shorter,
    3270                 :  * simpler and more efficient than MaybeEmitGroupAssignment, it is harder to
    3271                 :  * decompile so we restrict the ourselves to cases where the lhs and rhs are in
    3272                 :  * 1:1 correspondence and lhs elements are simple names.
    3273                 :  */
    3274                 : static bool
    3275            1134 : MaybeEmitLetGroupDecl(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn,
    3276                 :                       LetNotes *letNotes, JSOp *pop)
    3277                 : {
    3278            1134 :     JS_ASSERT(pn->isKind(PNK_ASSIGN));
    3279            1134 :     JS_ASSERT(pn->isOp(JSOP_NOP));
    3280            1134 :     JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV);
    3281                 : 
    3282            1134 :     ParseNode *lhs = pn->pn_left;
    3283            1134 :     ParseNode *rhs = pn->pn_right;
    3284            1890 :     if (lhs->isKind(PNK_RB) && rhs->isKind(PNK_RB) &&
    3285             378 :         !(rhs->pn_xflags & PNX_HOLEY) &&
    3286             378 :         !(lhs->pn_xflags & PNX_HOLEY) &&
    3287                 :         lhs->pn_count == rhs->pn_count)
    3288                 :     {
    3289             666 :         for (ParseNode *l = lhs->pn_head; l; l = l->pn_next) {
    3290             486 :             if (l->getOp() != JSOP_SETLOCAL)
    3291             162 :                 return true;
    3292                 :         }
    3293                 : 
    3294             468 :         for (ParseNode *r = rhs->pn_head; r; r = r->pn_next) {
    3295             288 :             if (!EmitTree(cx, bce, r))
    3296               0 :                 return false;
    3297                 :         }
    3298                 : 
    3299             180 :         letNotes->setGroupAssign();
    3300             180 :         *pop = JSOP_NOP;
    3301                 :     }
    3302             972 :     return true;
    3303                 : }
    3304                 : 
    3305                 : #endif /* JS_HAS_DESTRUCTURING */
    3306                 : 
    3307                 : static JSBool
    3308          161306 : EmitVariables(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption,
    3309                 :               LetNotes *letNotes = NULL)
    3310                 : {
    3311          161306 :     JS_ASSERT(pn->isArity(PN_LIST));
    3312          161306 :     JS_ASSERT(!!letNotes == (emitOption == PushInitialValues));
    3313                 : 
    3314          161306 :     ptrdiff_t off = -1, noteIndex = -1;
    3315                 :     ParseNode *next;
    3316          465160 :     for (ParseNode *pn2 = pn->pn_head; ; pn2 = next) {
    3317          465160 :         bool first = pn2 == pn->pn_head;
    3318          465160 :         next = pn2->pn_next;
    3319                 : 
    3320                 :         ParseNode *pn3;
    3321          465160 :         if (!pn2->isKind(PNK_NAME)) {
    3322                 : #if JS_HAS_DESTRUCTURING
    3323            8406 :             if (pn2->isKind(PNK_RB) || pn2->isKind(PNK_RC)) {
    3324                 :                 /*
    3325                 :                  * Emit variable binding ops, but not destructuring ops.  The
    3326                 :                  * parser (see Parser::variables) has ensured that our caller
    3327                 :                  * will be the PNK_FOR/PNK_FORIN case in EmitTree, and that
    3328                 :                  * case will emit the destructuring code only after emitting an
    3329                 :                  * enumerating opcode and a branch that tests whether the
    3330                 :                  * enumeration ended.
    3331                 :                  */
    3332             117 :                 JS_ASSERT(emitOption == DefineVars);
    3333             117 :                 JS_ASSERT(pn->pn_count == 1);
    3334             117 :                 if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn2))
    3335               0 :                     return JS_FALSE;
    3336             117 :                 break;
    3337                 :             }
    3338                 : #endif
    3339                 : 
    3340                 :             /*
    3341                 :              * A destructuring initialiser assignment preceded by var will
    3342                 :              * never occur to the left of 'in' in a for-in loop.  As with 'for
    3343                 :              * (var x = i in o)...', this will cause the entire 'var [a, b] =
    3344                 :              * i' to be hoisted out of the loop.
    3345                 :              */
    3346            8289 :             JS_ASSERT(pn2->isKind(PNK_ASSIGN));
    3347            8289 :             JS_ASSERT(pn2->isOp(JSOP_NOP));
    3348            8289 :             JS_ASSERT(emitOption != DefineVars);
    3349                 : 
    3350                 :             /*
    3351                 :              * To allow the front end to rewrite var f = x; as f = x; when a
    3352                 :              * function f(){} precedes the var, detect simple name assignment
    3353                 :              * here and initialize the name.
    3354                 :              */
    3355                 : #if !JS_HAS_DESTRUCTURING
    3356                 :             JS_ASSERT(pn2->pn_left->isKind(PNK_NAME));
    3357                 : #else
    3358            8289 :             if (pn2->pn_left->isKind(PNK_NAME))
    3359                 : #endif
    3360                 :             {
    3361            2547 :                 pn3 = pn2->pn_right;
    3362            2547 :                 pn2 = pn2->pn_left;
    3363            2547 :                 goto do_name;
    3364                 :             }
    3365                 : 
    3366                 : #if JS_HAS_DESTRUCTURING
    3367            5742 :             ptrdiff_t stackDepthBefore = bce->stackDepth;
    3368            5742 :             JSOp op = JSOP_POP;
    3369            5742 :             if (pn->pn_count == 1) {
    3370                 :                 /*
    3371                 :                  * If this is the only destructuring assignment in the list,
    3372                 :                  * try to optimize to a group assignment.  If we're in a let
    3373                 :                  * head, pass JSOP_POP rather than the pseudo-prolog JSOP_NOP
    3374                 :                  * in pn->pn_op, to suppress a second (and misplaced) 'let'.
    3375                 :                  */
    3376            2070 :                 JS_ASSERT(noteIndex < 0 && !pn2->pn_next);
    3377            2070 :                 if (letNotes) {
    3378            1134 :                     if (!MaybeEmitLetGroupDecl(cx, bce, pn2, letNotes, &op))
    3379               0 :                         return JS_FALSE;
    3380                 :                 } else {
    3381             936 :                     if (!MaybeEmitGroupAssignment(cx, bce, pn->getOp(), pn2, &op))
    3382               0 :                         return JS_FALSE;
    3383                 :                 }
    3384                 :             }
    3385            5742 :             if (op == JSOP_NOP) {
    3386             531 :                 pn->pn_xflags = (pn->pn_xflags & ~PNX_POPVAR) | PNX_GROUPINIT;
    3387                 :             } else {
    3388            5211 :                 pn3 = pn2->pn_left;
    3389            5211 :                 if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn3))
    3390               0 :                     return JS_FALSE;
    3391                 : 
    3392            5211 :                 if (!EmitTree(cx, bce, pn2->pn_right))
    3393               0 :                     return JS_FALSE;
    3394                 : 
    3395                 :                 /* Only the first list element should print 'let' or 'var'. */
    3396                 :                 ptrdiff_t declType = pn2 == pn->pn_head
    3397            1791 :                                      ? OpToDeclType(pn->getOp())
    3398            7002 :                                      : SRC_DECL_NONE;
    3399                 : 
    3400            5211 :                 if (!EmitDestructuringOps(cx, bce, declType, pn3, letNotes))
    3401               0 :                     return JS_FALSE;
    3402                 :             }
    3403            5742 :             ptrdiff_t stackDepthAfter = bce->stackDepth;
    3404                 : 
    3405                 :             /* Give let ([] = x) a slot (see CheckDestructuring). */
    3406            5742 :             JS_ASSERT(stackDepthBefore <= stackDepthAfter);
    3407            5742 :             if (letNotes && stackDepthBefore == stackDepthAfter) {
    3408            3690 :                 if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    3409               0 :                     return JS_FALSE;
    3410                 :             }
    3411                 : 
    3412                 :             /* If we are not initializing, nothing to pop. */
    3413            5742 :             if (emitOption != InitializeVars) {
    3414            4446 :                 if (next)
    3415            3159 :                     continue;
    3416            1287 :                 break;
    3417                 :             }
    3418            1296 :             goto emit_note_pop;
    3419                 : #endif
    3420                 :         }
    3421                 : 
    3422                 :         /*
    3423                 :          * Load initializer early to share code above that jumps to do_name.
    3424                 :          * NB: if this var redeclares an existing binding, then pn2 is linked
    3425                 :          * on its definition's use-chain and pn_expr has been overlayed with
    3426                 :          * pn_lexdef.
    3427                 :          */
    3428          456754 :         pn3 = pn2->maybeExpr();
    3429                 : 
    3430                 :      do_name:
    3431          459301 :         if (!BindNameToSlot(cx, bce, pn2))
    3432               0 :             return JS_FALSE;
    3433                 : 
    3434                 :         JSOp op;
    3435                 :         jsatomid atomIndex;
    3436                 : 
    3437          459301 :         op = pn2->getOp();
    3438          459301 :         if (op == JSOP_ARGUMENTS) {
    3439                 :             /* JSOP_ARGUMENTS => no initializer */
    3440               0 :             JS_ASSERT(!pn3 && !letNotes);
    3441               0 :             pn3 = NULL;
    3442               0 :             atomIndex = 0;
    3443                 :         } else {
    3444          459301 :             JS_ASSERT(op != JSOP_CALLEE);
    3445          459301 :             JS_ASSERT(!pn2->pn_cookie.isFree() || !pn->isOp(JSOP_NOP));
    3446          459301 :             if (!MaybeEmitVarDecl(cx, bce, pn->getOp(), pn2, &atomIndex))
    3447               0 :                 return JS_FALSE;
    3448                 : 
    3449          459301 :             if (pn3) {
    3450          148949 :                 JS_ASSERT(emitOption != DefineVars);
    3451          148949 :                 JS_ASSERT_IF(emitOption == PushInitialValues, op == JSOP_SETLOCAL);
    3452          148949 :                 if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
    3453           44844 :                     JSOp bindOp = (op == JSOP_SETNAME) ? JSOP_BINDNAME : JSOP_BINDGNAME;
    3454           44844 :                     if (!EmitIndex32(cx, bindOp, atomIndex, bce))
    3455               0 :                         return false;
    3456                 :                 }
    3457          205127 :                 if (pn->isOp(JSOP_DEFCONST) &&
    3458           56178 :                     !DefineCompileTimeConstant(cx, bce, pn2->pn_atom, pn3))
    3459                 :                 {
    3460               0 :                     return JS_FALSE;
    3461                 :                 }
    3462                 : 
    3463          148949 :                 unsigned oldflags = bce->flags;
    3464          148949 :                 bce->flags &= ~TCF_IN_FOR_INIT;
    3465          148949 :                 if (!EmitTree(cx, bce, pn3))
    3466               0 :                     return JS_FALSE;
    3467          148949 :                 bce->flags |= oldflags & TCF_IN_FOR_INIT;
    3468          310352 :             } else if (letNotes) {
    3469                 :                 /* JSOP_ENTERLETx expects at least 1 slot to have been pushed. */
    3470          147753 :                 if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    3471               0 :                     return JS_FALSE;
    3472                 :             }
    3473                 :         }
    3474                 : 
    3475                 :         /* If we are not initializing, nothing to pop. */
    3476          459301 :         if (emitOption != InitializeVars) {
    3477          158007 :             if (next)
    3478          147754 :                 continue;
    3479           10253 :             break;
    3480                 :         }
    3481                 : 
    3482          301294 :         JS_ASSERT_IF(pn2->isDefn(), pn3 == pn2->pn_expr);
    3483          449872 :         if (first && NewSrcNote2(cx, bce, SRC_DECL,
    3484          148578 :                                  (pn->isOp(JSOP_DEFCONST))
    3485                 :                                  ? SRC_DECL_CONST
    3486           92400 :                                  : (pn->isOp(JSOP_DEFVAR))
    3487                 :                                  ? SRC_DECL_VAR
    3488          240978 :                                  : SRC_DECL_LET) < 0) {
    3489               0 :             return JS_FALSE;
    3490                 :         }
    3491          301294 :         if (op == JSOP_ARGUMENTS) {
    3492               0 :             if (!EmitArguments(cx, bce))
    3493               0 :                 return JS_FALSE;
    3494          301294 :         } else if (!pn2->pn_cookie.isFree()) {
    3495          196516 :             EMIT_UINT16_IMM_OP(op, atomIndex);
    3496                 :         } else {
    3497          104778 :             if (!EmitIndexOp(cx, op, atomIndex, bce))
    3498               0 :                 return false;
    3499                 :         }
    3500                 : 
    3501                 : #if JS_HAS_DESTRUCTURING
    3502                 :     emit_note_pop:
    3503                 : #endif
    3504          302590 :         ptrdiff_t tmp = bce->offset();
    3505          302590 :         if (noteIndex >= 0) {
    3506          152941 :             if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, tmp-off))
    3507               0 :                 return JS_FALSE;
    3508                 :         }
    3509          302590 :         if (!next)
    3510          149649 :             break;
    3511          152941 :         off = tmp;
    3512          152941 :         noteIndex = NewSrcNote2(cx, bce, SRC_PCDELTA, 0);
    3513          152941 :         if (noteIndex < 0 || Emit1(cx, bce, JSOP_POP) < 0)
    3514               0 :             return JS_FALSE;
    3515                 :     }
    3516                 : 
    3517          161306 :     if (pn->pn_xflags & PNX_POPVAR) {
    3518          131989 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    3519               0 :             return JS_FALSE;
    3520                 :     }
    3521                 : 
    3522          161306 :     return JS_TRUE;
    3523                 : }
    3524                 : 
    3525                 : static bool
    3526          406347 : EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, ParseNode *rhs)
    3527                 : {
    3528          406347 :     ptrdiff_t top = bce->offset();
    3529                 : 
    3530                 :     /*
    3531                 :      * Check left operand type and generate specialized code for it.
    3532                 :      * Specialize to avoid ECMA "reference type" values on the operand
    3533                 :      * stack, which impose pervasive runtime "GetValue" costs.
    3534                 :      */
    3535          406347 :     jsatomid atomIndex = (jsatomid) -1;              /* quell GCC overwarning */
    3536          406347 :     jsbytecode offset = 1;
    3537                 : 
    3538          406347 :     switch (lhs->getKind()) {
    3539                 :       case PNK_NAME:
    3540          375616 :         if (!BindNameToSlot(cx, bce, lhs))
    3541               0 :             return false;
    3542          375616 :         if (!lhs->pn_cookie.isFree()) {
    3543          260022 :             JS_ASSERT(lhs->pn_cookie.level() == 0);
    3544          260022 :             atomIndex = lhs->pn_cookie.slot();
    3545                 :         } else {
    3546          115594 :             if (!bce->makeAtomIndex(lhs->pn_atom, &atomIndex))
    3547               0 :                 return false;
    3548          115594 :             if (!lhs->isConst()) {
    3549          115594 :                 JSOp op = lhs->isOp(JSOP_SETGNAME) ? JSOP_BINDGNAME : JSOP_BINDNAME;
    3550          115594 :                 if (!EmitIndex32(cx, op, atomIndex, bce))
    3551               0 :                     return false;
    3552          115594 :                 offset++;
    3553                 :             }
    3554                 :         }
    3555          375616 :         break;
    3556                 :       case PNK_DOT:
    3557           18188 :         if (!EmitTree(cx, bce, lhs->expr()))
    3558               0 :             return false;
    3559           18188 :         offset++;
    3560           18188 :         if (!bce->makeAtomIndex(lhs->pn_atom, &atomIndex))
    3561               0 :             return false;
    3562           18188 :         break;
    3563                 :       case PNK_LB:
    3564           12138 :         JS_ASSERT(lhs->isArity(PN_BINARY));
    3565           12138 :         if (!EmitTree(cx, bce, lhs->pn_left))
    3566               0 :             return false;
    3567           12138 :         if (!EmitTree(cx, bce, lhs->pn_right))
    3568               0 :             return false;
    3569           12138 :         offset += 2;
    3570           12138 :         break;
    3571                 : #if JS_HAS_DESTRUCTURING
    3572                 :       case PNK_RB:
    3573                 :       case PNK_RC:
    3574             369 :         break;
    3575                 : #endif
    3576                 :       case PNK_LP:
    3577              18 :         if (!EmitTree(cx, bce, lhs))
    3578               0 :             return false;
    3579              18 :         offset++;
    3580              18 :         break;
    3581                 : #if JS_HAS_XML_SUPPORT
    3582                 :       case PNK_XMLUNARY:
    3583              18 :         JS_ASSERT(!bce->inStrictMode());
    3584              18 :         JS_ASSERT(lhs->isOp(JSOP_SETXMLNAME));
    3585              18 :         if (!EmitTree(cx, bce, lhs->pn_kid))
    3586               0 :             return false;
    3587              18 :         if (Emit1(cx, bce, JSOP_BINDXMLNAME) < 0)
    3588               0 :             return false;
    3589              18 :         offset++;
    3590              18 :         break;
    3591                 : #endif
    3592                 :       default:
    3593               0 :         JS_ASSERT(0);
    3594                 :     }
    3595                 : 
    3596          406347 :     if (op != JSOP_NOP) {
    3597           28310 :         JS_ASSERT(rhs);
    3598           28310 :         switch (lhs->getKind()) {
    3599                 :           case PNK_NAME:
    3600           27284 :             if (lhs->isConst()) {
    3601               0 :                 if (lhs->isOp(JSOP_CALLEE)) {
    3602               0 :                     if (Emit1(cx, bce, JSOP_CALLEE) < 0)
    3603               0 :                         return false;
    3604               0 :                 } else if (lhs->isOp(JSOP_NAME) || lhs->isOp(JSOP_GETGNAME)) {
    3605               0 :                     if (!EmitIndex32(cx, lhs->getOp(), atomIndex, bce))
    3606               0 :                         return false;
    3607                 :                 } else {
    3608               0 :                     JS_ASSERT(JOF_OPTYPE(lhs->getOp()) != JOF_ATOM);
    3609               0 :                     EMIT_UINT16_IMM_OP(lhs->getOp(), atomIndex);
    3610                 :                 }
    3611           27284 :             } else if (lhs->isOp(JSOP_SETNAME)) {
    3612             534 :                 if (Emit1(cx, bce, JSOP_DUP) < 0)
    3613               0 :                     return false;
    3614             534 :                 if (!EmitIndex32(cx, JSOP_GETXPROP, atomIndex, bce))
    3615               0 :                     return false;
    3616           26750 :             } else if (lhs->isOp(JSOP_SETGNAME)) {
    3617           22015 :                 if (!BindGlobal(cx, bce, lhs, lhs->pn_atom))
    3618               0 :                     return false;
    3619           22015 :                 if (!EmitAtomOp(cx, lhs, JSOP_GETGNAME, bce))
    3620               0 :                     return false;
    3621                 :             } else {
    3622            4735 :                 EMIT_UINT16_IMM_OP(lhs->isOp(JSOP_SETARG) ? JSOP_GETARG : JSOP_GETLOCAL, atomIndex);
    3623                 :             }
    3624           27284 :             break;
    3625                 :           case PNK_DOT:
    3626             621 :             if (Emit1(cx, bce, JSOP_DUP) < 0)
    3627               0 :                 return false;
    3628             621 :             if (lhs->pn_atom == cx->runtime->atomState.protoAtom) {
    3629               0 :                 if (!EmitIndex32(cx, JSOP_QNAMEPART, atomIndex, bce))
    3630               0 :                     return false;
    3631               0 :                 if (!EmitElemOpBase(cx, bce, JSOP_GETELEM))
    3632               0 :                     return false;
    3633                 :             } else {
    3634             621 :                 bool isLength = (lhs->pn_atom == cx->runtime->atomState.lengthAtom);
    3635             621 :                 if (!EmitIndex32(cx, isLength ? JSOP_LENGTH : JSOP_GETPROP, atomIndex, bce))
    3636               0 :                     return false;
    3637                 :             }
    3638             621 :             break;
    3639                 :           case PNK_LB:
    3640                 :           case PNK_LP:
    3641                 : #if JS_HAS_XML_SUPPORT
    3642                 :           case PNK_XMLUNARY:
    3643                 : #endif
    3644             405 :             if (Emit1(cx, bce, JSOP_DUP2) < 0)
    3645               0 :                 return false;
    3646             405 :             if (!EmitElemOpBase(cx, bce, JSOP_GETELEM))
    3647               0 :                 return false;
    3648             405 :             break;
    3649                 :           default:;
    3650                 :         }
    3651                 :     }
    3652                 : 
    3653                 :     /* Now emit the right operand (it may affect the namespace). */
    3654          406347 :     if (rhs) {
    3655          401666 :         if (!EmitTree(cx, bce, rhs))
    3656               0 :             return false;
    3657                 :     } else {
    3658                 :         /* The value to assign is the next enumeration value in a for-in loop. */
    3659            4681 :         if (Emit2(cx, bce, JSOP_ITERNEXT, offset) < 0)
    3660               0 :             return false;
    3661                 :     }
    3662                 : 
    3663                 :     /* If += etc., emit the binary operator with a decompiler note. */
    3664          406347 :     if (op != JSOP_NOP) {
    3665                 :         /*
    3666                 :          * Take care to avoid SRC_ASSIGNOP if the left-hand side is a const
    3667                 :          * declared in the current compilation unit, as in this case (just
    3668                 :          * a bit further below) we will avoid emitting the assignment op.
    3669                 :          */
    3670           28310 :         if (!lhs->isKind(PNK_NAME) || !lhs->isConst()) {
    3671           28310 :             if (NewSrcNote(cx, bce, SRC_ASSIGNOP) < 0)
    3672               0 :                 return false;
    3673                 :         }
    3674           28310 :         if (Emit1(cx, bce, op) < 0)
    3675               0 :             return false;
    3676                 :     }
    3677                 : 
    3678                 :     /* Left parts such as a.b.c and a[b].c need a decompiler note. */
    3679          497874 :     if (!lhs->isKind(PNK_NAME) &&
    3680                 : #if JS_HAS_DESTRUCTURING
    3681           30731 :         !lhs->isKind(PNK_RB) &&
    3682           30434 :         !lhs->isKind(PNK_RC) &&
    3683                 : #endif
    3684           30362 :         NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - top) < 0)
    3685                 :     {
    3686               0 :         return false;
    3687                 :     }
    3688                 : 
    3689                 :     /* Finally, emit the specialized assignment bytecode. */
    3690          406347 :     switch (lhs->getKind()) {
    3691                 :       case PNK_NAME:
    3692          375616 :         if (lhs->isConst()) {
    3693               0 :             if (!rhs) {
    3694                 :                 ReportCompileErrorNumber(cx, bce->tokenStream(), lhs, JSREPORT_ERROR,
    3695               0 :                                          JSMSG_BAD_FOR_LEFTSIDE);
    3696               0 :                 return false;
    3697                 :             }
    3698               0 :             break;
    3699                 :         }
    3700          375616 :         if (lhs->isOp(JSOP_SETARG) || lhs->isOp(JSOP_SETLOCAL)) {
    3701          260022 :             JS_ASSERT(atomIndex < UINT16_MAX);
    3702          260022 :             EMIT_UINT16_IMM_OP(lhs->getOp(), atomIndex);
    3703                 :         } else {
    3704          115594 :             if (!EmitIndexOp(cx, lhs->getOp(), atomIndex, bce))
    3705               0 :                 return false;
    3706                 :         }
    3707          375616 :         break;
    3708                 :       case PNK_DOT:
    3709           18188 :         if (!EmitIndexOp(cx, lhs->getOp(), atomIndex, bce))
    3710               0 :             return false;
    3711           18188 :         break;
    3712                 :       case PNK_LB:
    3713                 :       case PNK_LP:
    3714           12156 :         if (Emit1(cx, bce, JSOP_SETELEM) < 0)
    3715               0 :             return false;
    3716           12156 :         break;
    3717                 : #if JS_HAS_DESTRUCTURING
    3718                 :       case PNK_RB:
    3719                 :       case PNK_RC:
    3720             369 :         if (!EmitDestructuringOps(cx, bce, SRC_DECL_NONE, lhs))
    3721               0 :             return false;
    3722             369 :         break;
    3723                 : #endif
    3724                 : #if JS_HAS_XML_SUPPORT
    3725                 :       case PNK_XMLUNARY:
    3726              18 :         JS_ASSERT(!bce->inStrictMode());
    3727              18 :         if (Emit1(cx, bce, JSOP_SETXMLNAME) < 0)
    3728               0 :             return false;
    3729              18 :         break;
    3730                 : #endif
    3731                 :       default:
    3732               0 :         JS_ASSERT(0);
    3733                 :     }
    3734          406347 :     return true;
    3735                 : }
    3736                 : 
    3737                 : #ifdef DEBUG
    3738                 : static JSBool
    3739              18 : GettableNoteForNextOp(BytecodeEmitter *bce)
    3740                 : {
    3741                 :     ptrdiff_t offset, target;
    3742                 :     jssrcnote *sn, *end;
    3743                 : 
    3744              18 :     offset = 0;
    3745              18 :     target = bce->offset();
    3746              45 :     for (sn = bce->notes(), end = sn + bce->noteCount(); sn < end;
    3747              27 :          sn = SN_NEXT(sn)) {
    3748              27 :         if (offset == target && SN_IS_GETTABLE(sn))
    3749               0 :             return JS_TRUE;
    3750              27 :         offset += SN_DELTA(sn);
    3751                 :     }
    3752              18 :     return JS_FALSE;
    3753                 : }
    3754                 : #endif
    3755                 : 
    3756                 : /* Top-level named functions need a nop for decompilation. */
    3757                 : static JSBool
    3758           28252 : EmitFunctionDefNop(JSContext *cx, BytecodeEmitter *bce, unsigned index)
    3759                 : {
    3760           28252 :     return NewSrcNote2(cx, bce, SRC_FUNCDEF, (ptrdiff_t)index) >= 0 &&
    3761           28252 :            Emit1(cx, bce, JSOP_NOP) >= 0;
    3762                 : }
    3763                 : 
    3764                 : static bool
    3765           11840 : EmitNewInit(JSContext *cx, BytecodeEmitter *bce, JSProtoKey key, ParseNode *pn)
    3766                 : {
    3767           11840 :     const size_t len = 1 + UINT32_INDEX_LEN;
    3768           11840 :     ptrdiff_t offset = EmitCheck(cx, bce, len);
    3769           11840 :     if (offset < 0)
    3770               0 :         return false;
    3771                 : 
    3772           11840 :     jsbytecode *next = bce->next();
    3773           11840 :     next[0] = JSOP_NEWINIT;
    3774           11840 :     next[1] = jsbytecode(key);
    3775           11840 :     next[2] = 0;
    3776           11840 :     next[3] = 0;
    3777           11840 :     next[4] = 0;
    3778           11840 :     bce->current->next = next + len;
    3779           11840 :     UpdateDepth(cx, bce, offset);
    3780           11840 :     CheckTypeSet(cx, bce, JSOP_NEWINIT);
    3781           11840 :     return true;
    3782                 : }
    3783                 : 
    3784                 : bool
    3785           24695 : ParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
    3786                 : {
    3787           24695 :     switch (getKind()) {
    3788                 :       case PNK_NUMBER:
    3789           13997 :         vp->setNumber(pn_dval);
    3790           13997 :         return true;
    3791                 :       case PNK_STRING:
    3792            3926 :         vp->setString(pn_atom);
    3793            3926 :         return true;
    3794                 :       case PNK_TRUE:
    3795             513 :         vp->setBoolean(true);
    3796             513 :         return true;
    3797                 :       case PNK_FALSE:
    3798             351 :         vp->setBoolean(false);
    3799             351 :         return true;
    3800                 :       case PNK_NULL:
    3801              81 :         vp->setNull();
    3802              81 :         return true;
    3803                 :       case PNK_RB: {
    3804            3258 :         JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
    3805                 : 
    3806            3258 :         JSObject *obj = NewDenseAllocatedArray(cx, pn_count);
    3807            3258 :         if (!obj)
    3808               0 :             return false;
    3809                 : 
    3810            3258 :         unsigned idx = 0;
    3811           17577 :         for (ParseNode *pn = pn_head; pn; idx++, pn = pn->pn_next) {
    3812                 :             Value value;
    3813           14319 :             if (!pn->getConstantValue(cx, strictChecks, &value))
    3814               0 :                 return false;
    3815           14319 :             if (!obj->defineGeneric(cx, INT_TO_JSID(idx), value, NULL, NULL, JSPROP_ENUMERATE))
    3816               0 :                 return false;
    3817                 :         }
    3818            3258 :         JS_ASSERT(idx == pn_count);
    3819                 : 
    3820            3258 :         types::FixArrayType(cx, obj);
    3821            3258 :         vp->setObject(*obj);
    3822            3258 :         return true;
    3823                 :       }
    3824                 :       case PNK_RC: {
    3825            2569 :         JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
    3826                 : 
    3827            2569 :         gc::AllocKind kind = GuessObjectGCKind(pn_count);
    3828            2569 :         JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
    3829            2569 :         if (!obj)
    3830               0 :             return false;
    3831                 : 
    3832            8045 :         for (ParseNode *pn = pn_head; pn; pn = pn->pn_next) {
    3833                 :             Value value;
    3834            5476 :             if (!pn->pn_right->getConstantValue(cx, strictChecks, &value))
    3835               0 :                 return false;
    3836                 : 
    3837            5476 :             ParseNode *pnid = pn->pn_left;
    3838            5476 :             if (pnid->isKind(PNK_NUMBER)) {
    3839             135 :                 Value idvalue = NumberValue(pnid->pn_dval);
    3840                 :                 jsid id;
    3841             135 :                 if (idvalue.isInt32() && INT_FITS_IN_JSID(idvalue.toInt32()))
    3842             108 :                     id = INT_TO_JSID(idvalue.toInt32());
    3843              27 :                 else if (!js_InternNonIntElementId(cx, obj, idvalue, &id))
    3844               0 :                     return false;
    3845             135 :                 if (!obj->defineGeneric(cx, id, value, NULL, NULL, JSPROP_ENUMERATE))
    3846               0 :                     return false;
    3847                 :             } else {
    3848            5341 :                 JS_ASSERT(pnid->isKind(PNK_NAME) || pnid->isKind(PNK_STRING));
    3849            5341 :                 JS_ASSERT(pnid->pn_atom != cx->runtime->atomState.protoAtom);
    3850            5341 :                 jsid id = ATOM_TO_JSID(pnid->pn_atom);
    3851            5341 :                 if (!DefineNativeProperty(cx, obj, id, value, NULL, NULL,
    3852            5341 :                                           JSPROP_ENUMERATE, 0, 0)) {
    3853               0 :                     return false;
    3854                 :                 }
    3855                 :             }
    3856                 :         }
    3857                 : 
    3858            2569 :         types::FixObjectType(cx, obj);
    3859            2569 :         vp->setObject(*obj);
    3860            2569 :         return true;
    3861                 :       }
    3862                 :       default:
    3863               0 :         JS_NOT_REACHED("Unexpected node");
    3864                 :     }
    3865                 :     return false;
    3866                 : }
    3867                 : 
    3868                 : static bool
    3869            4900 : EmitSingletonInitialiser(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    3870                 : {
    3871                 :     Value value;
    3872            4900 :     if (!pn->getConstantValue(cx, bce->needStrictChecks(), &value))
    3873               0 :         return false;
    3874                 : 
    3875            4900 :     JS_ASSERT(value.isObject());
    3876            4900 :     ObjectBox *objbox = bce->parser->newObjectBox(&value.toObject());
    3877            4900 :     if (!objbox)
    3878               0 :         return false;
    3879                 : 
    3880            4900 :     return EmitObjectOp(cx, objbox, JSOP_OBJECT, bce);
    3881                 : }
    3882                 : 
    3883                 : /* See the SRC_FOR source note offsetBias comments later in this file. */
    3884                 : JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
    3885                 : JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1);
    3886                 : 
    3887                 : class EmitLevelManager
    3888                 : {
    3889                 :     BytecodeEmitter *bce;
    3890                 :   public:
    3891         5657896 :     EmitLevelManager(BytecodeEmitter *bce) : bce(bce) { bce->emitLevel++; }
    3892         5657896 :     ~EmitLevelManager() { bce->emitLevel--; }
    3893                 : };
    3894                 : 
    3895                 : static bool
    3896           86985 : EmitCatch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    3897                 : {
    3898                 :     ptrdiff_t catchStart, guardJump;
    3899                 : 
    3900                 :     /*
    3901                 :      * Morph STMT_BLOCK to STMT_CATCH, note the block entry code offset,
    3902                 :      * and save the block object atom.
    3903                 :      */
    3904           86985 :     StmtInfo *stmt = bce->topStmt;
    3905           86985 :     JS_ASSERT(stmt->type == STMT_BLOCK && (stmt->flags & SIF_SCOPE));
    3906           86985 :     stmt->type = STMT_CATCH;
    3907           86985 :     catchStart = stmt->update;
    3908                 : 
    3909                 :     /* Go up one statement info record to the TRY or FINALLY record. */
    3910           86985 :     stmt = stmt->down;
    3911           86985 :     JS_ASSERT(stmt->type == STMT_TRY || stmt->type == STMT_FINALLY);
    3912                 : 
    3913                 :     /* Pick up the pending exception and bind it to the catch variable. */
    3914           86985 :     if (Emit1(cx, bce, JSOP_EXCEPTION) < 0)
    3915               0 :         return false;
    3916                 : 
    3917                 :     /*
    3918                 :      * Dup the exception object if there is a guard for rethrowing to use
    3919                 :      * it later when rethrowing or in other catches.
    3920                 :      */
    3921           86985 :     if (pn->pn_kid2 && Emit1(cx, bce, JSOP_DUP) < 0)
    3922               0 :         return false;
    3923                 : 
    3924           86985 :     ParseNode *pn2 = pn->pn_kid1;
    3925           86985 :     switch (pn2->getKind()) {
    3926                 : #if JS_HAS_DESTRUCTURING
    3927                 :       case PNK_RB:
    3928                 :       case PNK_RC:
    3929               0 :         if (!EmitDestructuringOps(cx, bce, SRC_DECL_NONE, pn2))
    3930               0 :             return false;
    3931               0 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    3932               0 :             return false;
    3933               0 :         break;
    3934                 : #endif
    3935                 : 
    3936                 :       case PNK_NAME:
    3937                 :         /* Inline and specialize BindNameToSlot for pn2. */
    3938           86985 :         JS_ASSERT(!pn2->pn_cookie.isFree());
    3939           86985 :         EMIT_UINT16_IMM_OP(JSOP_SETLOCAL, pn2->pn_cookie.slot());
    3940           86985 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    3941               0 :             return false;
    3942           86985 :         break;
    3943                 : 
    3944                 :       default:
    3945               0 :         JS_ASSERT(0);
    3946                 :     }
    3947                 : 
    3948                 :     /* Emit the guard expression, if there is one. */
    3949           86985 :     if (pn->pn_kid2) {
    3950              45 :         if (!EmitTree(cx, bce, pn->pn_kid2))
    3951               0 :             return false;
    3952              45 :         if (!SetSrcNoteOffset(cx, bce, CATCHNOTE(*stmt), 0, bce->offset() - catchStart))
    3953               0 :             return false;
    3954                 :         /* ifeq <next block> */
    3955              45 :         guardJump = EmitJump(cx, bce, JSOP_IFEQ, 0);
    3956              45 :         if (guardJump < 0)
    3957               0 :             return false;
    3958              45 :         GUARDJUMP(*stmt) = guardJump;
    3959                 : 
    3960                 :         /* Pop duplicated exception object as we no longer need it. */
    3961              45 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    3962               0 :             return false;
    3963                 :     }
    3964                 : 
    3965                 :     /* Emit the catch body. */
    3966           86985 :     if (!EmitTree(cx, bce, pn->pn_kid3))
    3967               0 :         return false;
    3968                 : 
    3969                 :     /*
    3970                 :      * Annotate the JSOP_LEAVEBLOCK that will be emitted as we unwind via
    3971                 :      * our PNK_LEXICALSCOPE parent, so the decompiler knows to pop.
    3972                 :      */
    3973           86985 :     ptrdiff_t off = bce->stackDepth;
    3974           86985 :     if (NewSrcNote2(cx, bce, SRC_CATCH, off) < 0)
    3975               0 :         return false;
    3976           86985 :     return true;
    3977                 : }
    3978                 : 
    3979                 : /*
    3980                 :  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr12127. See
    3981                 :  * the comment on EmitSwitch.
    3982                 :  */
    3983                 : MOZ_NEVER_INLINE static bool
    3984           87120 : EmitTry(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    3985                 : {
    3986                 :     StmtInfo stmtInfo;
    3987           87120 :     ptrdiff_t catchJump = -1;
    3988                 : 
    3989                 :     /*
    3990                 :      * Push stmtInfo to track jumps-over-catches and gosubs-to-finally
    3991                 :      * for later fixup.
    3992                 :      *
    3993                 :      * When a finally block is active (STMT_FINALLY in our tree context),
    3994                 :      * non-local jumps (including jumps-over-catches) result in a GOSUB
    3995                 :      * being written into the bytecode stream and fixed-up later (c.f.
    3996                 :      * EmitBackPatchOp and BackPatch).
    3997                 :      */
    3998           87120 :     PushStatement(bce, &stmtInfo, pn->pn_kid3 ? STMT_FINALLY : STMT_TRY, bce->offset());
    3999                 : 
    4000                 :     /*
    4001                 :      * Since an exception can be thrown at any place inside the try block,
    4002                 :      * we need to restore the stack and the scope chain before we transfer
    4003                 :      * the control to the exception handler.
    4004                 :      *
    4005                 :      * For that we store in a try note associated with the catch or
    4006                 :      * finally block the stack depth upon the try entry. The interpreter
    4007                 :      * uses this depth to properly unwind the stack and the scope chain.
    4008                 :      */
    4009           87120 :     int depth = bce->stackDepth;
    4010                 : 
    4011                 :     /* Mark try location for decompilation, then emit try block. */
    4012           87120 :     if (Emit1(cx, bce, JSOP_TRY) < 0)
    4013               0 :         return false;
    4014           87120 :     ptrdiff_t tryStart = bce->offset();
    4015           87120 :     if (!EmitTree(cx, bce, pn->pn_kid1))
    4016               0 :         return false;
    4017           87120 :     JS_ASSERT(depth == bce->stackDepth);
    4018                 : 
    4019                 :     /* GOSUB to finally, if present. */
    4020           87120 :     if (pn->pn_kid3) {
    4021             180 :         if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
    4022               0 :             return false;
    4023             180 :         if (EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, &GOSUBS(stmtInfo)) < 0)
    4024               0 :             return false;
    4025                 :     }
    4026                 : 
    4027                 :     /* Emit (hidden) jump over catch and/or finally. */
    4028           87120 :     if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
    4029               0 :         return false;
    4030           87120 :     if (EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, &catchJump) < 0)
    4031               0 :         return false;
    4032                 : 
    4033           87120 :     ptrdiff_t tryEnd = bce->offset();
    4034                 : 
    4035                 :     /* If this try has a catch block, emit it. */
    4036           87120 :     ParseNode *lastCatch = NULL;
    4037           87120 :     if (ParseNode *pn2 = pn->pn_kid2) {
    4038           86985 :         unsigned count = 0;    /* previous catch block's population */
    4039                 : 
    4040                 :         /*
    4041                 :          * The emitted code for a catch block looks like:
    4042                 :          *
    4043                 :          * [throwing]                          only if 2nd+ catch block
    4044                 :          * [leaveblock]                        only if 2nd+ catch block
    4045                 :          * enterblock                          with SRC_CATCH
    4046                 :          * exception
    4047                 :          * [dup]                               only if catchguard
    4048                 :          * setlocalpop <slot>                  or destructuring code
    4049                 :          * [< catchguard code >]               if there's a catchguard
    4050                 :          * [ifeq <offset to next catch block>]         " "
    4051                 :          * [pop]                               only if catchguard
    4052                 :          * < catch block contents >
    4053                 :          * leaveblock
    4054                 :          * goto <end of catch blocks>          non-local; finally applies
    4055                 :          *
    4056                 :          * If there's no catch block without a catchguard, the last
    4057                 :          * <offset to next catch block> points to rethrow code.  This
    4058                 :          * code will [gosub] to the finally code if appropriate, and is
    4059                 :          * also used for the catch-all trynote for capturing exceptions
    4060                 :          * thrown from catch{} blocks.
    4061                 :          */
    4062          173970 :         for (ParseNode *pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    4063                 :             ptrdiff_t guardJump, catchNote;
    4064                 : 
    4065           86985 :             JS_ASSERT(bce->stackDepth == depth);
    4066           86985 :             guardJump = GUARDJUMP(stmtInfo);
    4067           86985 :             if (guardJump != -1) {
    4068                 :                 /* Fix up and clean up previous catch block. */
    4069               0 :                 SetJumpOffsetAt(bce, guardJump);
    4070                 : 
    4071                 :                 /*
    4072                 :                  * Account for JSOP_ENTERBLOCK (whose block object count
    4073                 :                  * is saved below) and pushed exception object that we
    4074                 :                  * still have after the jumping from the previous guard.
    4075                 :                  */
    4076               0 :                 bce->stackDepth = depth + count + 1;
    4077                 : 
    4078                 :                 /*
    4079                 :                  * Move exception back to cx->exception to prepare for
    4080                 :                  * the next catch. We hide [throwing] from the decompiler
    4081                 :                  * since it compensates for the hidden JSOP_DUP at the
    4082                 :                  * start of the previous guarded catch.
    4083                 :                  */
    4084               0 :                 if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0 ||
    4085               0 :                     Emit1(cx, bce, JSOP_THROWING) < 0) {
    4086               0 :                     return false;
    4087                 :                 }
    4088               0 :                 if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
    4089               0 :                     return false;
    4090               0 :                 EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, count);
    4091               0 :                 JS_ASSERT(bce->stackDepth == depth);
    4092                 :             }
    4093                 : 
    4094                 :             /*
    4095                 :              * Annotate the JSOP_ENTERBLOCK that's about to be generated
    4096                 :              * by the call to EmitTree immediately below.  Save this
    4097                 :              * source note's index in stmtInfo for use by the PNK_CATCH:
    4098                 :              * case, where the length of the catch guard is set as the
    4099                 :              * note's offset.
    4100                 :              */
    4101           86985 :             catchNote = NewSrcNote2(cx, bce, SRC_CATCH, 0);
    4102           86985 :             if (catchNote < 0)
    4103               0 :                 return false;
    4104           86985 :             CATCHNOTE(stmtInfo) = catchNote;
    4105                 : 
    4106                 :             /*
    4107                 :              * Emit the lexical scope and catch body.  Save the catch's
    4108                 :              * block object population via count, for use when targeting
    4109                 :              * guardJump at the next catch (the guard mismatch case).
    4110                 :              */
    4111           86985 :             JS_ASSERT(pn3->isKind(PNK_LEXICALSCOPE));
    4112           86985 :             count = pn3->pn_objbox->object->asStaticBlock().slotCount();
    4113           86985 :             if (!EmitTree(cx, bce, pn3))
    4114               0 :                 return false;
    4115                 : 
    4116                 :             /* gosub <finally>, if required */
    4117           86985 :             if (pn->pn_kid3) {
    4118              45 :                 if (EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, &GOSUBS(stmtInfo)) < 0)
    4119               0 :                     return false;
    4120              45 :                 JS_ASSERT(bce->stackDepth == depth);
    4121                 :             }
    4122                 : 
    4123                 :             /*
    4124                 :              * Jump over the remaining catch blocks.  This will get fixed
    4125                 :              * up to jump to after catch/finally.
    4126                 :              */
    4127           86985 :             if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
    4128               0 :                 return false;
    4129           86985 :             if (EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, &catchJump) < 0)
    4130               0 :                 return false;
    4131                 : 
    4132                 :             /*
    4133                 :              * Save a pointer to the last catch node to handle try-finally
    4134                 :              * and try-catch(guard)-finally special cases.
    4135                 :              */
    4136           86985 :             lastCatch = pn3->expr();
    4137                 :         }
    4138                 :     }
    4139                 : 
    4140                 :     /*
    4141                 :      * Last catch guard jumps to the rethrow code sequence if none of the
    4142                 :      * guards match. Target guardJump at the beginning of the rethrow
    4143                 :      * sequence, just in case a guard expression throws and leaves the
    4144                 :      * stack unbalanced.
    4145                 :      */
    4146           87120 :     if (lastCatch && lastCatch->pn_kid2) {
    4147              45 :         SetJumpOffsetAt(bce, GUARDJUMP(stmtInfo));
    4148                 : 
    4149                 :         /* Sync the stack to take into account pushed exception. */
    4150              45 :         JS_ASSERT(bce->stackDepth == depth);
    4151              45 :         bce->stackDepth = depth + 1;
    4152                 : 
    4153                 :         /*
    4154                 :          * Rethrow the exception, delegating executing of finally if any
    4155                 :          * to the exception handler.
    4156                 :          */
    4157              45 :         if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0 || Emit1(cx, bce, JSOP_THROW) < 0)
    4158               0 :             return false;
    4159                 :     }
    4160                 : 
    4161           87120 :     JS_ASSERT(bce->stackDepth == depth);
    4162                 : 
    4163                 :     /* Emit finally handler if any. */
    4164           87120 :     ptrdiff_t finallyStart = 0;   /* to quell GCC uninitialized warnings */
    4165           87120 :     if (pn->pn_kid3) {
    4166                 :         /*
    4167                 :          * Fix up the gosubs that might have been emitted before non-local
    4168                 :          * jumps to the finally code.
    4169                 :          */
    4170             180 :         if (!BackPatch(cx, bce, GOSUBS(stmtInfo), bce->next(), JSOP_GOSUB))
    4171               0 :             return false;
    4172                 : 
    4173             180 :         finallyStart = bce->offset();
    4174                 : 
    4175                 :         /* Indicate that we're emitting a subroutine body. */
    4176             180 :         stmtInfo.type = STMT_SUBROUTINE;
    4177             180 :         if (!UpdateLineNumberNotes(cx, bce, pn->pn_kid3->pn_pos.begin.lineno))
    4178               0 :             return false;
    4179             540 :         if (Emit1(cx, bce, JSOP_FINALLY) < 0 ||
    4180             180 :             !EmitTree(cx, bce, pn->pn_kid3) ||
    4181             180 :             Emit1(cx, bce, JSOP_RETSUB) < 0)
    4182                 :         {
    4183               0 :             return false;
    4184                 :         }
    4185             180 :         JS_ASSERT(bce->stackDepth == depth);
    4186                 :     }
    4187           87120 :     if (!PopStatementBCE(cx, bce))
    4188               0 :         return false;
    4189                 : 
    4190           87120 :     if (NewSrcNote(cx, bce, SRC_ENDBRACE) < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
    4191               0 :         return false;
    4192                 : 
    4193                 :     /* Fix up the end-of-try/catch jumps to come here. */
    4194           87120 :     if (!BackPatch(cx, bce, catchJump, bce->next(), JSOP_GOTO))
    4195               0 :         return false;
    4196                 : 
    4197                 :     /*
    4198                 :      * Add the try note last, to let post-order give us the right ordering
    4199                 :      * (first to last for a given nesting level, inner to outer by level).
    4200                 :      */
    4201           87120 :     if (pn->pn_kid2 && !NewTryNote(cx, bce, JSTRY_CATCH, depth, tryStart, tryEnd))
    4202               0 :         return false;
    4203                 : 
    4204                 :     /*
    4205                 :      * If we've got a finally, mark try+catch region with additional
    4206                 :      * trynote to catch exceptions (re)thrown from a catch block or
    4207                 :      * for the try{}finally{} case.
    4208                 :      */
    4209           87120 :     if (pn->pn_kid3 && !NewTryNote(cx, bce, JSTRY_FINALLY, depth, tryStart, finallyStart))
    4210               0 :         return false;
    4211                 : 
    4212           87120 :     return true;
    4213                 : }
    4214                 : 
    4215                 : static bool
    4216           92057 : EmitIf(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    4217                 : {
    4218                 :     StmtInfo stmtInfo;
    4219                 : 
    4220                 :     /* Initialize so we can detect else-if chains and avoid recursion. */
    4221           92057 :     stmtInfo.type = STMT_IF;
    4222           92057 :     ptrdiff_t beq = -1;
    4223           92057 :     ptrdiff_t jmp = -1;
    4224           92057 :     ptrdiff_t noteIndex = -1;
    4225                 : 
    4226                 :   if_again:
    4227                 :     /* Emit code for the condition before pushing stmtInfo. */
    4228           92822 :     if (!EmitTree(cx, bce, pn->pn_kid1))
    4229               0 :         return JS_FALSE;
    4230           92822 :     ptrdiff_t top = bce->offset();
    4231           92822 :     if (stmtInfo.type == STMT_IF) {
    4232           92057 :         PushStatement(bce, &stmtInfo, STMT_IF, top);
    4233                 :     } else {
    4234                 :         /*
    4235                 :          * We came here from the goto further below that detects else-if
    4236                 :          * chains, so we must mutate stmtInfo back into a STMT_IF record.
    4237                 :          * Also (see below for why) we need a note offset for SRC_IF_ELSE
    4238                 :          * to help the decompiler.  Actually, we need two offsets, one for
    4239                 :          * decompiling any else clause and the second for decompiling an
    4240                 :          * else-if chain without bracing, overindenting, or incorrectly
    4241                 :          * scoping let declarations.
    4242                 :          */
    4243             765 :         JS_ASSERT(stmtInfo.type == STMT_ELSE);
    4244             765 :         stmtInfo.type = STMT_IF;
    4245             765 :         stmtInfo.update = top;
    4246             765 :         if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, jmp - beq))
    4247               0 :             return JS_FALSE;
    4248             765 :         if (!SetSrcNoteOffset(cx, bce, noteIndex, 1, top - beq))
    4249               0 :             return JS_FALSE;
    4250                 :     }
    4251                 : 
    4252                 :     /* Emit an annotated branch-if-false around the then part. */
    4253           92822 :     ParseNode *pn3 = pn->pn_kid3;
    4254           92822 :     noteIndex = NewSrcNote(cx, bce, pn3 ? SRC_IF_ELSE : SRC_IF);
    4255           92822 :     if (noteIndex < 0)
    4256               0 :         return JS_FALSE;
    4257           92822 :     beq = EmitJump(cx, bce, JSOP_IFEQ, 0);
    4258           92822 :     if (beq < 0)
    4259               0 :         return JS_FALSE;
    4260                 : 
    4261                 :     /* Emit code for the then and optional else parts. */
    4262           92822 :     if (!EmitTree(cx, bce, pn->pn_kid2))
    4263               0 :         return JS_FALSE;
    4264           92822 :     if (pn3) {
    4265                 :         /* Modify stmtInfo so we know we're in the else part. */
    4266            3304 :         stmtInfo.type = STMT_ELSE;
    4267                 : 
    4268                 :         /*
    4269                 :          * Emit a JSOP_BACKPATCH op to jump from the end of our then part
    4270                 :          * around the else part.  The PopStatementBCE call at the bottom of
    4271                 :          * this function will fix up the backpatch chain linked from
    4272                 :          * stmtInfo.breaks.
    4273                 :          */
    4274            3304 :         jmp = EmitGoto(cx, bce, &stmtInfo, &stmtInfo.breaks);
    4275            3304 :         if (jmp < 0)
    4276               0 :             return JS_FALSE;
    4277                 : 
    4278                 :         /* Ensure the branch-if-false comes here, then emit the else. */
    4279            3304 :         SetJumpOffsetAt(bce, beq);
    4280            3304 :         if (pn3->isKind(PNK_IF)) {
    4281             765 :             pn = pn3;
    4282             765 :             goto if_again;
    4283                 :         }
    4284                 : 
    4285            2539 :         if (!EmitTree(cx, bce, pn3))
    4286               0 :             return JS_FALSE;
    4287                 : 
    4288                 :         /*
    4289                 :          * Annotate SRC_IF_ELSE with the offset from branch to jump, for
    4290                 :          * the decompiler's benefit.  We can't just "back up" from the pc
    4291                 :          * of the else clause, because we don't know whether an extended
    4292                 :          * jump was required to leap from the end of the then clause over
    4293                 :          * the else clause.
    4294                 :          */
    4295            2539 :         if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, jmp - beq))
    4296               0 :             return JS_FALSE;
    4297                 :     } else {
    4298                 :         /* No else part, fixup the branch-if-false to come here. */
    4299           89518 :         SetJumpOffsetAt(bce, beq);
    4300                 :     }
    4301           92057 :     return PopStatementBCE(cx, bce);
    4302                 : }
    4303                 : 
    4304                 : #if JS_HAS_BLOCK_SCOPE
    4305                 : /*
    4306                 :  * pnLet represents one of:
    4307                 :  *
    4308                 :  *   let-expression:   (let (x = y) EXPR)
    4309                 :  *   let-statement:    let (x = y) { ... }
    4310                 :  *
    4311                 :  * For a let-expression 'let (x = a, [y,z] = b) e', EmitLet produces:
    4312                 :  *
    4313                 :  *  bytecode          stackDepth  srcnotes
    4314                 :  *  evaluate a        +1
    4315                 :  *  evaluate b        +1
    4316                 :  *  dup               +1          SRC_DESTRUCTLET + offset to enterlet0
    4317                 :  *  destructure y
    4318                 :  *  pick 1
    4319                 :  *  dup               +1          SRC_DESTRUCTLET + offset to enterlet0
    4320                 :  *  pick
    4321                 :  *  destructure z
    4322                 :  *  pick 1
    4323                 :  *  pop               -1
    4324                 :  *  enterlet0                     SRC_DECL + offset to leaveblockexpr
    4325                 :  *  evaluate e        +1
    4326                 :  *  leaveblockexpr    -3          SRC_PCBASE + offset to evaluate a
    4327                 :  *
    4328                 :  * Note that, since enterlet0 simply changes fp->blockChain and does not
    4329                 :  * otherwise touch the stack, evaluation of the let-var initializers must leave
    4330                 :  * the initial value in the let-var's future slot.
    4331                 :  *
    4332                 :  * The SRC_DESTRUCTLET distinguish JSOP_DUP as the beginning of a destructuring
    4333                 :  * let initialization and the offset allows the decompiler to find the block
    4334                 :  * object from which to find let var names. These forward offsets require
    4335                 :  * backpatching, which is handled by LetNotes.
    4336                 :  *
    4337                 :  * The SRC_DECL offset allows recursive decompilation of 'e'.
    4338                 :  *
    4339                 :  * The SRC_PCBASE allows js_DecompileValueGenerator to walk backwards from
    4340                 :  * JSOP_LEAVEBLOCKEXPR to the beginning of the let and is only needed for
    4341                 :  * let-expressions.
    4342                 :  */
    4343                 : /*
    4344                 :  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr12127. See
    4345                 :  * the comment on EmitSwitch.
    4346                 :  */
    4347                 : MOZ_NEVER_INLINE static bool
    4348            8416 : EmitLet(JSContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
    4349                 : {
    4350            8416 :     JS_ASSERT(pnLet->isArity(PN_BINARY));
    4351            8416 :     ParseNode *varList = pnLet->pn_left;
    4352            8416 :     JS_ASSERT(varList->isArity(PN_LIST));
    4353            8416 :     ParseNode *letBody = pnLet->pn_right;
    4354            8416 :     JS_ASSERT(letBody->isLet() && letBody->isKind(PNK_LEXICALSCOPE));
    4355            8416 :     StaticBlockObject &blockObj = letBody->pn_objbox->object->asStaticBlock();
    4356                 : 
    4357            8416 :     ptrdiff_t letHeadOffset = bce->offset();
    4358            8416 :     int letHeadDepth = bce->stackDepth;
    4359                 : 
    4360           16832 :     LetNotes letNotes(cx);
    4361            8416 :     if (!EmitVariables(cx, bce, varList, PushInitialValues, &letNotes))
    4362               0 :         return false;
    4363                 : 
    4364                 :     /* Push storage for hoisted let decls (e.g. 'let (x) { let y }'). */
    4365            8416 :     uint32_t alreadyPushed = unsigned(bce->stackDepth - letHeadDepth);
    4366            8416 :     uint32_t blockObjCount = blockObj.slotCount();
    4367            8596 :     for (uint32_t i = alreadyPushed; i < blockObjCount; ++i) {
    4368                 :         /* Tell the decompiler not to print the decl in the let head. */
    4369             180 :         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
    4370               0 :             return false;
    4371             180 :         if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    4372               0 :             return false;
    4373                 :     }
    4374                 : 
    4375                 :     StmtInfo stmtInfo;
    4376            8416 :     PushBlockScope(bce, &stmtInfo, blockObj, bce->offset());
    4377                 : 
    4378            8416 :     if (!letNotes.update(cx, bce, bce->offset()))
    4379               0 :         return false;
    4380                 : 
    4381            8416 :     ptrdiff_t declNote = NewSrcNote(cx, bce, SRC_DECL);
    4382            8416 :     if (declNote < 0)
    4383               0 :         return false;
    4384                 : 
    4385            8416 :     ptrdiff_t bodyBegin = bce->offset();
    4386            8416 :     if (!EmitEnterBlock(cx, bce, letBody, JSOP_ENTERLET0))
    4387               0 :         return false;
    4388                 : 
    4389            8416 :     if (!EmitTree(cx, bce, letBody->pn_expr))
    4390               0 :         return false;
    4391                 : 
    4392            8416 :     JSOp leaveOp = letBody->getOp();
    4393            8416 :     if (leaveOp == JSOP_LEAVEBLOCKEXPR) {
    4394            1459 :         if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - letHeadOffset) < 0)
    4395               0 :             return false;
    4396                 :     }
    4397                 : 
    4398            8416 :     JS_ASSERT(leaveOp == JSOP_LEAVEBLOCK || leaveOp == JSOP_LEAVEBLOCKEXPR);
    4399            8416 :     EMIT_UINT16_IMM_OP(leaveOp, blockObj.slotCount());
    4400                 : 
    4401            8416 :     ptrdiff_t bodyEnd = bce->offset();
    4402            8416 :     JS_ASSERT(bodyEnd > bodyBegin);
    4403                 : 
    4404            8416 :     if (!PopStatementBCE(cx, bce))
    4405               0 :         return false;
    4406                 : 
    4407                 :     ptrdiff_t o = PackLetData((bodyEnd - bodyBegin) -
    4408                 :                               (JSOP_ENTERLET0_LENGTH + JSOP_LEAVEBLOCK_LENGTH),
    4409            8416 :                               letNotes.isGroupAssign());
    4410            8416 :     return SetSrcNoteOffset(cx, bce, declNote, 0, o);
    4411                 : }
    4412                 : #endif
    4413                 : 
    4414                 : #if JS_HAS_XML_SUPPORT
    4415                 : static bool
    4416              36 : EmitXMLTag(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    4417                 : {
    4418              36 :     JS_ASSERT(!bce->inStrictMode());
    4419                 : 
    4420              36 :     if (Emit1(cx, bce, JSOP_STARTXML) < 0)
    4421               0 :         return false;
    4422                 : 
    4423                 :     {
    4424                 :         jsatomid index;
    4425              36 :         JSAtom *tagAtom = (pn->isKind(PNK_XMLETAGO))
    4426                 :                           ? cx->runtime->atomState.etagoAtom
    4427              36 :                           : cx->runtime->atomState.stagoAtom;
    4428              36 :         if (!bce->makeAtomIndex(tagAtom, &index))
    4429               0 :             return false;
    4430              36 :         if (!EmitIndex32(cx, JSOP_STRING, index, bce))
    4431               0 :             return false;
    4432                 :     }
    4433                 : 
    4434              36 :     JS_ASSERT(pn->pn_count != 0);
    4435              36 :     ParseNode *pn2 = pn->pn_head;
    4436              36 :     if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
    4437               0 :         return false;
    4438              36 :     if (!EmitTree(cx, bce, pn2))
    4439               0 :         return false;
    4440              36 :     if (Emit1(cx, bce, JSOP_ADD) < 0)
    4441               0 :         return false;
    4442                 : 
    4443                 :     uint32_t i;
    4444              36 :     for (pn2 = pn2->pn_next, i = 0; pn2; pn2 = pn2->pn_next, i++) {
    4445               0 :         if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
    4446               0 :             return false;
    4447               0 :         if (!EmitTree(cx, bce, pn2))
    4448               0 :             return false;
    4449               0 :         if ((i & 1) && pn2->isKind(PNK_XMLCURLYEXPR)) {
    4450               0 :             if (Emit1(cx, bce, JSOP_TOATTRVAL) < 0)
    4451               0 :                 return false;
    4452                 :         }
    4453               0 :         if (Emit1(cx, bce, (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0)
    4454               0 :             return false;
    4455                 :     }
    4456                 : 
    4457                 :     {
    4458                 :         jsatomid index;
    4459              36 :         JSAtom *tmp = (pn->isKind(PNK_XMLPTAGC)) ? cx->runtime->atomState.ptagcAtom
    4460              36 :                                                  : cx->runtime->atomState.tagcAtom;
    4461              36 :         if (!bce->makeAtomIndex(tmp, &index))
    4462               0 :             return false;
    4463              36 :         if (!EmitIndex32(cx, JSOP_STRING, index, bce))
    4464               0 :             return false;
    4465                 :     }
    4466              36 :     if (Emit1(cx, bce, JSOP_ADD) < 0)
    4467               0 :         return false;
    4468                 : 
    4469              36 :     if ((pn->pn_xflags & PNX_XMLROOT) && Emit1(cx, bce, pn->getOp()) < 0)
    4470               0 :         return false;
    4471                 : 
    4472              36 :     return true;
    4473                 : }
    4474                 : 
    4475                 : static bool
    4476               0 : EmitXMLProcessingInstruction(JSContext *cx, BytecodeEmitter *bce, XMLProcessingInstruction &pi)
    4477                 : {
    4478               0 :     JS_ASSERT(!bce->inStrictMode());
    4479                 : 
    4480                 :     jsatomid index;
    4481               0 :     if (!bce->makeAtomIndex(pi.data(), &index))
    4482               0 :         return false;
    4483               0 :     if (!EmitIndex32(cx, JSOP_QNAMEPART, index, bce))
    4484               0 :         return false;
    4485               0 :     if (!EmitAtomOp(cx, pi.target(), JSOP_XMLPI, bce))
    4486               0 :         return false;
    4487               0 :     return true;
    4488                 : }
    4489                 : #endif
    4490                 : 
    4491                 : /*
    4492                 :  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr12127. See
    4493                 :  * the comment on EmitSwitch.
    4494                 :  */
    4495                 : MOZ_NEVER_INLINE static bool
    4496           88677 : EmitLexicalScope(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    4497                 : {
    4498           88677 :     JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
    4499           88677 :     JS_ASSERT(pn->getOp() == JSOP_LEAVEBLOCK);
    4500                 : 
    4501                 :     StmtInfo stmtInfo;
    4502           88677 :     ObjectBox *objbox = pn->pn_objbox;
    4503           88677 :     StaticBlockObject &blockObj = objbox->object->asStaticBlock();
    4504           88677 :     PushBlockScope(bce, &stmtInfo, blockObj, bce->offset());
    4505                 : 
    4506                 :     /*
    4507                 :      * For compound statements (i.e. { stmt-list }), the decompiler does not
    4508                 :      * emit curlies by default. However, if this stmt-list contains a let
    4509                 :      * declaration, this is semantically invalid so we need to add a srcnote to
    4510                 :      * enterblock to tell the decompiler to add curlies. This condition
    4511                 :      * shouldn't be so complicated; try to find a simpler condition.
    4512                 :      */
    4513           88677 :     ptrdiff_t noteIndex = -1;
    4514          177129 :     if (pn->expr()->getKind() != PNK_FOR &&
    4515           88236 :         pn->expr()->getKind() != PNK_CATCH &&
    4516                 :         (stmtInfo.down
    4517                 :          ? stmtInfo.down->type == STMT_BLOCK &&
    4518             144 :            (!stmtInfo.down->down || stmtInfo.down->down->type != STMT_FOR_IN_LOOP)
    4519              72 :          : !bce->inFunction()))
    4520                 :     {
    4521                 :         /* There must be no source note already output for the next op. */
    4522             243 :         JS_ASSERT(bce->noteCount() == 0 ||
    4523                 :                   bce->lastNoteOffset() != bce->offset() ||
    4524             243 :                   !GettableNoteForNextOp(bce));
    4525             153 :         noteIndex = NewSrcNote2(cx, bce, SRC_BRACE, 0);
    4526             153 :         if (noteIndex < 0)
    4527               0 :             return false;
    4528                 :     }
    4529                 : 
    4530           88677 :     ptrdiff_t bodyBegin = bce->offset();
    4531           88677 :     if (!EmitEnterBlock(cx, bce, pn, JSOP_ENTERBLOCK))
    4532               0 :         return false;
    4533                 : 
    4534           88677 :     if (!EmitTree(cx, bce, pn->pn_expr))
    4535               0 :         return false;
    4536                 : 
    4537           88677 :     if (noteIndex >= 0) {
    4538             153 :         if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, bce->offset() - bodyBegin))
    4539               0 :             return false;
    4540                 :     }
    4541                 : 
    4542           88677 :     EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObj.slotCount());
    4543                 : 
    4544           88677 :     return PopStatementBCE(cx, bce);
    4545                 : }
    4546                 : 
    4547                 : static bool
    4548             648 : EmitWith(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    4549                 : {
    4550                 :     StmtInfo stmtInfo;
    4551             648 :     if (!EmitTree(cx, bce, pn->pn_left))
    4552               0 :         return false;
    4553             648 :     PushStatement(bce, &stmtInfo, STMT_WITH, bce->offset());
    4554             648 :     if (Emit1(cx, bce, JSOP_ENTERWITH) < 0)
    4555               0 :         return false;
    4556                 : 
    4557             648 :     if (!EmitTree(cx, bce, pn->pn_right))
    4558               0 :         return false;
    4559             648 :     if (Emit1(cx, bce, JSOP_LEAVEWITH) < 0)
    4560               0 :         return false;
    4561             648 :     return PopStatementBCE(cx, bce);
    4562                 : }
    4563                 : 
    4564                 : static bool
    4565            4681 : EmitForIn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    4566                 : {
    4567                 :     StmtInfo stmtInfo;
    4568            4681 :     PushStatement(bce, &stmtInfo, STMT_FOR_IN_LOOP, top);
    4569                 : 
    4570            4681 :     ParseNode *forHead = pn->pn_left;
    4571            4681 :     ParseNode *forBody = pn->pn_right;
    4572                 : 
    4573            4681 :     ParseNode *pn1 = forHead->pn_kid1;
    4574            4681 :     bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
    4575            4681 :     JS_ASSERT_IF(letDecl, pn1->isLet());
    4576                 : 
    4577            4681 :     StaticBlockObject *blockObj = letDecl ? &pn1->pn_objbox->object->asStaticBlock() : NULL;
    4578            4681 :     uint32_t blockObjCount = blockObj ? blockObj->slotCount() : 0;
    4579                 : 
    4580            4681 :     if (letDecl) {
    4581                 :         /*
    4582                 :          * The let's slot(s) will be under the iterator, but the block must not
    4583                 :          * be entered (i.e. fp->blockChain set) until after evaluating the rhs.
    4584                 :          * Thus, push to reserve space and enterblock after. The same argument
    4585                 :          * applies when leaving the loop. Thus, a for-let-in loop looks like:
    4586                 :          *
    4587                 :          *   push x N
    4588                 :          *   eval rhs
    4589                 :          *   iter
    4590                 :          *   enterlet1
    4591                 :          *   goto
    4592                 :          *     ... loop body
    4593                 :          *   ifne
    4594                 :          *   leaveforinlet
    4595                 :          *   enditer
    4596                 :          *   popn(N)
    4597                 :          */
    4598            2367 :         for (uint32_t i = 0; i < blockObjCount; ++i) {
    4599            1233 :             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    4600               0 :                 return false;
    4601                 :         }
    4602                 :     }
    4603                 : 
    4604                 :     /*
    4605                 :      * If the left part is 'var x', emit code to define x if necessary
    4606                 :      * using a prolog opcode, but do not emit a pop. If the left part was
    4607                 :      * originally 'var x = i', the parser will have rewritten it; see
    4608                 :      * Parser::forStatement. 'for (let x = i in o)' is mercifully banned.
    4609                 :      */
    4610            4681 :     if (pn1) {
    4611            3241 :         ParseNode *decl = letDecl ? pn1->pn_expr : pn1;
    4612            3241 :         JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET));
    4613            3241 :         bce->flags |= TCF_IN_FOR_INIT;
    4614            3241 :         if (!EmitVariables(cx, bce, decl, DefineVars))
    4615               0 :             return false;
    4616            3241 :         bce->flags &= ~TCF_IN_FOR_INIT;
    4617                 :     }
    4618                 : 
    4619                 :     /* Compile the object expression to the right of 'in'. */
    4620            4681 :     if (!EmitTree(cx, bce, forHead->pn_kid3))
    4621               0 :         return JS_FALSE;
    4622                 : 
    4623                 :     /*
    4624                 :      * Emit a bytecode to convert top of stack value to the iterator
    4625                 :      * object depending on the loop variant (for-in, for-each-in, or
    4626                 :      * destructuring for-in).
    4627                 :      */
    4628            4681 :     JS_ASSERT(pn->isOp(JSOP_ITER));
    4629            4681 :     if (Emit2(cx, bce, JSOP_ITER, (uint8_t) pn->pn_iflags) < 0)
    4630               0 :         return false;
    4631                 : 
    4632                 :     /* Enter the block before the loop body, after evaluating the obj. */
    4633                 :     StmtInfo letStmt;
    4634            4681 :     if (letDecl) {
    4635            1134 :         PushBlockScope(bce, &letStmt, *blockObj, bce->offset());
    4636            1134 :         letStmt.flags |= SIF_FOR_BLOCK;
    4637            1134 :         if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1))
    4638               0 :             return false;
    4639                 :     }
    4640                 : 
    4641                 :     /* Annotate so the decompiler can find the loop-closing jump. */
    4642            4681 :     int noteIndex = NewSrcNote(cx, bce, SRC_FOR_IN);
    4643            4681 :     if (noteIndex < 0)
    4644               0 :         return false;
    4645                 : 
    4646                 :     /*
    4647                 :      * Jump down to the loop condition to minimize overhead assuming at
    4648                 :      * least one iteration, as the other loop forms do.
    4649                 :      */
    4650            4681 :     ptrdiff_t jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
    4651            4681 :     if (jmp < 0)
    4652               0 :         return false;
    4653                 : 
    4654            4681 :     top = bce->offset();
    4655            4681 :     SET_STATEMENT_TOP(&stmtInfo, top);
    4656            4681 :     if (EmitLoopHead(cx, bce, NULL) < 0)
    4657               0 :         return false;
    4658                 : 
    4659                 : #ifdef DEBUG
    4660            4681 :     int loopDepth = bce->stackDepth;
    4661                 : #endif
    4662                 : 
    4663                 :     /*
    4664                 :      * Emit code to get the next enumeration value and assign it to the
    4665                 :      * left hand side. The JSOP_POP after this assignment is annotated
    4666                 :      * so that the decompiler can distinguish 'for (x in y)' from
    4667                 :      * 'for (var x in y)'.
    4668                 :      */
    4669            4681 :     if (!EmitAssignment(cx, bce, forHead->pn_kid2, JSOP_NOP, NULL))
    4670               0 :         return false;
    4671                 : 
    4672            4681 :     ptrdiff_t tmp2 = bce->offset();
    4673            7922 :     if (forHead->pn_kid1 && NewSrcNote2(cx, bce, SRC_DECL,
    4674            3241 :                                         (forHead->pn_kid1->isOp(JSOP_DEFVAR))
    4675                 :                                         ? SRC_DECL_VAR
    4676            3241 :                                         : SRC_DECL_LET) < 0) {
    4677               0 :         return false;
    4678                 :     }
    4679            4681 :     if (Emit1(cx, bce, JSOP_POP) < 0)
    4680               0 :         return false;
    4681                 : 
    4682                 :     /* The stack should be balanced around the assignment opcode sequence. */
    4683            4681 :     JS_ASSERT(bce->stackDepth == loopDepth);
    4684                 : 
    4685                 :     /* Emit code for the loop body. */
    4686            4681 :     if (!EmitTree(cx, bce, forBody))
    4687               0 :         return false;
    4688                 : 
    4689                 :     /* Set loop and enclosing "update" offsets, for continue. */
    4690            4681 :     StmtInfo *stmt = &stmtInfo;
    4691            4789 :     do {
    4692            4789 :         stmt->update = bce->offset();
    4693                 :     } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
    4694                 : 
    4695                 :     /*
    4696                 :      * Fixup the goto that starts the loop to jump down to JSOP_MOREITER.
    4697                 :      */
    4698            4681 :     SetJumpOffsetAt(bce, jmp);
    4699            4681 :     if (!EmitLoopEntry(cx, bce, NULL))
    4700               0 :         return false;
    4701            4681 :     if (Emit1(cx, bce, JSOP_MOREITER) < 0)
    4702               0 :         return false;
    4703            4681 :     ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFNE, top - bce->offset());
    4704            4681 :     if (beq < 0)
    4705               0 :         return false;
    4706                 : 
    4707                 :     /* Set the first srcnote offset so we can find the start of the loop body. */
    4708            4681 :     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, tmp2 - jmp))
    4709               0 :         return false;
    4710                 :     /* Set the second srcnote offset so we can find the closing jump. */
    4711            4681 :     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 1, beq - jmp))
    4712               0 :         return false;
    4713                 : 
    4714                 :     /* Fixup breaks and continues before JSOP_ITER (and JSOP_LEAVEFORINLET). */
    4715            4681 :     if (!PopStatementBCE(cx, bce))
    4716               0 :         return false;
    4717                 : 
    4718            4681 :     if (letDecl) {
    4719            1134 :         if (!PopStatementBCE(cx, bce))
    4720               0 :             return false;
    4721            1134 :         if (Emit1(cx, bce, JSOP_LEAVEFORLETIN) < 0)
    4722               0 :             return false;
    4723                 :     }
    4724                 : 
    4725            4681 :     if (!NewTryNote(cx, bce, JSTRY_ITER, bce->stackDepth, top, bce->offset()))
    4726               0 :         return false;
    4727            4681 :     if (Emit1(cx, bce, JSOP_ENDITER) < 0)
    4728               0 :         return false;
    4729                 : 
    4730            4681 :     if (letDecl) {
    4731                 :         /* Tell the decompiler to pop but not to print. */
    4732            1134 :         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
    4733               0 :             return false;
    4734            1134 :         EMIT_UINT16_IMM_OP(JSOP_POPN, blockObjCount);
    4735                 :     }
    4736                 : 
    4737            4681 :     return true;
    4738                 : }
    4739                 : 
    4740                 : static bool
    4741           24888 : EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    4742                 : {
    4743                 :     StmtInfo stmtInfo;
    4744           24888 :     PushStatement(bce, &stmtInfo, STMT_FOR_LOOP, top);
    4745                 : 
    4746           24888 :     ParseNode *forHead = pn->pn_left;
    4747           24888 :     ParseNode *forBody = pn->pn_right;
    4748                 : 
    4749                 :     /* C-style for (init; cond; update) ... loop. */
    4750           24888 :     JSOp op = JSOP_POP;
    4751           24888 :     ParseNode *pn3 = forHead->pn_kid1;
    4752           24888 :     if (!pn3) {
    4753                 :         /* No initializer: emit an annotated nop for the decompiler. */
    4754            5788 :         op = JSOP_NOP;
    4755                 :     } else {
    4756           19100 :         bce->flags |= TCF_IN_FOR_INIT;
    4757                 : #if JS_HAS_DESTRUCTURING
    4758           19100 :         if (pn3->isKind(PNK_ASSIGN)) {
    4759            1791 :             JS_ASSERT(pn3->isOp(JSOP_NOP));
    4760            1791 :             if (!MaybeEmitGroupAssignment(cx, bce, op, pn3, &op))
    4761               0 :                 return false;
    4762                 :         }
    4763                 : #endif
    4764           19100 :         if (op == JSOP_POP) {
    4765           19100 :             if (!EmitTree(cx, bce, pn3))
    4766               0 :                 return false;
    4767           19100 :             if (pn3->isKind(PNK_VAR) || pn3->isKind(PNK_CONST) || pn3->isKind(PNK_LET)) {
    4768                 :                 /*
    4769                 :                  * Check whether a destructuring-initialized var decl
    4770                 :                  * was optimized to a group assignment.  If so, we do
    4771                 :                  * not need to emit a pop below, so switch to a nop,
    4772                 :                  * just for the decompiler.
    4773                 :                  */
    4774           17300 :                 JS_ASSERT(pn3->isArity(PN_LIST) || pn3->isArity(PN_BINARY));
    4775           17300 :                 if (pn3->pn_xflags & PNX_GROUPINIT)
    4776               0 :                     op = JSOP_NOP;
    4777                 :             }
    4778                 :         }
    4779           19100 :         bce->flags &= ~TCF_IN_FOR_INIT;
    4780                 :     }
    4781                 : 
    4782                 :     /*
    4783                 :      * NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH).
    4784                 :      * Use tmp to hold the biased srcnote "top" offset, which differs
    4785                 :      * from the top local variable by the length of the JSOP_GOTO
    4786                 :      * emitted in between tmp and top if this loop has a condition.
    4787                 :      */
    4788           24888 :     int noteIndex = NewSrcNote(cx, bce, SRC_FOR);
    4789           24888 :     if (noteIndex < 0 || Emit1(cx, bce, op) < 0)
    4790               0 :         return false;
    4791           24888 :     ptrdiff_t tmp = bce->offset();
    4792                 : 
    4793           24888 :     ptrdiff_t jmp = -1;
    4794           24888 :     if (forHead->pn_kid2) {
    4795                 :         /* Goto the loop condition, which branches back to iterate. */
    4796           24500 :         jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
    4797           24500 :         if (jmp < 0)
    4798               0 :             return false;
    4799                 :     } else {
    4800             388 :         if (op != JSOP_NOP && Emit1(cx, bce, JSOP_NOP) < 0)
    4801               0 :             return false;
    4802                 :     }
    4803                 : 
    4804           24888 :     top = bce->offset();
    4805           24888 :     SET_STATEMENT_TOP(&stmtInfo, top);
    4806                 : 
    4807                 :     /* Emit code for the loop body. */
    4808           24888 :     if (EmitLoopHead(cx, bce, forBody) < 0)
    4809               0 :         return false;
    4810           24888 :     if (jmp == -1 && !EmitLoopEntry(cx, bce, forBody))
    4811               0 :         return false;
    4812           24888 :     if (!EmitTree(cx, bce, forBody))
    4813               0 :         return false;
    4814                 : 
    4815                 :     /* Set the second note offset so we can find the update part. */
    4816           24888 :     JS_ASSERT(noteIndex != -1);
    4817           24888 :     ptrdiff_t tmp2 = bce->offset();
    4818                 : 
    4819                 :     /* Set loop and enclosing "update" offsets, for continue. */
    4820           24888 :     StmtInfo *stmt = &stmtInfo;
    4821           24906 :     do {
    4822           24906 :         stmt->update = bce->offset();
    4823                 :     } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
    4824                 : 
    4825                 :     /* Check for update code to do before the condition (if any). */
    4826           24888 :     pn3 = forHead->pn_kid3;
    4827           24888 :     if (pn3) {
    4828           24419 :         op = JSOP_POP;
    4829                 : #if JS_HAS_DESTRUCTURING
    4830           24419 :         if (pn3->isKind(PNK_ASSIGN)) {
    4831             171 :             JS_ASSERT(pn3->isOp(JSOP_NOP));
    4832             171 :             if (!MaybeEmitGroupAssignment(cx, bce, op, pn3, &op))
    4833               0 :                 return false;
    4834                 :         }
    4835                 : #endif
    4836           24419 :         if (op == JSOP_POP && !EmitTree(cx, bce, pn3))
    4837               0 :             return false;
    4838                 : 
    4839                 :         /* Always emit the POP or NOP, to help the decompiler. */
    4840           24419 :         if (Emit1(cx, bce, op) < 0)
    4841               0 :             return false;
    4842                 : 
    4843                 :         /* Restore the absolute line number for source note readers. */
    4844           24419 :         ptrdiff_t lineno = pn->pn_pos.end.lineno;
    4845           24419 :         if (bce->currentLine() != (unsigned) lineno) {
    4846           22110 :             if (NewSrcNote2(cx, bce, SRC_SETLINE, lineno) < 0)
    4847               0 :                 return false;
    4848           22110 :             bce->current->currentLine = (unsigned) lineno;
    4849                 :         }
    4850                 :     }
    4851                 : 
    4852           24888 :     ptrdiff_t tmp3 = bce->offset();
    4853                 : 
    4854           24888 :     if (forHead->pn_kid2) {
    4855                 :         /* Fix up the goto from top to target the loop condition. */
    4856           24500 :         JS_ASSERT(jmp >= 0);
    4857           24500 :         SetJumpOffsetAt(bce, jmp);
    4858           24500 :         if (!EmitLoopEntry(cx, bce, forHead->pn_kid2))
    4859               0 :             return false;
    4860                 : 
    4861           24500 :         if (!EmitTree(cx, bce, forHead->pn_kid2))
    4862               0 :             return false;
    4863                 :     }
    4864                 : 
    4865                 :     /* Set the first note offset so we can find the loop condition. */
    4866           24888 :     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, tmp3 - tmp))
    4867               0 :         return false;
    4868           24888 :     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 1, tmp2 - tmp))
    4869               0 :         return false;
    4870                 :     /* The third note offset helps us find the loop-closing jump. */
    4871           24888 :     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 2, bce->offset() - tmp))
    4872               0 :         return false;
    4873                 : 
    4874                 :     /* If no loop condition, just emit a loop-closing jump. */
    4875           24888 :     op = forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO;
    4876           24888 :     if (EmitJump(cx, bce, op, top - bce->offset()) < 0)
    4877               0 :         return false;
    4878                 : 
    4879                 :     /* Now fixup all breaks and continues. */
    4880           24888 :     return PopStatementBCE(cx, bce);
    4881                 : }
    4882                 : 
    4883                 : static inline bool
    4884           29569 : EmitFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    4885                 : {
    4886           29569 :     JS_ASSERT(pn->pn_left->isKind(PNK_FORIN) || pn->pn_left->isKind(PNK_FORHEAD));
    4887           29569 :     return pn->pn_left->isKind(PNK_FORIN)
    4888                 :            ? EmitForIn(cx, bce, pn, top)
    4889           29569 :            : EmitNormalFor(cx, bce, pn, top);
    4890                 : }
    4891                 : 
    4892                 : static JS_NEVER_INLINE bool
    4893          157939 : EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    4894                 : {
    4895                 : #if JS_HAS_XML_SUPPORT
    4896          157939 :     if (pn->isArity(PN_NULLARY))
    4897              36 :         return Emit1(cx, bce, JSOP_GETFUNNS) >= 0;
    4898                 : #endif
    4899                 : 
    4900          157903 :     JSFunction *fun = pn->pn_funbox->function();
    4901          157903 :     JS_ASSERT(fun->isInterpreted());
    4902          157903 :     if (fun->script()) {
    4903                 :         /*
    4904                 :          * This second pass is needed to emit JSOP_NOP with a source note
    4905                 :          * for the already-emitted function definition prolog opcode. See
    4906                 :          * comments in the PNK_STATEMENTLIST case.
    4907                 :          */
    4908            3753 :         JS_ASSERT(pn->isOp(JSOP_NOP));
    4909            3753 :         JS_ASSERT(bce->inFunction());
    4910            3753 :         return EmitFunctionDefNop(cx, bce, pn->pn_index);
    4911                 :     }
    4912                 : 
    4913            8269 :     JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
    4914          162419 :                  fun->kind() == JSFUN_INTERPRETED);
    4915                 : 
    4916                 :     {
    4917          308300 :         BytecodeEmitter bce2(bce->parser, pn->pn_pos.begin.lineno);
    4918          154150 :         if (!bce2.init(cx))
    4919               0 :             return false;
    4920                 : 
    4921                 :         bce2.flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION |
    4922          154150 :                      (bce->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
    4923          154150 :         bce2.bindings.transfer(cx, &pn->pn_funbox->bindings);
    4924          154150 :         bce2.setFunction(fun);
    4925          154150 :         bce2.funbox = pn->pn_funbox;
    4926          154150 :         bce2.parent = bce;
    4927          154150 :         bce2.globalScope = bce->globalScope;
    4928                 : 
    4929                 :         /*
    4930                 :          * js::frontend::SetStaticLevel limited static nesting depth to fit in
    4931                 :          * 16 bits and to reserve the all-ones value, thereby reserving the
    4932                 :          * magic FREE_UPVAR_COOKIE value. Note the bce2.staticLevel assignment
    4933                 :          * below.
    4934                 :          */
    4935          154150 :         JS_ASSERT(bce->staticLevel < JS_BITMASK(16) - 1);
    4936          154150 :         bce2.staticLevel = bce->staticLevel + 1;
    4937                 : 
    4938                 :         /* We measured the max scope depth when we parsed the function. */
    4939          154150 :         if (!EmitFunctionScript(cx, &bce2, pn->pn_body))
    4940               0 :             return false;
    4941                 :     }
    4942                 : 
    4943                 :     /* Make the function object a literal in the outer script's pool. */
    4944          154150 :     unsigned index = bce->objectList.index(pn->pn_funbox);
    4945                 : 
    4946                 :     /* Emit a bytecode pointing to the closure object in its immediate. */
    4947          154150 :     if (pn->getOp() != JSOP_NOP) {
    4948          126069 :         if ((pn->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) &&
    4949             171 :             NewSrcNote(cx, bce, SRC_GENEXP) < 0)
    4950                 :         {
    4951               0 :             return false;
    4952                 :         }
    4953                 : 
    4954          125898 :         return EmitFunctionOp(cx, pn->getOp(), index, bce);
    4955                 :     }
    4956                 : 
    4957                 :     /*
    4958                 :      * For a script we emit the code as we parse. Thus the bytecode for
    4959                 :      * top-level functions should go in the prolog to predefine their
    4960                 :      * names in the variable object before the already-generated main code
    4961                 :      * is executed. This extra work for top-level scripts is not necessary
    4962                 :      * when we emit the code for a function. It is fully parsed prior to
    4963                 :      * invocation of the emitter and calls to EmitTree for function
    4964                 :      * definitions can be scheduled before generating the rest of code.
    4965                 :      */
    4966           28252 :     if (!bce->inFunction()) {
    4967           24499 :         JS_ASSERT(!bce->topStmt);
    4968           24499 :         if (!BindGlobal(cx, bce, pn, fun->atom))
    4969               0 :             return false;
    4970           24499 :         if (pn->pn_cookie.isFree()) {
    4971            2660 :             bce->switchToProlog();
    4972            2660 :             if (!EmitFunctionOp(cx, JSOP_DEFFUN, index, bce))
    4973               0 :                 return false;
    4974            2660 :             if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
    4975               0 :                 return false;
    4976            2660 :             bce->switchToMain();
    4977                 :         }
    4978                 : 
    4979                 :         /* Emit NOP for the decompiler. */
    4980           24499 :         if (!EmitFunctionDefNop(cx, bce, index))
    4981               0 :             return false;
    4982                 :     } else {
    4983                 :         unsigned slot;
    4984            7506 :         DebugOnly<BindingKind> kind = bce->bindings.lookup(cx, fun->atom, &slot);
    4985            3753 :         JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
    4986            3753 :         JS_ASSERT(index < JS_BIT(20));
    4987            3753 :         pn->pn_index = index;
    4988            4554 :         if (pn->isClosed() &&
    4989             459 :             !bce->callsEval() &&
    4990             342 :             !bce->closedVars.append(pn->pn_cookie.slot()))
    4991                 :         {
    4992               0 :             return false;
    4993                 :         }
    4994                 : 
    4995            3753 :         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
    4996               0 :             return false;
    4997            3753 :         if (!EmitIndexOp(cx, JSOP_LAMBDA, index, bce))
    4998               0 :             return false;
    4999            3753 :         EMIT_UINT16_IMM_OP(JSOP_SETLOCAL, slot);
    5000            3753 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    5001               0 :             return false;
    5002                 :     }
    5003                 : 
    5004           28252 :     return true;
    5005                 : }
    5006                 : 
    5007                 : static bool
    5008             189 : EmitDo(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5009                 : {
    5010                 :     /* Emit an annotated nop so we know to decompile a 'do' keyword. */
    5011             189 :     ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_WHILE);
    5012             189 :     if (noteIndex < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
    5013               0 :         return false;
    5014                 : 
    5015             189 :     ptrdiff_t noteIndex2 = NewSrcNote(cx, bce, SRC_WHILE);
    5016             189 :     if (noteIndex2 < 0)
    5017               0 :         return false;
    5018                 : 
    5019                 :     /* Compile the loop body. */
    5020             189 :     ptrdiff_t top = EmitLoopHead(cx, bce, pn->pn_left);
    5021             189 :     if (top < 0)
    5022               0 :         return false;
    5023             189 :     if (!EmitLoopEntry(cx, bce, NULL))
    5024               0 :         return false;
    5025                 : 
    5026                 :     StmtInfo stmtInfo;
    5027             189 :     PushStatement(bce, &stmtInfo, STMT_DO_LOOP, top);
    5028             189 :     if (!EmitTree(cx, bce, pn->pn_left))
    5029               0 :         return false;
    5030                 : 
    5031                 :     /* Set loop and enclosing label update offsets, for continue. */
    5032             189 :     ptrdiff_t off = bce->offset();
    5033             189 :     StmtInfo *stmt = &stmtInfo;
    5034             189 :     do {
    5035             189 :         stmt->update = off;
    5036                 :     } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
    5037                 : 
    5038                 :     /* Compile the loop condition, now that continues know where to go. */
    5039             189 :     if (!EmitTree(cx, bce, pn->pn_right))
    5040               0 :         return false;
    5041                 : 
    5042                 :     /*
    5043                 :      * Since we use JSOP_IFNE for other purposes as well as for do-while
    5044                 :      * loops, we must store 1 + (beq - top) in the SRC_WHILE note offset,
    5045                 :      * and the decompiler must get that delta and decompile recursively.
    5046                 :      */
    5047             189 :     ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFNE, top - bce->offset());
    5048             189 :     if (beq < 0)
    5049               0 :         return false;
    5050                 : 
    5051                 :     /*
    5052                 :      * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
    5053                 :      * note gets bigger.
    5054                 :      */
    5055             189 :     if (!SetSrcNoteOffset(cx, bce, noteIndex2, 0, beq - top))
    5056               0 :         return false;
    5057             189 :     if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, 1 + (off - top)))
    5058               0 :         return false;
    5059                 : 
    5060             189 :     return PopStatementBCE(cx, bce);
    5061                 : }
    5062                 : 
    5063                 : static bool
    5064            2127 : EmitWhile(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    5065                 : {
    5066                 :     /*
    5067                 :      * Minimize bytecodes issued for one or more iterations by jumping to
    5068                 :      * the condition below the body and closing the loop if the condition
    5069                 :      * is true with a backward branch. For iteration count i:
    5070                 :      *
    5071                 :      *  i    test at the top                 test at the bottom
    5072                 :      *  =    ===============                 ==================
    5073                 :      *  0    ifeq-pass                       goto; ifne-fail
    5074                 :      *  1    ifeq-fail; goto; ifne-pass      goto; ifne-pass; ifne-fail
    5075                 :      *  2    2*(ifeq-fail; goto); ifeq-pass  goto; 2*ifne-pass; ifne-fail
    5076                 :      *  . . .
    5077                 :      *  N    N*(ifeq-fail; goto); ifeq-pass  goto; N*ifne-pass; ifne-fail
    5078                 :      */
    5079                 :     StmtInfo stmtInfo;
    5080            2127 :     PushStatement(bce, &stmtInfo, STMT_WHILE_LOOP, top);
    5081                 : 
    5082            2127 :     ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_WHILE);
    5083            2127 :     if (noteIndex < 0)
    5084               0 :         return false;
    5085                 : 
    5086            2127 :     ptrdiff_t jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
    5087            2127 :     if (jmp < 0)
    5088               0 :         return false;
    5089                 : 
    5090            2127 :     top = EmitLoopHead(cx, bce, pn->pn_right);
    5091            2127 :     if (top < 0)
    5092               0 :         return false;
    5093                 : 
    5094            2127 :     if (!EmitTree(cx, bce, pn->pn_right))
    5095               0 :         return false;
    5096                 : 
    5097            2127 :     SetJumpOffsetAt(bce, jmp);
    5098            2127 :     if (!EmitLoopEntry(cx, bce, pn->pn_left))
    5099               0 :         return false;
    5100            2127 :     if (!EmitTree(cx, bce, pn->pn_left))
    5101               0 :         return false;
    5102                 : 
    5103            2127 :     ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFNE, top - bce->offset());
    5104            2127 :     if (beq < 0)
    5105               0 :         return false;
    5106                 : 
    5107            2127 :     if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, beq - jmp))
    5108               0 :         return false;
    5109                 : 
    5110            2127 :     return PopStatementBCE(cx, bce);
    5111                 : }
    5112                 : 
    5113                 : static bool
    5114            1656 : EmitBreak(JSContext *cx, BytecodeEmitter *bce, PropertyName *label)
    5115                 : {
    5116            1656 :     StmtInfo *stmt = bce->topStmt;
    5117                 :     SrcNoteType noteType;
    5118                 :     jsatomid labelIndex;
    5119            1656 :     if (label) {
    5120              90 :         if (!bce->makeAtomIndex(label, &labelIndex))
    5121               0 :             return false;
    5122                 : 
    5123             594 :         while (stmt->type != STMT_LABEL || stmt->label != label)
    5124             414 :             stmt = stmt->down;
    5125              90 :         noteType = SRC_BREAK2LABEL;
    5126                 :     } else {
    5127            1566 :         labelIndex = INVALID_ATOMID;
    5128            5364 :         while (!STMT_IS_LOOP(stmt) && stmt->type != STMT_SWITCH)
    5129            2232 :             stmt = stmt->down;
    5130            1566 :         noteType = (stmt->type == STMT_SWITCH) ? SRC_SWITCHBREAK : SRC_BREAK;
    5131                 :     }
    5132                 : 
    5133            1656 :     return EmitGoto(cx, bce, stmt, &stmt->breaks, labelIndex, noteType) >= 0;
    5134                 : }
    5135                 : 
    5136                 : static bool
    5137             153 : EmitContinue(JSContext *cx, BytecodeEmitter *bce, PropertyName *label)
    5138                 : {
    5139             153 :     StmtInfo *stmt = bce->topStmt;
    5140                 :     SrcNoteType noteType;
    5141                 :     jsatomid labelIndex;
    5142             153 :     if (label) {
    5143              36 :         if (!bce->makeAtomIndex(label, &labelIndex))
    5144               0 :             return false;
    5145                 : 
    5146                 :         /* Find the loop statement enclosed by the matching label. */
    5147              36 :         StmtInfo *loop = NULL;
    5148             225 :         while (stmt->type != STMT_LABEL || stmt->label != label) {
    5149             153 :             if (STMT_IS_LOOP(stmt))
    5150              63 :                 loop = stmt;
    5151             153 :             stmt = stmt->down;
    5152                 :         }
    5153              36 :         stmt = loop;
    5154              36 :         noteType = SRC_CONT2LABEL;
    5155                 :     } else {
    5156             117 :         labelIndex = INVALID_ATOMID;
    5157             504 :         while (!STMT_IS_LOOP(stmt))
    5158             270 :             stmt = stmt->down;
    5159             117 :         noteType = SRC_CONTINUE;
    5160                 :     }
    5161                 : 
    5162             153 :     return EmitGoto(cx, bce, stmt, &stmt->continues, labelIndex, noteType) >= 0;
    5163                 : }
    5164                 : 
    5165                 : static bool
    5166           37782 : EmitReturn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5167                 : {
    5168                 :     /* Push a return value */
    5169           37782 :     if (ParseNode *pn2 = pn->pn_kid) {
    5170           36423 :         if (!EmitTree(cx, bce, pn2))
    5171               0 :             return false;
    5172                 :     } else {
    5173                 :         /* No explicit return value provided */
    5174            1359 :         if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    5175               0 :             return false;
    5176                 :     }
    5177                 : 
    5178                 :     /*
    5179                 :      * EmitNonLocalJumpFixup may add fixup bytecode to close open try
    5180                 :      * blocks having finally clauses and to exit intermingled let blocks.
    5181                 :      * We can't simply transfer control flow to our caller in that case,
    5182                 :      * because we must gosub to those finally clauses from inner to outer,
    5183                 :      * with the correct stack pointer (i.e., after popping any with,
    5184                 :      * for/in, etc., slots nested inside the finally's try).
    5185                 :      *
    5186                 :      * In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an
    5187                 :      * extra JSOP_RETRVAL after the fixups.
    5188                 :      */
    5189           37782 :     ptrdiff_t top = bce->offset();
    5190                 : 
    5191           37782 :     if (Emit1(cx, bce, JSOP_RETURN) < 0)
    5192               0 :         return false;
    5193           37782 :     if (!EmitNonLocalJumpFixup(cx, bce, NULL))
    5194               0 :         return false;
    5195           37782 :     if (top + JSOP_RETURN_LENGTH != bce->offset()) {
    5196            4072 :         bce->base()[top] = JSOP_SETRVAL;
    5197            4072 :         if (Emit1(cx, bce, JSOP_RETRVAL) < 0)
    5198               0 :             return false;
    5199                 :     }
    5200                 : 
    5201           37782 :     return true;
    5202                 : }
    5203                 : 
    5204                 : static bool
    5205          440408 : EmitStatementList(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    5206                 : {
    5207          440408 :     JS_ASSERT(pn->isArity(PN_LIST));
    5208                 : 
    5209          440408 :     ptrdiff_t noteIndex = -1;
    5210          440408 :     ptrdiff_t tmp = bce->offset();
    5211          440408 :     if (pn->pn_xflags & PNX_NEEDBRACES) {
    5212              99 :         noteIndex = NewSrcNote2(cx, bce, SRC_BRACE, 0);
    5213              99 :         if (noteIndex < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
    5214               0 :             return false;
    5215                 :     }
    5216                 : 
    5217                 :     StmtInfo stmtInfo;
    5218          440408 :     PushStatement(bce, &stmtInfo, STMT_BLOCK, top);
    5219                 : 
    5220          440408 :     ParseNode *pnchild = pn->pn_head;
    5221          440408 :     if (pn->pn_xflags & PNX_FUNCDEFS) {
    5222                 :         /*
    5223                 :          * This block contains top-level function definitions. To ensure
    5224                 :          * that we emit the bytecode defining them before the rest of code
    5225                 :          * in the block we use a separate pass over functions. During the
    5226                 :          * main pass later the emitter will add JSOP_NOP with source notes
    5227                 :          * for the function to preserve the original functions position
    5228                 :          * when decompiling.
    5229                 :          *
    5230                 :          * Currently this is used only for functions, as compile-as-we go
    5231                 :          * mode for scripts does not allow separate emitter passes.
    5232                 :          */
    5233            2736 :         JS_ASSERT(bce->inFunction());
    5234            2736 :         if (pn->pn_xflags & PNX_DESTRUCT) {
    5235                 :             /*
    5236                 :              * Assign the destructuring arguments before defining any
    5237                 :              * functions, see bug 419662.
    5238                 :              */
    5239               0 :             JS_ASSERT(pnchild->isKind(PNK_SEMI));
    5240               0 :             JS_ASSERT(pnchild->pn_kid->isKind(PNK_VAR) || pnchild->pn_kid->isKind(PNK_CONST));
    5241               0 :             if (!EmitTree(cx, bce, pnchild))
    5242               0 :                 return false;
    5243               0 :             pnchild = pnchild->pn_next;
    5244                 :         }
    5245                 : 
    5246           17109 :         for (ParseNode *pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
    5247           14373 :             if (pn2->isKind(PNK_FUNCTION)) {
    5248            3753 :                 if (pn2->isOp(JSOP_NOP)) {
    5249            3753 :                     if (!EmitTree(cx, bce, pn2))
    5250               0 :                         return false;
    5251                 :                 } else {
    5252                 :                     /*
    5253                 :                      * JSOP_DEFFUN in a top-level block with function
    5254                 :                      * definitions appears, for example, when "if (true)"
    5255                 :                      * is optimized away from "if (true) function x() {}".
    5256                 :                      * See bug 428424.
    5257                 :                      */
    5258               0 :                     JS_ASSERT(pn2->isOp(JSOP_DEFFUN));
    5259                 :                 }
    5260                 :             }
    5261                 :         }
    5262                 :     }
    5263                 : 
    5264         1076961 :     for (ParseNode *pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
    5265          636553 :         if (!EmitTree(cx, bce, pn2))
    5266               0 :             return false;
    5267                 :     }
    5268                 : 
    5269          440408 :     if (noteIndex >= 0 && !SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, bce->offset() - tmp))
    5270               0 :         return false;
    5271                 : 
    5272          440408 :     return PopStatementBCE(cx, bce);
    5273                 : }
    5274                 : 
    5275                 : static bool
    5276          556399 : EmitStatement(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5277                 : {
    5278          556399 :     JS_ASSERT(pn->isKind(PNK_SEMI));
    5279                 : 
    5280          556399 :     ParseNode *pn2 = pn->pn_kid;
    5281          556399 :     if (!pn2)
    5282            1647 :         return true;
    5283                 : 
    5284                 :     /*
    5285                 :      * Top-level or called-from-a-native JS_Execute/EvaluateScript,
    5286                 :      * debugger, and eval frames may need the value of the ultimate
    5287                 :      * expression statement as the script's result, despite the fact
    5288                 :      * that it appears useless to the compiler.
    5289                 :      *
    5290                 :      * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
    5291                 :      * calling JS_Compile* to suppress JSOP_POPV.
    5292                 :      */
    5293                 :     bool wantval;
    5294          554752 :     JSBool useful = wantval = !(bce->flags & (TCF_IN_FUNCTION | TCF_NO_SCRIPT_RVAL));
    5295                 : 
    5296                 :     /* Don't eliminate expressions with side effects. */
    5297          554752 :     if (!useful) {
    5298          519330 :         if (!CheckSideEffects(cx, bce, pn2, &useful))
    5299               0 :             return false;
    5300                 : 
    5301                 :         /*
    5302                 :          * Don't eliminate apparently useless expressions if they are
    5303                 :          * labeled expression statements.  The tc->topStmt->update test
    5304                 :          * catches the case where we are nesting in EmitTree for a labeled
    5305                 :          * compound statement.
    5306                 :          */
    5307          519357 :         if (bce->topStmt &&
    5308                 :             bce->topStmt->type == STMT_LABEL &&
    5309              27 :             bce->topStmt->update >= bce->offset())
    5310                 :         {
    5311              27 :             useful = true;
    5312                 :         }
    5313                 :     }
    5314                 : 
    5315          554752 :     if (useful) {
    5316          554039 :         JSOp op = wantval ? JSOP_POPV : JSOP_POP;
    5317          554039 :         JS_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
    5318                 : #if JS_HAS_DESTRUCTURING
    5319         1438706 :         if (!wantval &&
    5320          518617 :             pn2->isKind(PNK_ASSIGN) &&
    5321          366050 :             !MaybeEmitGroupAssignment(cx, bce, op, pn2, &op))
    5322                 :         {
    5323               0 :             return false;
    5324                 :         }
    5325                 : #endif
    5326          554039 :         if (op != JSOP_NOP) {
    5327          554030 :             if (!EmitTree(cx, bce, pn2))
    5328               0 :                 return false;
    5329          554030 :             if (Emit1(cx, bce, op) < 0)
    5330               0 :                 return false;
    5331                 :         }
    5332             713 :     } else if (!pn->isDirectivePrologueMember()) {
    5333                 :         /* Don't complain about directive prologue members; just don't emit their code. */
    5334             163 :         bce->current->currentLine = pn2->pn_pos.begin.lineno;
    5335             163 :         if (!ReportCompileErrorNumber(cx, bce->tokenStream(), pn2,
    5336             163 :                                       JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_USELESS_EXPR))
    5337                 :         {
    5338               0 :             return false;
    5339                 :         }
    5340                 :     }
    5341                 : 
    5342          554752 :     return true;
    5343                 : }
    5344                 : 
    5345                 : static bool
    5346            1260 : EmitDelete(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5347                 : {
    5348                 :     /*
    5349                 :      * Under ECMA 3, deleting a non-reference returns true -- but alas we
    5350                 :      * must evaluate the operand if it appears it might have side effects.
    5351                 :      */
    5352            1260 :     ParseNode *pn2 = pn->pn_kid;
    5353            1260 :     switch (pn2->getKind()) {
    5354                 :       case PNK_NAME:
    5355                 :       {
    5356             486 :         if (!BindNameToSlot(cx, bce, pn2))
    5357               0 :             return false;
    5358             486 :         JSOp op = pn2->getOp();
    5359             486 :         if (op == JSOP_FALSE) {
    5360              18 :             if (Emit1(cx, bce, op) < 0)
    5361               0 :                 return false;
    5362                 :         } else {
    5363             468 :             if (!EmitAtomOp(cx, pn2, op, bce))
    5364               0 :                 return false;
    5365                 :         }
    5366             486 :         break;
    5367                 :       }
    5368                 :       case PNK_DOT:
    5369             378 :         if (!EmitPropOp(cx, pn2, JSOP_DELPROP, bce, false))
    5370               0 :             return false;
    5371             378 :         break;
    5372                 : #if JS_HAS_XML_SUPPORT
    5373                 :       case PNK_DBLDOT:
    5374               0 :         JS_ASSERT(!bce->inStrictMode());
    5375               0 :         if (!EmitElemOp(cx, pn2, JSOP_DELDESC, bce))
    5376               0 :             return false;
    5377               0 :         break;
    5378                 : #endif
    5379                 :       case PNK_LB:
    5380             396 :         if (!EmitElemOp(cx, pn2, JSOP_DELELEM, bce))
    5381               0 :             return false;
    5382             396 :         break;
    5383                 :       default:
    5384                 :       {
    5385                 :         /*
    5386                 :          * If useless, just emit JSOP_TRUE; otherwise convert delete foo()
    5387                 :          * to foo(), true (a comma expression, requiring SRC_PCDELTA).
    5388                 :          */
    5389               0 :         JSBool useful = false;
    5390               0 :         if (!CheckSideEffects(cx, bce, pn2, &useful))
    5391               0 :             return false;
    5392                 : 
    5393                 :         ptrdiff_t off, noteIndex;
    5394               0 :         if (useful) {
    5395               0 :             JS_ASSERT_IF(pn2->isKind(PNK_LP), !(pn2->pn_xflags & PNX_SETCALL));
    5396               0 :             if (!EmitTree(cx, bce, pn2))
    5397               0 :                 return false;
    5398               0 :             off = bce->offset();
    5399               0 :             noteIndex = NewSrcNote2(cx, bce, SRC_PCDELTA, 0);
    5400               0 :             if (noteIndex < 0 || Emit1(cx, bce, JSOP_POP) < 0)
    5401               0 :                 return false;
    5402                 :         } else {
    5403               0 :             off = noteIndex = -1;
    5404                 :         }
    5405                 : 
    5406               0 :         if (Emit1(cx, bce, JSOP_TRUE) < 0)
    5407               0 :             return false;
    5408               0 :         if (noteIndex >= 0) {
    5409               0 :             ptrdiff_t tmp = bce->offset();
    5410               0 :             if (!SetSrcNoteOffset(cx, bce, unsigned(noteIndex), 0, tmp - off))
    5411               0 :                 return false;
    5412                 :         }
    5413                 :       }
    5414                 :     }
    5415                 : 
    5416            1260 :     return true;
    5417                 : }
    5418                 : 
    5419                 : static bool
    5420          225006 : EmitCallOrNew(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    5421                 : {
    5422          225006 :     bool callop = pn->isKind(PNK_LP);
    5423                 : 
    5424                 :     /*
    5425                 :      * Emit callable invocation or operator new (constructor call) code.
    5426                 :      * First, emit code for the left operand to evaluate the callable or
    5427                 :      * constructable object expression.
    5428                 :      *
    5429                 :      * For operator new applied to other expressions than E4X ones, we emit
    5430                 :      * JSOP_GETPROP instead of JSOP_CALLPROP, etc. This is necessary to
    5431                 :      * interpose the lambda-initialized method read barrier -- see the code
    5432                 :      * in jsinterp.cpp for JSOP_LAMBDA followed by JSOP_{SET,INIT}PROP.
    5433                 :      *
    5434                 :      * Then (or in a call case that has no explicit reference-base
    5435                 :      * object) we emit JSOP_UNDEFINED to produce the undefined |this| 
    5436                 :      * value required for calls (which non-strict mode functions 
    5437                 :      * will box into the global object).
    5438                 :      */
    5439          225006 :     ParseNode *pn2 = pn->pn_head;
    5440          225006 :     switch (pn2->getKind()) {
    5441                 :       case PNK_NAME:
    5442          153768 :         if (!EmitNameOp(cx, bce, pn2, callop))
    5443               0 :             return false;
    5444          153768 :         break;
    5445                 :       case PNK_DOT:
    5446           62971 :         if (!EmitPropOp(cx, pn2, pn2->getOp(), bce, callop))
    5447               0 :             return false;
    5448           62971 :         break;
    5449                 :       case PNK_LB:
    5450             567 :         JS_ASSERT(pn2->isOp(JSOP_GETELEM));
    5451             567 :         if (!EmitElemOp(cx, pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM, bce))
    5452               0 :             return false;
    5453             567 :         break;
    5454                 : #if JS_HAS_XML_SUPPORT
    5455                 :       case PNK_XMLUNARY:
    5456               9 :         JS_ASSERT(pn2->isOp(JSOP_XMLNAME));
    5457               9 :         if (!EmitXMLName(cx, pn2, JSOP_CALLXMLNAME, bce))
    5458               0 :             return false;
    5459               9 :         callop = true;          /* suppress JSOP_UNDEFINED after */
    5460               9 :         break;
    5461                 : #endif
    5462                 :       default:
    5463            7691 :         if (!EmitTree(cx, bce, pn2))
    5464               0 :             return false;
    5465            7691 :         callop = false;             /* trigger JSOP_UNDEFINED after */
    5466            7691 :         break;
    5467                 :     }
    5468          225006 :     if (!callop && Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    5469               0 :         return false;
    5470                 : 
    5471                 :     /* Remember start of callable-object bytecode for decompilation hint. */
    5472          225006 :     ptrdiff_t off = top;
    5473                 : 
    5474                 :     /*
    5475                 :      * Emit code for each argument in order, then emit the JSOP_*CALL or
    5476                 :      * JSOP_NEW bytecode with a two-byte immediate telling how many args
    5477                 :      * were pushed on the operand stack.
    5478                 :      */
    5479          225006 :     unsigned oldflags = bce->flags;
    5480          225006 :     bce->flags &= ~TCF_IN_FOR_INIT;
    5481          543289 :     for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
    5482          318283 :         if (!EmitTree(cx, bce, pn3))
    5483               0 :             return false;
    5484                 :     }
    5485          225006 :     bce->flags |= oldflags & TCF_IN_FOR_INIT;
    5486          225006 :     if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - off) < 0)
    5487               0 :         return false;
    5488                 : 
    5489          225006 :     uint32_t argc = pn->pn_count - 1;
    5490          225006 :     if (Emit3(cx, bce, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0)
    5491               0 :         return false;
    5492          225006 :     CheckTypeSet(cx, bce, pn->getOp());
    5493          225006 :     if (pn->isOp(JSOP_EVAL))
    5494            3849 :         EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
    5495          225006 :     if (pn->pn_xflags & PNX_SETCALL) {
    5496              36 :         if (Emit1(cx, bce, JSOP_SETCALL) < 0)
    5497               0 :             return false;
    5498                 :     }
    5499          225006 :     return true;
    5500                 : }
    5501                 : 
    5502                 : static bool
    5503            6453 : EmitLogical(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5504                 : {
    5505                 :     /*
    5506                 :      * JSOP_OR converts the operand on the stack to boolean, leaves the original
    5507                 :      * value on the stack and jumps if true; otherwise it falls into the next
    5508                 :      * bytecode, which pops the left operand and then evaluates the right operand.
    5509                 :      * The jump goes around the right operand evaluation.
    5510                 :      *
    5511                 :      * JSOP_AND converts the operand on the stack to boolean and jumps if false;
    5512                 :      * otherwise it falls into the right operand's bytecode.
    5513                 :      */
    5514                 : 
    5515            6453 :     if (pn->isArity(PN_BINARY)) {
    5516            6210 :         if (!EmitTree(cx, bce, pn->pn_left))
    5517               0 :             return false;
    5518            6210 :         ptrdiff_t top = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
    5519            6210 :         if (top < 0)
    5520               0 :             return false;
    5521            6210 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    5522               0 :             return false;
    5523            6210 :         if (!EmitTree(cx, bce, pn->pn_right))
    5524               0 :             return false;
    5525            6210 :         ptrdiff_t off = bce->offset();
    5526            6210 :         jsbytecode *pc = bce->code(top);
    5527            6210 :         SET_JUMP_OFFSET(pc, off - top);
    5528            6210 :         *pc = pn->getOp();
    5529            6210 :         return true;
    5530                 :     }
    5531                 : 
    5532             243 :     JS_ASSERT(pn->isArity(PN_LIST));
    5533             243 :     JS_ASSERT(pn->pn_head->pn_next->pn_next);
    5534                 : 
    5535                 :     /* Left-associative operator chain: avoid too much recursion. */
    5536             243 :     ParseNode *pn2 = pn->pn_head;
    5537             243 :     if (!EmitTree(cx, bce, pn2))
    5538               0 :         return false;
    5539             243 :     ptrdiff_t top = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
    5540             243 :     if (top < 0)
    5541               0 :         return false;
    5542             243 :     if (Emit1(cx, bce, JSOP_POP) < 0)
    5543               0 :         return false;
    5544                 : 
    5545                 :     /* Emit nodes between the head and the tail. */
    5546             243 :     ptrdiff_t jmp = top;
    5547             801 :     while ((pn2 = pn2->pn_next)->pn_next) {
    5548             315 :         if (!EmitTree(cx, bce, pn2))
    5549               0 :             return false;
    5550             315 :         ptrdiff_t off = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
    5551             315 :         if (off < 0)
    5552               0 :             return false;
    5553             315 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    5554               0 :             return false;
    5555             315 :         SET_JUMP_OFFSET(bce->code(jmp), off - jmp);
    5556             315 :         jmp = off;
    5557                 :     }
    5558             243 :     if (!EmitTree(cx, bce, pn2))
    5559               0 :         return false;
    5560                 : 
    5561             243 :     pn2 = pn->pn_head;
    5562             243 :     ptrdiff_t off = bce->offset();
    5563             558 :     do {
    5564             558 :         jsbytecode *pc = bce->code(top);
    5565             558 :         ptrdiff_t tmp = GET_JUMP_OFFSET(pc);
    5566             558 :         SET_JUMP_OFFSET(pc, off - top);
    5567             558 :         *pc = pn->getOp();
    5568             558 :         top += tmp;
    5569                 :     } while ((pn2 = pn2->pn_next)->pn_next);
    5570                 : 
    5571             243 :     return true;
    5572                 : }
    5573                 : 
    5574                 : static bool
    5575           29933 : EmitIncOrDec(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5576                 : {
    5577                 :     /* Emit lvalue-specialized code for ++/-- operators. */
    5578           29933 :     ParseNode *pn2 = pn->pn_kid;
    5579           29933 :     JS_ASSERT(!pn2->isKind(PNK_RP));
    5580           29933 :     JSOp op = pn->getOp();
    5581           29933 :     switch (pn2->getKind()) {
    5582                 :       case PNK_DOT:
    5583             423 :         if (!EmitPropIncDec(cx, pn2, op, bce))
    5584               0 :             return false;
    5585             423 :         break;
    5586                 :       case PNK_LB:
    5587             459 :         if (!EmitElemIncDec(cx, pn2, op, bce))
    5588               0 :             return false;
    5589             459 :         break;
    5590                 :       case PNK_LP:
    5591              18 :         if (!EmitTree(cx, bce, pn2))
    5592               0 :             return false;
    5593              18 :         if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pn2->pn_offset) < 0)
    5594               0 :             return false;
    5595              18 :         if (Emit1(cx, bce, op) < 0)
    5596               0 :             return false;
    5597                 :         /*
    5598                 :          * This is dead code for the decompiler, don't generate
    5599                 :          * a decomposed version of the opcode. We do need to balance
    5600                 :          * the stacks in the decomposed version.
    5601                 :          */
    5602              18 :         JS_ASSERT(js_CodeSpec[op].format & JOF_DECOMPOSE);
    5603              18 :         JS_ASSERT(js_CodeSpec[op].format & JOF_ELEM);
    5604              18 :         if (Emit1(cx, bce, (JSOp)1) < 0)
    5605               0 :             return false;
    5606              18 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    5607               0 :             return false;
    5608              18 :         break;
    5609                 : #if JS_HAS_XML_SUPPORT
    5610                 :       case PNK_XMLUNARY:
    5611               9 :         JS_ASSERT(!bce->inStrictMode());
    5612               9 :         JS_ASSERT(pn2->isOp(JSOP_SETXMLNAME));
    5613               9 :         if (!EmitTree(cx, bce, pn2->pn_kid))
    5614               0 :             return false;
    5615               9 :         if (Emit1(cx, bce, JSOP_BINDXMLNAME) < 0)
    5616               0 :             return false;
    5617               9 :         if (!EmitElemIncDec(cx, NULL, op, bce))
    5618               0 :             return false;
    5619               9 :         break;
    5620                 : #endif
    5621                 :       default:
    5622           29024 :         JS_ASSERT(pn2->isKind(PNK_NAME));
    5623           29024 :         pn2->setOp(op);
    5624           29024 :         if (!BindNameToSlot(cx, bce, pn2))
    5625               0 :             return false;
    5626           29024 :         op = pn2->getOp();
    5627           29024 :         if (op == JSOP_CALLEE) {
    5628               0 :             if (Emit1(cx, bce, op) < 0)
    5629               0 :                 return false;
    5630           29024 :         } else if (!pn2->pn_cookie.isFree()) {
    5631           21623 :             EMIT_UINT16_IMM_OP(op, pn2->pn_cookie.slot());
    5632                 :         } else {
    5633            7401 :             JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
    5634            7401 :             if (js_CodeSpec[op].format & (JOF_INC | JOF_DEC)) {
    5635            7392 :                 if (!EmitNameIncDec(cx, pn2, op, bce))
    5636               0 :                     return false;
    5637                 :             } else {
    5638               9 :                 if (!EmitAtomOp(cx, pn2, op, bce))
    5639               0 :                     return false;
    5640                 :             }
    5641            7401 :             break;
    5642                 :         }
    5643           21623 :         if (pn2->isConst()) {
    5644               0 :             if (Emit1(cx, bce, JSOP_POS) < 0)
    5645               0 :                 return false;
    5646               0 :             op = pn->getOp();
    5647               0 :             if (!(js_CodeSpec[op].format & JOF_POST)) {
    5648               0 :                 if (Emit1(cx, bce, JSOP_ONE) < 0)
    5649               0 :                     return false;
    5650               0 :                 op = (js_CodeSpec[op].format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
    5651               0 :                 if (Emit1(cx, bce, op) < 0)
    5652               0 :                     return false;
    5653                 :             }
    5654                 :         }
    5655                 :     }
    5656           29933 :     return true;
    5657                 : }
    5658                 : 
    5659                 : /*
    5660                 :  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr12127. See
    5661                 :  * the comment on EmitSwitch.
    5662                 :  */
    5663                 : MOZ_NEVER_INLINE static bool
    5664             189 : EmitLabel(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5665                 : {
    5666                 :     /*
    5667                 :      * Emit a JSOP_LABEL instruction. The argument is the offset to the statement
    5668                 :      * following the labeled statement. This op has either a SRC_LABEL or
    5669                 :      * SRC_LABELBRACE source note for the decompiler.
    5670                 :      */
    5671             189 :     JSAtom *atom = pn->pn_atom;
    5672                 : 
    5673                 :     jsatomid index;
    5674             189 :     if (!bce->makeAtomIndex(atom, &index))
    5675               0 :         return false;
    5676                 : 
    5677             189 :     ParseNode *pn2 = pn->expr();
    5678             189 :     SrcNoteType noteType = (pn2->isKind(PNK_STATEMENTLIST) ||
    5679             189 :                             (pn2->isKind(PNK_LEXICALSCOPE) &&
    5680               0 :                              pn2->expr()->isKind(PNK_STATEMENTLIST)))
    5681                 :                            ? SRC_LABELBRACE
    5682             378 :                            : SRC_LABEL;
    5683             189 :     ptrdiff_t noteIndex = NewSrcNote2(cx, bce, noteType, ptrdiff_t(index));
    5684             189 :     if (noteIndex < 0)
    5685               0 :         return false;
    5686                 : 
    5687             189 :     ptrdiff_t top = EmitJump(cx, bce, JSOP_LABEL, 0);
    5688             189 :     if (top < 0)
    5689               0 :         return false;
    5690                 : 
    5691                 :     /* Emit code for the labeled statement. */
    5692                 :     StmtInfo stmtInfo;
    5693             189 :     PushStatement(bce, &stmtInfo, STMT_LABEL, bce->offset());
    5694             189 :     stmtInfo.label = atom;
    5695             189 :     if (!EmitTree(cx, bce, pn2))
    5696               0 :         return false;
    5697             189 :     if (!PopStatementBCE(cx, bce))
    5698               0 :         return false;
    5699                 : 
    5700                 :     /* Patch the JSOP_LABEL offset. */
    5701             189 :     SetJumpOffsetAt(bce, top);
    5702                 : 
    5703                 :     /* If the statement was compound, emit a note for the end brace. */
    5704             189 :     if (noteType == SRC_LABELBRACE) {
    5705               0 :         if (NewSrcNote(cx, bce, SRC_ENDBRACE) < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
    5706               0 :             return false;
    5707                 :     }
    5708                 : 
    5709             189 :     return true;
    5710                 : }
    5711                 : 
    5712                 : static bool
    5713              36 : EmitSyntheticStatements(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    5714                 : {
    5715              36 :     JS_ASSERT(pn->isArity(PN_LIST));
    5716                 :     StmtInfo stmtInfo;
    5717              36 :     PushStatement(bce, &stmtInfo, STMT_SEQ, top);
    5718             108 :     for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    5719              72 :         if (!EmitTree(cx, bce, pn2))
    5720               0 :             return false;
    5721                 :     }
    5722              36 :     return PopStatementBCE(cx, bce);
    5723                 : }
    5724                 : 
    5725                 : static bool
    5726            6635 : EmitConditionalExpression(JSContext *cx, BytecodeEmitter *bce, ConditionalExpression &conditional)
    5727                 : {
    5728                 :     /* Emit the condition, then branch if false to the else part. */
    5729            6635 :     if (!EmitTree(cx, bce, &conditional.condition()))
    5730               0 :         return false;
    5731            6635 :     ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_COND);
    5732            6635 :     if (noteIndex < 0)
    5733               0 :         return false;
    5734            6635 :     ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFEQ, 0);
    5735            6635 :     if (beq < 0 || !EmitTree(cx, bce, &conditional.thenExpression()))
    5736               0 :         return false;
    5737                 : 
    5738                 :     /* Jump around else, fixup the branch, emit else, fixup jump. */
    5739            6635 :     ptrdiff_t jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
    5740            6635 :     if (jmp < 0)
    5741               0 :         return false;
    5742            6635 :     SetJumpOffsetAt(bce, beq);
    5743                 : 
    5744                 :     /*
    5745                 :      * Because each branch pushes a single value, but our stack budgeting
    5746                 :      * analysis ignores branches, we now have to adjust bce->stackDepth to
    5747                 :      * ignore the value pushed by the first branch.  Execution will follow
    5748                 :      * only one path, so we must decrement bce->stackDepth.
    5749                 :      *
    5750                 :      * Failing to do this will foil code, such as let expression and block
    5751                 :      * code generation, which must use the stack depth to compute local
    5752                 :      * stack indexes correctly.
    5753                 :      */
    5754            6635 :     JS_ASSERT(bce->stackDepth > 0);
    5755            6635 :     bce->stackDepth--;
    5756            6635 :     if (!EmitTree(cx, bce, &conditional.elseExpression()))
    5757               0 :         return false;
    5758            6635 :     SetJumpOffsetAt(bce, jmp);
    5759            6635 :     return SetSrcNoteOffset(cx, bce, noteIndex, 0, jmp - beq);
    5760                 : }
    5761                 : 
    5762                 : static bool
    5763           13554 : EmitObject(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5764                 : {
    5765                 : #if JS_HAS_DESTRUCTURING_SHORTHAND
    5766           13554 :     if (pn->pn_xflags & PNX_DESTRUCT) {
    5767                 :         ReportCompileErrorNumber(cx, bce->tokenStream(), pn, JSREPORT_ERROR,
    5768               0 :                                  JSMSG_BAD_OBJECT_INIT);
    5769               0 :         return false;
    5770                 :     }
    5771                 : #endif
    5772                 : 
    5773           13554 :     if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && bce->checkSingletonContext())
    5774            1984 :         return EmitSingletonInitialiser(cx, bce, pn);
    5775                 : 
    5776                 :     /*
    5777                 :      * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
    5778                 :      * a new object and in source order evaluating each property value and
    5779                 :      * adding the property to the object, without invoking latent setters.
    5780                 :      * We use the JSOP_NEWINIT and JSOP_INITELEM/JSOP_INITPROP bytecodes to
    5781                 :      * ignore setters and to avoid dup'ing and popping the object as each
    5782                 :      * property is added, as JSOP_SETELEM/JSOP_SETPROP would do.
    5783                 :      */
    5784           11570 :     ptrdiff_t offset = bce->next() - bce->base();
    5785           11570 :     if (!EmitNewInit(cx, bce, JSProto_Object, pn))
    5786               0 :         return false;
    5787                 : 
    5788                 :     /*
    5789                 :      * Try to construct the shape of the object as we go, so we can emit a
    5790                 :      * JSOP_NEWOBJECT with the final shape instead.
    5791                 :      */
    5792           11570 :     JSObject *obj = NULL;
    5793           11570 :     if (bce->compileAndGo()) {
    5794           10813 :         gc::AllocKind kind = GuessObjectGCKind(pn->pn_count);
    5795           10813 :         obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
    5796           10813 :         if (!obj)
    5797               0 :             return false;
    5798                 :     }
    5799                 : 
    5800           29335 :     for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    5801                 :         /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
    5802           17765 :         ParseNode *pn3 = pn2->pn_left;
    5803           17765 :         if (pn3->isKind(PNK_NUMBER)) {
    5804             729 :             if (!EmitNumberOp(cx, pn3->pn_dval, bce))
    5805               0 :                 return false;
    5806                 :         }
    5807                 : 
    5808                 :         /* Emit code for the property initializer. */
    5809           17765 :         if (!EmitTree(cx, bce, pn2->pn_right))
    5810               0 :             return false;
    5811                 : 
    5812           17765 :         JSOp op = pn2->getOp();
    5813           17765 :         if (op == JSOP_GETTER || op == JSOP_SETTER) {
    5814             297 :             obj = NULL;
    5815             297 :             if (Emit1(cx, bce, op) < 0)
    5816               0 :                 return false;
    5817                 :         }
    5818                 : 
    5819                 :         /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */
    5820           17765 :         if (pn3->isKind(PNK_NUMBER)) {
    5821             729 :             obj = NULL;
    5822             729 :             if (NewSrcNote(cx, bce, SRC_INITPROP) < 0)
    5823               0 :                 return false;
    5824             729 :             if (Emit1(cx, bce, JSOP_INITELEM) < 0)
    5825               0 :                 return false;
    5826                 :         } else {
    5827           17036 :             JS_ASSERT(pn3->isKind(PNK_NAME) || pn3->isKind(PNK_STRING));
    5828                 :             jsatomid index;
    5829           17036 :             if (!bce->makeAtomIndex(pn3->pn_atom, &index))
    5830               0 :                 return false;
    5831                 : 
    5832                 :             /*
    5833                 :              * Disable NEWOBJECT on initializers that set __proto__, which has
    5834                 :              * a non-standard setter on objects.
    5835                 :              */
    5836           17036 :             if (pn3->pn_atom == cx->runtime->atomState.protoAtom)
    5837              54 :                 obj = NULL;
    5838           17036 :             op = JSOP_INITPROP;
    5839                 : 
    5840           17036 :             if (obj) {
    5841           12535 :                 JS_ASSERT(!obj->inDictionaryMode());
    5842           25070 :                 if (!DefineNativeProperty(cx, obj, ATOM_TO_JSID(pn3->pn_atom),
    5843                 :                                           UndefinedValue(), NULL, NULL,
    5844           25070 :                                           JSPROP_ENUMERATE, 0, 0))
    5845                 :                 {
    5846               0 :                     return false;
    5847                 :                 }
    5848           12535 :                 if (obj->inDictionaryMode())
    5849               0 :                     obj = NULL;
    5850                 :             }
    5851                 : 
    5852           17036 :             if (!EmitIndex32(cx, op, index, bce))
    5853               0 :                 return false;
    5854                 :         }
    5855                 :     }
    5856                 : 
    5857           11570 :     if (Emit1(cx, bce, JSOP_ENDINIT) < 0)
    5858               0 :         return false;
    5859                 : 
    5860           11570 :     if (obj) {
    5861                 :         /*
    5862                 :          * The object survived and has a predictable shape: update the original
    5863                 :          * bytecode.
    5864                 :          */
    5865           10147 :         ObjectBox *objbox = bce->parser->newObjectBox(obj);
    5866           10147 :         if (!objbox)
    5867               0 :             return false;
    5868           10147 :         unsigned index = bce->objectList.index(objbox);
    5869                 :         MOZ_STATIC_ASSERT(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
    5870                 :                           "newinit and newobject must have equal length to edit in-place");
    5871           10147 :         EMIT_UINT32_IN_PLACE(offset, JSOP_NEWOBJECT, uint32_t(index));
    5872                 :     }
    5873                 : 
    5874           11570 :     return true;
    5875                 : }
    5876                 : 
    5877                 : static bool
    5878           15703 : EmitArray(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5879                 : {
    5880                 :     /*
    5881                 :      * Emit code for [a, b, c] that is equivalent to constructing a new
    5882                 :      * array and in source order evaluating each element value and adding
    5883                 :      * it to the array, without invoking latent setters.  We use the
    5884                 :      * JSOP_NEWINIT and JSOP_INITELEM bytecodes to ignore setters and to
    5885                 :      * avoid dup'ing and popping the array as each element is added, as
    5886                 :      * JSOP_SETELEM/JSOP_SETPROP would do.
    5887                 :      */
    5888                 : 
    5889                 : #if JS_HAS_GENERATORS
    5890           15703 :     if (pn->isKind(PNK_ARRAYCOMP)) {
    5891             270 :         if (!EmitNewInit(cx, bce, JSProto_Array, pn))
    5892               0 :             return false;
    5893                 : 
    5894                 :         /*
    5895                 :          * Pass the new array's stack index to the PNK_ARRAYPUSH case via
    5896                 :          * bce->arrayCompDepth, then simply traverse the PNK_FOR node and
    5897                 :          * its kids under pn2 to generate this comprehension.
    5898                 :          */
    5899             270 :         JS_ASSERT(bce->stackDepth > 0);
    5900             270 :         unsigned saveDepth = bce->arrayCompDepth;
    5901             270 :         bce->arrayCompDepth = (uint32_t) (bce->stackDepth - 1);
    5902             270 :         if (!EmitTree(cx, bce, pn->pn_head))
    5903               0 :             return false;
    5904             270 :         bce->arrayCompDepth = saveDepth;
    5905                 : 
    5906                 :         /* Emit the usual op needed for decompilation. */
    5907             270 :         return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
    5908                 :     }
    5909                 : #endif /* JS_HAS_GENERATORS */
    5910                 : 
    5911           15433 :     if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && bce->checkSingletonContext())
    5912            2916 :         return EmitSingletonInitialiser(cx, bce, pn);
    5913                 : 
    5914           12517 :     ptrdiff_t off = EmitN(cx, bce, JSOP_NEWARRAY, 3);
    5915           12517 :     if (off < 0)
    5916               0 :         return false;
    5917           12517 :     CheckTypeSet(cx, bce, JSOP_NEWARRAY);
    5918           12517 :     jsbytecode *pc = bce->code(off);
    5919           12517 :     SET_UINT24(pc, pn->pn_count);
    5920                 : 
    5921           12517 :     ParseNode *pn2 = pn->pn_head;
    5922                 :     jsatomid atomIndex;
    5923           51824 :     for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
    5924           39307 :         if (!EmitNumberOp(cx, atomIndex, bce))
    5925               0 :             return false;
    5926           39307 :         if (pn2->isKind(PNK_COMMA) && pn2->isArity(PN_NULLARY)) {
    5927            4887 :             if (Emit1(cx, bce, JSOP_HOLE) < 0)
    5928               0 :                 return false;
    5929                 :         } else {
    5930           34420 :             if (!EmitTree(cx, bce, pn2))
    5931               0 :                 return false;
    5932                 :         }
    5933           39307 :         if (Emit1(cx, bce, JSOP_INITELEM) < 0)
    5934               0 :             return false;
    5935                 :     }
    5936           12517 :     JS_ASSERT(atomIndex == pn->pn_count);
    5937                 : 
    5938           12517 :     if (pn->pn_xflags & PNX_ENDCOMMA) {
    5939                 :         /* Emit a source note so we know to decompile an extra comma. */
    5940             252 :         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
    5941               0 :             return false;
    5942                 :     }
    5943                 : 
    5944                 :     /* Emit an op to finish the array and aid in decompilation. */
    5945           12517 :     return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
    5946                 : }
    5947                 : 
    5948                 : static bool
    5949           89136 : EmitUnary(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5950                 : {
    5951                 :     /* Unary op, including unary +/-. */
    5952           89136 :     JSOp op = pn->getOp();
    5953           89136 :     ParseNode *pn2 = pn->pn_kid;
    5954                 : 
    5955           89136 :     JS_ASSERT(op != JSOP_XMLNAME);
    5956           89136 :     if (op == JSOP_TYPEOF && !pn2->isKind(PNK_NAME))
    5957               0 :         op = JSOP_TYPEOFEXPR;
    5958                 : 
    5959           89136 :     unsigned oldflags = bce->flags;
    5960           89136 :     bce->flags &= ~TCF_IN_FOR_INIT;
    5961           89136 :     if (!EmitTree(cx, bce, pn2))
    5962               0 :         return false;
    5963                 : 
    5964           89136 :     bce->flags |= oldflags & TCF_IN_FOR_INIT;
    5965           89136 :     return Emit1(cx, bce, op) >= 0;
    5966                 : }
    5967                 : 
    5968                 : JSBool
    5969         5657896 : frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5970                 : {
    5971         5657896 :     JS_CHECK_RECURSION(cx, return JS_FALSE);
    5972                 : 
    5973        11315792 :     EmitLevelManager elm(bce);
    5974                 : 
    5975         5657896 :     JSBool ok = true;
    5976         5657896 :     ptrdiff_t top = bce->offset();
    5977         5657896 :     pn->pn_offset = top;
    5978                 : 
    5979                 :     /* Emit notes to tell the current bytecode's source line number. */
    5980         5657896 :     UPDATE_LINE_NUMBER_NOTES(cx, bce, pn->pn_pos.begin.lineno);
    5981                 : 
    5982         5657896 :     switch (pn->getKind()) {
    5983                 :       case PNK_FUNCTION:
    5984          157939 :         ok = EmitFunc(cx, bce, pn);
    5985          157939 :         break;
    5986                 : 
    5987                 :       case PNK_ARGSBODY:
    5988                 :       {
    5989           57623 :         ParseNode *pnlast = pn->last();
    5990          282150 :         for (ParseNode *pn2 = pn->pn_head; pn2 != pnlast; pn2 = pn2->pn_next) {
    5991          224527 :             if (!pn2->isDefn())
    5992              18 :                 continue;
    5993          224509 :             if (!BindNameToSlot(cx, bce, pn2))
    5994               0 :                 return JS_FALSE;
    5995          224509 :             if (JOF_OPTYPE(pn2->getOp()) == JOF_QARG && bce->shouldNoteClosedName(pn2)) {
    5996            1711 :                 if (!bce->closedArgs.append(pn2->pn_cookie.slot()))
    5997               0 :                     return JS_FALSE;
    5998                 :             }
    5999                 :         }
    6000           57623 :         ok = EmitTree(cx, bce, pnlast);
    6001           57623 :         break;
    6002                 :       }
    6003                 : 
    6004                 :       case PNK_UPVARS:
    6005           60628 :         JS_ASSERT(pn->pn_names->count() != 0);
    6006           60628 :         bce->roLexdeps = pn->pn_names;
    6007           60628 :         ok = EmitTree(cx, bce, pn->pn_tree);
    6008           60628 :         bce->roLexdeps.clearMap();
    6009           60628 :         pn->pn_names.releaseMap(cx);
    6010           60628 :         break;
    6011                 : 
    6012                 :       case PNK_IF:
    6013           92057 :         ok = EmitIf(cx, bce, pn);
    6014           92057 :         break;
    6015                 : 
    6016                 :       case PNK_SWITCH:
    6017             873 :         ok = EmitSwitch(cx, bce, pn);
    6018             873 :         break;
    6019                 : 
    6020                 :       case PNK_WHILE:
    6021            2127 :         ok = EmitWhile(cx, bce, pn, top);
    6022            2127 :         break;
    6023                 : 
    6024                 :       case PNK_DOWHILE:
    6025             189 :         ok = EmitDo(cx, bce, pn);
    6026             189 :         break;
    6027                 : 
    6028                 :       case PNK_FOR:
    6029           29569 :         ok = EmitFor(cx, bce, pn, top);
    6030           29569 :         break;
    6031                 : 
    6032                 :       case PNK_BREAK:
    6033            1656 :         ok = EmitBreak(cx, bce, pn->asBreakStatement().label());
    6034            1656 :         break;
    6035                 : 
    6036                 :       case PNK_CONTINUE:
    6037             153 :         ok = EmitContinue(cx, bce, pn->asContinueStatement().label());
    6038             153 :         break;
    6039                 : 
    6040                 :       case PNK_WITH:
    6041             648 :         ok = EmitWith(cx, bce, pn);
    6042             648 :         break;
    6043                 : 
    6044                 :       case PNK_TRY:
    6045           87120 :         if (!EmitTry(cx, bce, pn))
    6046               0 :             return false;
    6047           87120 :         break;
    6048                 : 
    6049                 :       case PNK_CATCH:
    6050           86985 :         if (!EmitCatch(cx, bce, pn))
    6051               0 :             return false;
    6052           86985 :         break;
    6053                 : 
    6054                 :       case PNK_VAR:
    6055                 :       case PNK_CONST:
    6056          148110 :         if (!EmitVariables(cx, bce, pn, InitializeVars))
    6057               0 :             return JS_FALSE;
    6058          148110 :         break;
    6059                 : 
    6060                 :       case PNK_RETURN:
    6061           37782 :         ok = EmitReturn(cx, bce, pn);
    6062           37782 :         break;
    6063                 : 
    6064                 : #if JS_HAS_GENERATORS
    6065                 :       case PNK_YIELD:
    6066             720 :         JS_ASSERT(bce->inFunction());
    6067             720 :         if (pn->pn_kid) {
    6068             567 :             if (!EmitTree(cx, bce, pn->pn_kid))
    6069               0 :                 return JS_FALSE;
    6070                 :         } else {
    6071             153 :             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    6072               0 :                 return JS_FALSE;
    6073                 :         }
    6074             720 :         if (pn->pn_hidden && NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
    6075               0 :             return JS_FALSE;
    6076             720 :         if (Emit1(cx, bce, JSOP_YIELD) < 0)
    6077               0 :             return JS_FALSE;
    6078             720 :         break;
    6079                 : #endif
    6080                 : 
    6081                 : #if JS_HAS_XML_SUPPORT
    6082                 :       case PNK_XMLCURLYEXPR:
    6083               0 :         JS_ASSERT(pn->isArity(PN_UNARY));
    6084               0 :         if (!EmitTree(cx, bce, pn->pn_kid))
    6085               0 :             return JS_FALSE;
    6086               0 :         if (Emit1(cx, bce, pn->getOp()) < 0)
    6087               0 :             return JS_FALSE;
    6088               0 :         break;
    6089                 : #endif
    6090                 : 
    6091                 :       case PNK_STATEMENTLIST:
    6092          440408 :         ok = EmitStatementList(cx, bce, pn, top);
    6093          440408 :         break;
    6094                 : 
    6095                 :       case PNK_SEQ:
    6096              36 :         ok = EmitSyntheticStatements(cx, bce, pn, top);
    6097              36 :         break;
    6098                 : 
    6099                 :       case PNK_SEMI:
    6100          556399 :         ok = EmitStatement(cx, bce, pn);
    6101          556399 :         break;
    6102                 : 
    6103                 :       case PNK_COLON:
    6104             189 :         ok = EmitLabel(cx, bce, pn);
    6105             189 :         break;
    6106                 : 
    6107                 :       case PNK_COMMA:
    6108                 :       {
    6109                 :         /*
    6110                 :          * Emit SRC_PCDELTA notes on each JSOP_POP between comma operands.
    6111                 :          * These notes help the decompiler bracket the bytecodes generated
    6112                 :          * from each sub-expression that follows a comma.
    6113                 :          */
    6114            1116 :         ptrdiff_t off = -1, noteIndex = -1;
    6115            2916 :         for (ParseNode *pn2 = pn->pn_head; ; pn2 = pn2->pn_next) {
    6116            2916 :             if (!EmitTree(cx, bce, pn2))
    6117               0 :                 return JS_FALSE;
    6118            2916 :             ptrdiff_t tmp = bce->offset();
    6119            2916 :             if (noteIndex >= 0) {
    6120            1800 :                 if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, tmp-off))
    6121               0 :                     return JS_FALSE;
    6122                 :             }
    6123            2916 :             if (!pn2->pn_next)
    6124                 :                 break;
    6125            1800 :             off = tmp;
    6126            1800 :             noteIndex = NewSrcNote2(cx, bce, SRC_PCDELTA, 0);
    6127            3600 :             if (noteIndex < 0 ||
    6128            1800 :                 Emit1(cx, bce, JSOP_POP) < 0) {
    6129               0 :                 return JS_FALSE;
    6130                 :             }
    6131                 :         }
    6132            1116 :         break;
    6133                 :       }
    6134                 : 
    6135                 :       case PNK_ASSIGN:
    6136                 :       case PNK_ADDASSIGN:
    6137                 :       case PNK_SUBASSIGN:
    6138                 :       case PNK_BITORASSIGN:
    6139                 :       case PNK_BITXORASSIGN:
    6140                 :       case PNK_BITANDASSIGN:
    6141                 :       case PNK_LSHASSIGN:
    6142                 :       case PNK_RSHASSIGN:
    6143                 :       case PNK_URSHASSIGN:
    6144                 :       case PNK_MULASSIGN:
    6145                 :       case PNK_DIVASSIGN:
    6146                 :       case PNK_MODASSIGN:
    6147          401666 :         if (!EmitAssignment(cx, bce, pn->pn_left, pn->getOp(), pn->pn_right))
    6148               0 :             return false;
    6149          401666 :         break;
    6150                 : 
    6151                 :       case PNK_CONDITIONAL:
    6152            6635 :         ok = EmitConditionalExpression(cx, bce, pn->asConditionalExpression());
    6153            6635 :         break;
    6154                 : 
    6155                 :       case PNK_OR:
    6156                 :       case PNK_AND:
    6157            6453 :         ok = EmitLogical(cx, bce, pn);
    6158            6453 :         break;
    6159                 : 
    6160                 :       case PNK_ADD:
    6161                 :       case PNK_SUB:
    6162                 :       case PNK_BITOR:
    6163                 :       case PNK_BITXOR:
    6164                 :       case PNK_BITAND:
    6165                 :       case PNK_STRICTEQ:
    6166                 :       case PNK_EQ:
    6167                 :       case PNK_STRICTNE:
    6168                 :       case PNK_NE:
    6169                 :       case PNK_LT:
    6170                 :       case PNK_LE:
    6171                 :       case PNK_GT:
    6172                 :       case PNK_GE:
    6173                 :       case PNK_IN:
    6174                 :       case PNK_INSTANCEOF:
    6175                 :       case PNK_LSH:
    6176                 :       case PNK_RSH:
    6177                 :       case PNK_URSH:
    6178                 :       case PNK_STAR:
    6179                 :       case PNK_DIV:
    6180                 :       case PNK_MOD:
    6181          197898 :         if (pn->isArity(PN_LIST)) {
    6182                 :             /* Left-associative operator chain: avoid too much recursion. */
    6183            5695 :             ParseNode *pn2 = pn->pn_head;
    6184            5695 :             if (!EmitTree(cx, bce, pn2))
    6185               0 :                 return JS_FALSE;
    6186            5695 :             JSOp op = pn->getOp();
    6187            5695 :             while ((pn2 = pn2->pn_next) != NULL) {
    6188         1489820 :                 if (!EmitTree(cx, bce, pn2))
    6189               0 :                     return JS_FALSE;
    6190         1489820 :                 if (Emit1(cx, bce, op) < 0)
    6191               0 :                     return JS_FALSE;
    6192                 :             }
    6193                 :         } else {
    6194                 : #if JS_HAS_XML_SUPPORT
    6195                 :             unsigned oldflags;
    6196                 : 
    6197                 :       case PNK_DBLCOLON:
    6198          192275 :             JS_ASSERT(pn->getOp() != JSOP_XMLNAME);
    6199          192275 :             if (pn->isArity(PN_NAME)) {
    6200              72 :                 if (!EmitTree(cx, bce, pn->expr()))
    6201               0 :                     return JS_FALSE;
    6202              72 :                 if (!EmitAtomOp(cx, pn, pn->getOp(), bce))
    6203               0 :                     return JS_FALSE;
    6204              72 :                 break;
    6205                 :             }
    6206                 : 
    6207                 :             /*
    6208                 :              * Binary :: has a right operand that brackets arbitrary code,
    6209                 :              * possibly including a let (a = b) ... expression.  We must clear
    6210                 :              * TCF_IN_FOR_INIT to avoid mis-compiling such beasts.
    6211                 :              */
    6212          192203 :             oldflags = bce->flags;
    6213          192203 :             bce->flags &= ~TCF_IN_FOR_INIT;
    6214                 : #endif
    6215                 : 
    6216                 :             /* Binary operators that evaluate both operands unconditionally. */
    6217          192203 :             if (!EmitTree(cx, bce, pn->pn_left))
    6218               0 :                 return JS_FALSE;
    6219          192203 :             if (!EmitTree(cx, bce, pn->pn_right))
    6220               0 :                 return JS_FALSE;
    6221                 : #if JS_HAS_XML_SUPPORT
    6222          192203 :             bce->flags |= oldflags & TCF_IN_FOR_INIT;
    6223                 : #endif
    6224          192203 :             if (Emit1(cx, bce, pn->getOp()) < 0)
    6225               0 :                 return JS_FALSE;
    6226                 :         }
    6227          197898 :         break;
    6228                 : 
    6229                 : #if JS_HAS_XML_SUPPORT
    6230                 :       case PNK_XMLUNARY:
    6231              54 :         if (pn->getOp() == JSOP_XMLNAME) {
    6232              54 :             if (!EmitXMLName(cx, pn, JSOP_XMLNAME, bce))
    6233               0 :                 return false;
    6234                 :         } else {
    6235               0 :             JSOp op = pn->getOp();
    6236               0 :             JS_ASSERT(op == JSOP_BINDXMLNAME || op == JSOP_SETXMLNAME);
    6237               0 :             unsigned oldflags = bce->flags;
    6238               0 :             bce->flags &= ~TCF_IN_FOR_INIT;
    6239               0 :             if (!EmitTree(cx, bce, pn->pn_kid))
    6240               0 :                 return false;
    6241               0 :             bce->flags |= oldflags & TCF_IN_FOR_INIT;
    6242               0 :             if (Emit1(cx, bce, op) < 0)
    6243               0 :                 return false;
    6244                 :         }
    6245              54 :         break;
    6246                 : #endif
    6247                 : 
    6248                 :       case PNK_THROW:
    6249                 : #if JS_HAS_XML_SUPPORT
    6250                 :       case PNK_AT:
    6251                 :       case PNK_DEFXMLNS:
    6252            2878 :         JS_ASSERT(pn->isArity(PN_UNARY));
    6253                 :         /* FALL THROUGH */
    6254                 : #endif
    6255                 :       case PNK_TYPEOF:
    6256                 :       case PNK_VOID:
    6257                 :       case PNK_NOT:
    6258                 :       case PNK_BITNOT:
    6259                 :       case PNK_POS:
    6260                 :       case PNK_NEG:
    6261           89136 :         ok = EmitUnary(cx, bce, pn);
    6262           89136 :         break;
    6263                 : 
    6264                 :       case PNK_PREINCREMENT:
    6265                 :       case PNK_PREDECREMENT:
    6266                 :       case PNK_POSTINCREMENT:
    6267                 :       case PNK_POSTDECREMENT:
    6268           29933 :         ok = EmitIncOrDec(cx, bce, pn);
    6269           29933 :         break;
    6270                 : 
    6271                 :       case PNK_DELETE:
    6272            1260 :         ok = EmitDelete(cx, bce, pn);
    6273            1260 :         break;
    6274                 : 
    6275                 : #if JS_HAS_XML_SUPPORT
    6276                 :       case PNK_FILTER:
    6277                 :       {
    6278              72 :         JS_ASSERT(!bce->inStrictMode());
    6279                 : 
    6280              72 :         if (!EmitTree(cx, bce, pn->pn_left))
    6281               0 :             return JS_FALSE;
    6282              72 :         ptrdiff_t jmp = EmitJump(cx, bce, JSOP_FILTER, 0);
    6283              72 :         if (jmp < 0)
    6284               0 :             return JS_FALSE;
    6285              72 :         top = EmitLoopHead(cx, bce, pn->pn_right);
    6286              72 :         if (top < 0)
    6287               0 :             return JS_FALSE;
    6288              72 :         if (!EmitTree(cx, bce, pn->pn_right))
    6289               0 :             return JS_FALSE;
    6290              72 :         SetJumpOffsetAt(bce, jmp);
    6291              72 :         if (!EmitLoopEntry(cx, bce, NULL))
    6292               0 :             return false;
    6293              72 :         if (EmitJump(cx, bce, JSOP_ENDFILTER, top - bce->offset()) < 0)
    6294               0 :             return JS_FALSE;
    6295              72 :         break;
    6296                 :       }
    6297                 : #endif
    6298                 : 
    6299                 :       case PNK_DOT:
    6300                 :         /*
    6301                 :          * Pop a stack operand, convert it to object, get a property named by
    6302                 :          * this bytecode's immediate-indexed atom operand, and push its value
    6303                 :          * (not a reference to it).
    6304                 :          */
    6305           51691 :         ok = EmitPropOp(cx, pn, pn->getOp(), bce, JS_FALSE);
    6306           51691 :         break;
    6307                 : 
    6308                 : #if JS_HAS_XML_SUPPORT
    6309                 :       case PNK_DBLDOT:
    6310               9 :         JS_ASSERT(!bce->inStrictMode());
    6311                 :         /* FALL THROUGH */
    6312                 : #endif
    6313                 :       case PNK_LB:
    6314                 :         /*
    6315                 :          * Pop two operands, convert the left one to object and the right one
    6316                 :          * to property name (atom or tagged int), get the named property, and
    6317                 :          * push its value.  Set the "obj" register to the result of ToObject
    6318                 :          * on the left operand.
    6319                 :          */
    6320           35570 :         ok = EmitElemOp(cx, pn, pn->getOp(), bce);
    6321           35570 :         break;
    6322                 : 
    6323                 :       case PNK_NEW:
    6324                 :       case PNK_LP:
    6325          225006 :         ok = EmitCallOrNew(cx, bce, pn, top);
    6326          225006 :         break;
    6327                 : 
    6328                 :       case PNK_LEXICALSCOPE:
    6329           88677 :         ok = EmitLexicalScope(cx, bce, pn);
    6330           88677 :         break;
    6331                 : 
    6332                 : #if JS_HAS_BLOCK_SCOPE
    6333                 :       case PNK_LET:
    6334            9955 :         ok = pn->isArity(PN_BINARY)
    6335            8416 :              ? EmitLet(cx, bce, pn)
    6336           18371 :              : EmitVariables(cx, bce, pn, InitializeVars);
    6337            9955 :         break;
    6338                 : #endif /* JS_HAS_BLOCK_SCOPE */
    6339                 : #if JS_HAS_GENERATORS
    6340                 :       case PNK_ARRAYPUSH: {
    6341                 :         int slot;
    6342                 : 
    6343                 :         /*
    6344                 :          * The array object's stack index is in bce->arrayCompDepth. See below
    6345                 :          * under the array initialiser code generator for array comprehension
    6346                 :          * special casing.
    6347                 :          */
    6348             270 :         if (!EmitTree(cx, bce, pn->pn_kid))
    6349               0 :             return JS_FALSE;
    6350             270 :         slot = AdjustBlockSlot(cx, bce, bce->arrayCompDepth);
    6351             270 :         if (slot < 0)
    6352               0 :             return JS_FALSE;
    6353             270 :         EMIT_UINT16_IMM_OP(pn->getOp(), slot);
    6354             270 :         break;
    6355                 :       }
    6356                 : #endif
    6357                 : 
    6358                 :       case PNK_RB:
    6359                 : #if JS_HAS_GENERATORS
    6360                 :       case PNK_ARRAYCOMP:
    6361                 : #endif
    6362           15703 :         ok = EmitArray(cx, bce, pn);
    6363           15703 :         break;
    6364                 : 
    6365                 :       case PNK_RC:
    6366           13554 :         ok = EmitObject(cx, bce, pn);
    6367           13554 :         break;
    6368                 : 
    6369                 :       case PNK_NAME:
    6370                 :         /*
    6371                 :          * Cope with a left-over function definition that was replaced by a use
    6372                 :          * of a later function definition of the same name. See FunctionDef and
    6373                 :          * MakeDefIntoUse in Parser.cpp.
    6374                 :          */
    6375         1927025 :         if (pn->isOp(JSOP_NOP))
    6376               0 :             break;
    6377         1927025 :         if (!EmitNameOp(cx, bce, pn, JS_FALSE))
    6378               0 :             return JS_FALSE;
    6379         1927025 :         break;
    6380                 : 
    6381                 : #if JS_HAS_XML_SUPPORT
    6382                 :       case PNK_XMLATTR:
    6383                 :       case PNK_XMLSPACE:
    6384                 :       case PNK_XMLTEXT:
    6385                 :       case PNK_XMLCDATA:
    6386                 :       case PNK_XMLCOMMENT:
    6387             334 :         JS_ASSERT(!bce->inStrictMode());
    6388                 :         /* FALL THROUGH */
    6389                 : #endif
    6390                 :       case PNK_STRING:
    6391          279796 :         ok = EmitAtomOp(cx, pn, pn->getOp(), bce);
    6392          279796 :         break;
    6393                 : 
    6394                 :       case PNK_NUMBER:
    6395          381323 :         ok = EmitNumberOp(cx, pn->pn_dval, bce);
    6396          381323 :         break;
    6397                 : 
    6398                 :       case PNK_REGEXP:
    6399            3677 :         JS_ASSERT(pn->isOp(JSOP_REGEXP));
    6400            3677 :         ok = EmitRegExp(cx, bce->regexpList.index(pn->pn_objbox), bce);
    6401            3677 :         break;
    6402                 : 
    6403                 : #if JS_HAS_XML_SUPPORT
    6404                 :       case PNK_ANYNAME:
    6405                 : #endif
    6406                 :       case PNK_TRUE:
    6407                 :       case PNK_FALSE:
    6408                 :       case PNK_THIS:
    6409                 :       case PNK_NULL:
    6410          125430 :         if (Emit1(cx, bce, pn->getOp()) < 0)
    6411               0 :             return JS_FALSE;
    6412          125430 :         break;
    6413                 : 
    6414                 :       case PNK_DEBUGGER:
    6415            4334 :         if (Emit1(cx, bce, JSOP_DEBUGGER) < 0)
    6416               0 :             return JS_FALSE;
    6417            4334 :         break;
    6418                 : 
    6419                 : #if JS_HAS_XML_SUPPORT
    6420                 :       case PNK_XMLELEM:
    6421                 :       case PNK_XMLLIST:
    6422             307 :         JS_ASSERT(!bce->inStrictMode());
    6423             307 :         JS_ASSERT(pn->isKind(PNK_XMLLIST) || pn->pn_count != 0);
    6424                 : 
    6425             307 :         switch (pn->pn_head ? pn->pn_head->getKind() : PNK_XMLLIST) {
    6426                 :           case PNK_XMLETAGO:
    6427               0 :             JS_ASSERT(0);
    6428                 :             /* FALL THROUGH */
    6429                 :           case PNK_XMLPTAGC:
    6430                 :           case PNK_XMLSTAGO:
    6431               9 :             break;
    6432                 :           default:
    6433             298 :             if (Emit1(cx, bce, JSOP_STARTXML) < 0)
    6434               0 :                 return JS_FALSE;
    6435                 :         }
    6436                 : 
    6437             632 :         for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    6438             325 :             if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
    6439               0 :                 return JS_FALSE;
    6440             325 :             if (!EmitTree(cx, bce, pn2))
    6441               0 :                 return JS_FALSE;
    6442             325 :             if (pn2 != pn->pn_head && Emit1(cx, bce, JSOP_ADD) < 0)
    6443               0 :                 return JS_FALSE;
    6444                 :         }
    6445                 : 
    6446             307 :         if (pn->pn_xflags & PNX_XMLROOT) {
    6447             307 :             if (pn->pn_count == 0) {
    6448               0 :                 JS_ASSERT(pn->isKind(PNK_XMLLIST));
    6449               0 :                 JSAtom *atom = cx->runtime->atomState.emptyAtom;
    6450                 :                 jsatomid index;
    6451               0 :                 if (!bce->makeAtomIndex(atom, &index))
    6452               0 :                     return JS_FALSE;
    6453               0 :                 if (!EmitIndex32(cx, JSOP_STRING, index, bce))
    6454               0 :                     return false;
    6455                 :             }
    6456             307 :             if (Emit1(cx, bce, pn->getOp()) < 0)
    6457               0 :                 return JS_FALSE;
    6458                 :         }
    6459                 : #ifdef DEBUG
    6460                 :         else
    6461               0 :             JS_ASSERT(pn->pn_count != 0);
    6462                 : #endif
    6463             307 :         break;
    6464                 : 
    6465                 :       case PNK_XMLPTAGC:
    6466                 :       case PNK_XMLSTAGO:
    6467                 :       case PNK_XMLETAGO:
    6468              36 :         if (!EmitXMLTag(cx, bce, pn))
    6469               0 :             return false;
    6470              36 :         break;
    6471                 : 
    6472                 :       case PNK_XMLNAME:
    6473              36 :         JS_ASSERT(!bce->inStrictMode());
    6474                 : 
    6475              36 :         if (pn->isArity(PN_LIST)) {
    6476               0 :             JS_ASSERT(pn->pn_count != 0);
    6477               0 :             for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    6478               0 :                 if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
    6479               0 :                     return JS_FALSE;
    6480               0 :                 if (!EmitTree(cx, bce, pn2))
    6481               0 :                     return JS_FALSE;
    6482               0 :                 if (pn2 != pn->pn_head && Emit1(cx, bce, JSOP_ADD) < 0)
    6483               0 :                     return JS_FALSE;
    6484                 :             }
    6485                 :         } else {
    6486              36 :             JS_ASSERT(pn->isArity(PN_NULLARY));
    6487              36 :             ok = pn->isOp(JSOP_OBJECT)
    6488               0 :                  ? EmitObjectOp(cx, pn->pn_objbox, pn->getOp(), bce)
    6489              36 :                  : EmitAtomOp(cx, pn, pn->getOp(), bce);
    6490                 :         }
    6491              36 :         break;
    6492                 : 
    6493                 :       case PNK_XMLPI:
    6494               0 :         if (!EmitXMLProcessingInstruction(cx, bce, pn->asXMLProcessingInstruction()))
    6495               0 :             return false;
    6496               0 :         break;
    6497                 : #endif /* JS_HAS_XML_SUPPORT */
    6498                 : 
    6499                 :       default:
    6500               0 :         JS_ASSERT(0);
    6501                 :     }
    6502                 : 
    6503                 :     /* bce->emitLevel == 1 means we're last on the stack, so finish up. */
    6504         5657896 :     if (ok && bce->emitLevel == 1) {
    6505          474768 :         if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.end.lineno))
    6506               0 :             return JS_FALSE;
    6507                 :     }
    6508                 : 
    6509         5657896 :     return ok;
    6510                 : }
    6511                 : 
    6512                 : static int
    6513         4251364 : AllocSrcNote(JSContext *cx, BytecodeEmitter *bce)
    6514                 : {
    6515         4251364 :     jssrcnote *notes = bce->notes();
    6516                 :     jssrcnote *newnotes;
    6517         4251364 :     unsigned index = bce->noteCount();
    6518         4251364 :     unsigned max = bce->noteLimit();
    6519                 : 
    6520         4251364 :     if (index == max) {
    6521                 :         size_t newlength;
    6522          162819 :         if (!notes) {
    6523          162333 :             JS_ASSERT(!index && !max);
    6524          162333 :             newlength = SRCNOTE_CHUNK_LENGTH;
    6525          162333 :             newnotes = (jssrcnote *) cx->malloc_(SRCNOTE_SIZE(newlength));
    6526                 :         } else {
    6527             486 :             JS_ASSERT(index <= max);
    6528             486 :             newlength = max * 2;
    6529             486 :             newnotes = (jssrcnote *) cx->realloc_(notes, SRCNOTE_SIZE(newlength));
    6530                 :         }
    6531          162819 :         if (!newnotes) {
    6532               0 :             js_ReportOutOfMemory(cx);
    6533               0 :             return -1;
    6534                 :         }
    6535          162819 :         bce->current->notes = newnotes;
    6536          162819 :         bce->current->noteLimit = newlength;
    6537                 :     }
    6538                 : 
    6539         4251364 :     bce->current->noteCount = index + 1;
    6540         4251364 :     return (int)index;
    6541                 : }
    6542                 : 
    6543                 : int
    6544         3457387 : frontend::NewSrcNote(JSContext *cx, BytecodeEmitter *bce, SrcNoteType type)
    6545                 : {
    6546                 :     int index, n;
    6547                 :     jssrcnote *sn;
    6548                 :     ptrdiff_t offset, delta, xdelta;
    6549                 : 
    6550                 :     /*
    6551                 :      * Claim a note slot in bce->notes() by growing it if necessary and then
    6552                 :      * incrementing bce->noteCount().
    6553                 :      */
    6554         3457387 :     index = AllocSrcNote(cx, bce);
    6555         3457387 :     if (index < 0)
    6556               0 :         return -1;
    6557         3457387 :     sn = &bce->notes()[index];
    6558                 : 
    6559                 :     /*
    6560                 :      * Compute delta from the last annotated bytecode's offset.  If it's too
    6561                 :      * big to fit in sn, allocate one or more xdelta notes and reset sn.
    6562                 :      */
    6563         3457387 :     offset = bce->offset();
    6564         3457387 :     delta = offset - bce->lastNoteOffset();
    6565         3457387 :     bce->current->lastNoteOffset = offset;
    6566         3457387 :     if (delta >= SN_DELTA_LIMIT) {
    6567          793977 :         do {
    6568          793977 :             xdelta = JS_MIN(delta, SN_XDELTA_MASK);
    6569          793977 :             SN_MAKE_XDELTA(sn, xdelta);
    6570          793977 :             delta -= xdelta;
    6571          793977 :             index = AllocSrcNote(cx, bce);
    6572          793977 :             if (index < 0)
    6573               0 :                 return -1;
    6574          793977 :             sn = &bce->notes()[index];
    6575                 :         } while (delta >= SN_DELTA_LIMIT);
    6576                 :     }
    6577                 : 
    6578                 :     /*
    6579                 :      * Initialize type and delta, then allocate the minimum number of notes
    6580                 :      * needed for type's arity.  Usually, we won't need more, but if an offset
    6581                 :      * does take two bytes, SetSrcNoteOffset will grow bce->notes().
    6582                 :      */
    6583         3457387 :     SN_MAKE_NOTE(sn, type, delta);
    6584         4799973 :     for (n = (int)js_SrcNoteSpec[type].arity; n > 0; n--) {
    6585         1342586 :         if (NewSrcNote(cx, bce, SRC_NULL) < 0)
    6586               0 :             return -1;
    6587                 :     }
    6588         3457387 :     return index;
    6589                 : }
    6590                 : 
    6591                 : int
    6592         1230436 : frontend::NewSrcNote2(JSContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset)
    6593                 : {
    6594                 :     int index;
    6595                 : 
    6596         1230436 :     index = NewSrcNote(cx, bce, type);
    6597         1230436 :     if (index >= 0) {
    6598         1230436 :         if (!SetSrcNoteOffset(cx, bce, index, 0, offset))
    6599               0 :             return -1;
    6600                 :     }
    6601         1230436 :     return index;
    6602                 : }
    6603                 : 
    6604                 : int
    6605             873 : frontend::NewSrcNote3(JSContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset1,
    6606                 :             ptrdiff_t offset2)
    6607                 : {
    6608                 :     int index;
    6609                 : 
    6610             873 :     index = NewSrcNote(cx, bce, type);
    6611             873 :     if (index >= 0) {
    6612             873 :         if (!SetSrcNoteOffset(cx, bce, index, 0, offset1))
    6613               0 :             return -1;
    6614             873 :         if (!SetSrcNoteOffset(cx, bce, index, 1, offset2))
    6615               0 :             return -1;
    6616                 :     }
    6617             873 :     return index;
    6618                 : }
    6619                 : 
    6620                 : static JSBool
    6621               9 : GrowSrcNotes(JSContext *cx, BytecodeEmitter *bce)
    6622                 : {
    6623               9 :     size_t newlength = bce->noteLimit() * 2;
    6624               9 :     jssrcnote *newnotes = (jssrcnote *) cx->realloc_(bce->notes(), newlength);
    6625               9 :     if (!newnotes) {
    6626               0 :         js_ReportOutOfMemory(cx);
    6627               0 :         return JS_FALSE;
    6628                 :     }
    6629               9 :     bce->current->notes = newnotes;
    6630               9 :     bce->current->noteLimit = newlength;
    6631               9 :     return JS_TRUE;
    6632                 : }
    6633                 : 
    6634                 : jssrcnote *
    6635           41808 : frontend::AddToSrcNoteDelta(JSContext *cx, BytecodeEmitter *bce, jssrcnote *sn, ptrdiff_t delta)
    6636                 : {
    6637                 :     ptrdiff_t base, limit, newdelta, diff;
    6638                 :     int index;
    6639                 : 
    6640                 :     /*
    6641                 :      * Called only from OptimizeSpanDeps and FinishTakingSrcNotes to add to
    6642                 :      * main script note deltas, and only by a small positive amount.
    6643                 :      */
    6644           41808 :     JS_ASSERT(bce->current == &bce->main);
    6645           41808 :     JS_ASSERT((unsigned) delta < (unsigned) SN_XDELTA_LIMIT);
    6646                 : 
    6647           41808 :     base = SN_DELTA(sn);
    6648           41808 :     limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
    6649           41808 :     newdelta = base + delta;
    6650           41808 :     if (newdelta < limit) {
    6651           22710 :         SN_SET_DELTA(sn, newdelta);
    6652                 :     } else {
    6653           19098 :         index = sn - bce->main.notes;
    6654           19098 :         if (bce->main.noteCount == bce->main.noteLimit) {
    6655               0 :             if (!GrowSrcNotes(cx, bce))
    6656               0 :                 return NULL;
    6657               0 :             sn = bce->main.notes + index;
    6658                 :         }
    6659           19098 :         diff = bce->main.noteCount - index;
    6660           19098 :         bce->main.noteCount++;
    6661           19098 :         memmove(sn + 1, sn, SRCNOTE_SIZE(diff));
    6662           19098 :         SN_MAKE_XDELTA(sn, delta);
    6663           19098 :         sn++;
    6664                 :     }
    6665           41808 :     return sn;
    6666                 : }
    6667                 : 
    6668                 : static JSBool
    6669         1502735 : SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, unsigned index, unsigned which, ptrdiff_t offset)
    6670                 : {
    6671                 :     jssrcnote *sn;
    6672                 :     ptrdiff_t diff;
    6673                 : 
    6674         1502735 :     if (size_t(offset) > SN_MAX_OFFSET) {
    6675               0 :         ReportStatementTooLarge(cx, bce);
    6676               0 :         return JS_FALSE;
    6677                 :     }
    6678                 : 
    6679                 :     /* Find the offset numbered which (i.e., skip exactly which offsets). */
    6680         1502735 :     sn = &bce->notes()[index];
    6681         1502735 :     JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
    6682         1502735 :     JS_ASSERT((int) which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
    6683         1583862 :     for (sn++; which; sn++, which--) {
    6684           81127 :         if (*sn & SN_3BYTE_OFFSET_FLAG)
    6685            4365 :             sn += 2;
    6686                 :     }
    6687                 : 
    6688                 :     /*
    6689                 :      * See if the new offset requires three bytes either by being too big or if
    6690                 :      * the offset has already been inflated (in which case, we need to stay big
    6691                 :      * to not break the srcnote encoding if this isn't the last srcnote).
    6692                 :      */
    6693         1502735 :     if (offset > (ptrdiff_t)SN_3BYTE_OFFSET_MASK || (*sn & SN_3BYTE_OFFSET_FLAG)) {
    6694                 :         /* Maybe this offset was already set to a three-byte value. */
    6695           44983 :         if (!(*sn & SN_3BYTE_OFFSET_FLAG)) {
    6696                 :             /* Losing, need to insert another two bytes for this offset. */
    6697           40717 :             index = sn - bce->notes();
    6698                 : 
    6699                 :             /*
    6700                 :              * Test to see if the source note array must grow to accommodate
    6701                 :              * either the first or second byte of additional storage required
    6702                 :              * by this 3-byte offset.
    6703                 :              */
    6704           40717 :             if (bce->noteCount() + 1 >= bce->noteLimit()) {
    6705               9 :                 if (!GrowSrcNotes(cx, bce))
    6706               0 :                     return JS_FALSE;
    6707               9 :                 sn = bce->notes() + index;
    6708                 :             }
    6709           40717 :             bce->current->noteCount += 2;
    6710                 : 
    6711           40717 :             diff = bce->noteCount() - (index + 3);
    6712           40717 :             JS_ASSERT(diff >= 0);
    6713           40717 :             if (diff > 0)
    6714           10683 :                 memmove(sn + 3, sn + 1, SRCNOTE_SIZE(diff));
    6715                 :         }
    6716           44983 :         *sn++ = (jssrcnote)(SN_3BYTE_OFFSET_FLAG | (offset >> 16));
    6717           44983 :         *sn++ = (jssrcnote)(offset >> 8);
    6718                 :     }
    6719         1502735 :     *sn = (jssrcnote)offset;
    6720         1502735 :     return JS_TRUE;
    6721                 : }
    6722                 : 
    6723                 : #ifdef DEBUG_notme
    6724                 : #define DEBUG_srcnotesize
    6725                 : #endif
    6726                 : 
    6727                 : #ifdef DEBUG_srcnotesize
    6728                 : #define NBINS 10
    6729                 : static uint32_t hist[NBINS];
    6730                 : 
    6731                 : static void
    6732                 : DumpSrcNoteSizeHist()
    6733                 : {
    6734                 :     static FILE *fp;
    6735                 :     int i, n;
    6736                 : 
    6737                 :     if (!fp) {
    6738                 :         fp = fopen("/tmp/srcnotes.hist", "w");
    6739                 :         if (!fp)
    6740                 :             return;
    6741                 :         setvbuf(fp, NULL, _IONBF, 0);
    6742                 :     }
    6743                 :     fprintf(fp, "SrcNote size histogram:\n");
    6744                 :     for (i = 0; i < NBINS; i++) {
    6745                 :         fprintf(fp, "%4u %4u ", JS_BIT(i), hist[i]);
    6746                 :         for (n = (int) JS_HOWMANY(hist[i], 10); n > 0; --n)
    6747                 :             fputc('*', fp);
    6748                 :         fputc('\n', fp);
    6749                 :     }
    6750                 :     fputc('\n', fp);
    6751                 : }
    6752                 : #endif
    6753                 : 
    6754                 : /*
    6755                 :  * Fill in the storage at notes with prolog and main srcnotes; the space at
    6756                 :  * notes was allocated using the BytecodeEmitter::countFinalSourceNotes()
    6757                 :  * method from BytecodeEmitter.h. SO DON'T CHANGE THIS FUNCTION WITHOUT AT
    6758                 :  * LEAST CHECKING WHETHER BytecodeEmitter::countFinalSourceNotes() NEEDS
    6759                 :  * CORRESPONDING CHANGES!
    6760                 :  */
    6761                 : JSBool
    6762          259010 : frontend::FinishTakingSrcNotes(JSContext *cx, BytecodeEmitter *bce, jssrcnote *notes)
    6763                 : {
    6764                 :     unsigned prologCount, mainCount, totalCount;
    6765                 :     ptrdiff_t offset, delta;
    6766                 :     jssrcnote *sn;
    6767                 : 
    6768          259010 :     JS_ASSERT(bce->current == &bce->main);
    6769                 : 
    6770          259010 :     prologCount = bce->prolog.noteCount;
    6771          259010 :     if (prologCount && bce->prolog.currentLine != bce->firstLine) {
    6772            1029 :         bce->switchToProlog();
    6773            1029 :         if (NewSrcNote2(cx, bce, SRC_SETLINE, (ptrdiff_t)bce->firstLine) < 0)
    6774               0 :             return false;
    6775            1029 :         prologCount = bce->prolog.noteCount;
    6776            1029 :         bce->switchToMain();
    6777                 :     } else {
    6778                 :         /*
    6779                 :          * Either no prolog srcnotes, or no line number change over prolog.
    6780                 :          * We don't need a SRC_SETLINE, but we may need to adjust the offset
    6781                 :          * of the first main note, by adding to its delta and possibly even
    6782                 :          * prepending SRC_XDELTA notes to it to account for prolog bytecodes
    6783                 :          * that came at and after the last annotated bytecode.
    6784                 :          */
    6785          257981 :         offset = bce->prologOffset() - bce->prolog.lastNoteOffset;
    6786          257981 :         JS_ASSERT(offset >= 0);
    6787          257981 :         if (offset > 0 && bce->main.noteCount != 0) {
    6788                 :             /* NB: Use as much of the first main note's delta as we can. */
    6789           22710 :             sn = bce->main.notes;
    6790                 :             delta = SN_IS_XDELTA(sn)
    6791                 :                     ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK)
    6792           22710 :                     : SN_DELTA_MASK - (*sn & SN_DELTA_MASK);
    6793           22710 :             if (offset < delta)
    6794            3594 :                 delta = offset;
    6795           19098 :             for (;;) {
    6796           41808 :                 if (!AddToSrcNoteDelta(cx, bce, sn, delta))
    6797               0 :                     return false;
    6798           41808 :                 offset -= delta;
    6799           41808 :                 if (offset == 0)
    6800                 :                     break;
    6801           19098 :                 delta = JS_MIN(offset, SN_XDELTA_MASK);
    6802           19098 :                 sn = bce->main.notes;
    6803                 :             }
    6804                 :         }
    6805                 :     }
    6806                 : 
    6807          259010 :     mainCount = bce->main.noteCount;
    6808          259010 :     totalCount = prologCount + mainCount;
    6809          259010 :     if (prologCount)
    6810            1029 :         PodCopy(notes, bce->prolog.notes, prologCount);
    6811          259010 :     PodCopy(notes + prologCount, bce->main.notes, mainCount);
    6812          259010 :     SN_MAKE_TERMINATOR(&notes[totalCount]);
    6813                 : 
    6814          259010 :     return true;
    6815                 : }
    6816                 : 
    6817                 : static JSBool
    6818           91846 : NewTryNote(JSContext *cx, BytecodeEmitter *bce, JSTryNoteKind kind, unsigned stackDepth, size_t start,
    6819                 :            size_t end)
    6820                 : {
    6821           91846 :     JS_ASSERT((unsigned)(uint16_t)stackDepth == stackDepth);
    6822           91846 :     JS_ASSERT(start <= end);
    6823                 :     JS_ASSERT((size_t)(uint32_t)start == start);
    6824                 :     JS_ASSERT((size_t)(uint32_t)end == end);
    6825                 : 
    6826           91846 :     TryNode *tryNode = cx->tempLifoAlloc().new_<TryNode>();
    6827           91846 :     if (!tryNode) {
    6828               0 :         js_ReportOutOfMemory(cx);
    6829               0 :         return JS_FALSE;
    6830                 :     }
    6831                 : 
    6832           91846 :     tryNode->note.kind = kind;
    6833           91846 :     tryNode->note.stackDepth = (uint16_t)stackDepth;
    6834           91846 :     tryNode->note.start = (uint32_t)start;
    6835           91846 :     tryNode->note.length = (uint32_t)(end - start);
    6836           91846 :     tryNode->prev = bce->lastTryNode;
    6837           91846 :     bce->lastTryNode = tryNode;
    6838           91846 :     bce->ntrynotes++;
    6839           91846 :     return JS_TRUE;
    6840                 : }
    6841                 : 
    6842                 : void
    6843            7372 : frontend::FinishTakingTryNotes(BytecodeEmitter *bce, JSTryNoteArray *array)
    6844                 : {
    6845                 :     TryNode *tryNode;
    6846                 :     JSTryNote *tn;
    6847                 : 
    6848            7372 :     JS_ASSERT(array->length > 0 && array->length == bce->ntrynotes);
    6849            7372 :     tn = array->vector + array->length;
    6850            7372 :     tryNode = bce->lastTryNode;
    6851           91837 :     do {
    6852           91837 :         *--tn = tryNode->note;
    6853                 :     } while ((tryNode = tryNode->prev) != NULL);
    6854            7372 :     JS_ASSERT(tn == array->vector);
    6855            7372 : }
    6856                 : 
    6857                 : /*
    6858                 :  * Find the index of the given object for code generator.
    6859                 :  *
    6860                 :  * Since the emitter refers to each parsed object only once, for the index we
    6861                 :  * use the number of already indexes objects. We also add the object to a list
    6862                 :  * to convert the list to a fixed-size array when we complete code generation,
    6863                 :  * see js::CGObjectList::finish below.
    6864                 :  *
    6865                 :  * Most of the objects go to BytecodeEmitter::objectList but for regexp we use
    6866                 :  * a separated BytecodeEmitter::regexpList. In this way the emitted index can
    6867                 :  * be directly used to store and fetch a reference to a cloned RegExp object
    6868                 :  * that shares the same JSRegExp private data created for the object literal in
    6869                 :  * objbox. We need a cloned object to hold lastIndex and other direct
    6870                 :  * properties that should not be shared among threads sharing a precompiled
    6871                 :  * function or script.
    6872                 :  *
    6873                 :  * If the code being compiled is function code, allocate a reserved slot in
    6874                 :  * the cloned function object that shares its precompiled script with other
    6875                 :  * cloned function objects and with the compiler-created clone-parent. There
    6876                 :  * are nregexps = script->regexps()->length such reserved slots in each
    6877                 :  * function object cloned from fun->object. NB: during compilation, a funobj
    6878                 :  * slots element must never be allocated, because JSObject::allocSlot could
    6879                 :  * hand out one of the slots that should be given to a regexp clone.
    6880                 :  *
    6881                 :  * If the code being compiled is global code, the cloned regexp are stored in
    6882                 :  * fp->vars slot and to protect regexp slots from GC we set fp->nvars to
    6883                 :  * nregexps.
    6884                 :  *
    6885                 :  * The slots initially contain undefined or null. We populate them lazily when
    6886                 :  * JSOP_REGEXP is executed for the first time.
    6887                 :  *
    6888                 :  * Why clone regexp objects?  ECMA specifies that when a regular expression
    6889                 :  * literal is scanned, a RegExp object is created.  In the spec, compilation
    6890                 :  * and execution happen indivisibly, but in this implementation and many of
    6891                 :  * its embeddings, code is precompiled early and re-executed in multiple
    6892                 :  * threads, or using multiple global objects, or both, for efficiency.
    6893                 :  *
    6894                 :  * In such cases, naively following ECMA leads to wrongful sharing of RegExp
    6895                 :  * objects, which makes for collisions on the lastIndex property (especially
    6896                 :  * for global regexps) and on any ad-hoc properties.  Also, __proto__ refers to
    6897                 :  * the pre-compilation prototype, a pigeon-hole problem for instanceof tests.
    6898                 :  */
    6899                 : unsigned
    6900          271209 : CGObjectList::index(ObjectBox *objbox)
    6901                 : {
    6902          271209 :     JS_ASSERT(!objbox->emitLink);
    6903          271209 :     objbox->emitLink = lastbox;
    6904          271209 :     lastbox = objbox;
    6905          271209 :     return length++;
    6906                 : }
    6907                 : 
    6908                 : void
    6909           84695 : CGObjectList::finish(JSObjectArray *array)
    6910                 : {
    6911           84695 :     JS_ASSERT(length <= INDEX_LIMIT);
    6912           84695 :     JS_ASSERT(length == array->length);
    6913                 : 
    6914           84695 :     js::HeapPtrObject *cursor = array->vector + array->length;
    6915           84695 :     ObjectBox *objbox = lastbox;
    6916          291965 :     do {
    6917          291965 :         --cursor;
    6918          291965 :         JS_ASSERT(!*cursor);
    6919          291965 :         *cursor = objbox->object;
    6920                 :     } while ((objbox = objbox->emitLink) != NULL);
    6921           84695 :     JS_ASSERT(cursor == array->vector);
    6922           84695 : }
    6923                 : 
    6924                 : void
    6925            2774 : GCConstList::finish(JSConstArray *array)
    6926                 : {
    6927            2774 :     JS_ASSERT(array->length == list.length());
    6928            2774 :     Value *src = list.begin(), *srcend = list.end();
    6929            2774 :     HeapValue *dst = array->vector;
    6930           13927 :     for (; src != srcend; ++src, ++dst)
    6931           11153 :         *dst = *src;
    6932            2774 : }
    6933                 : 
    6934                 : /*
    6935                 :  * We should try to get rid of offsetBias (always 0 or 1, where 1 is
    6936                 :  * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL.
    6937                 :  */
    6938                 : JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
    6939                 :     {"null",            0},
    6940                 :     {"if",              0},
    6941                 :     {"if-else",         2},
    6942                 :     {"for",             3},
    6943                 :     {"while",           1},
    6944                 :     {"continue",        0},
    6945                 :     {"decl",            1},
    6946                 :     {"pcdelta",         1},
    6947                 :     {"assignop",        0},
    6948                 :     {"cond",            1},
    6949                 :     {"brace",           1},
    6950                 :     {"hidden",          0},
    6951                 :     {"pcbase",          1},
    6952                 :     {"label",           1},
    6953                 :     {"labelbrace",      1},
    6954                 :     {"endbrace",        0},
    6955                 :     {"break2label",     1},
    6956                 :     {"cont2label",      1},
    6957                 :     {"switch",          2},
    6958                 :     {"funcdef",         1},
    6959                 :     {"catch",           1},
    6960                 :     {"unused",         -1},
    6961                 :     {"newline",         0},
    6962                 :     {"setline",         1},
    6963                 :     {"xdelta",          0},
    6964                 : };
    6965                 : 
    6966                 : JS_FRIEND_API(unsigned)
    6967        78072791 : js_SrcNoteLength(jssrcnote *sn)
    6968                 : {
    6969                 :     unsigned arity;
    6970                 :     jssrcnote *base;
    6971                 : 
    6972        78072791 :     arity = (int)js_SrcNoteSpec[SN_TYPE(sn)].arity;
    6973       158073692 :     for (base = sn++; arity; sn++, arity--) {
    6974        80000901 :         if (*sn & SN_3BYTE_OFFSET_FLAG)
    6975          556490 :             sn += 2;
    6976                 :     }
    6977        78072791 :     return sn - base;
    6978                 : }
    6979                 : 
    6980                 : JS_FRIEND_API(ptrdiff_t)
    6981         1223594 : js_GetSrcNoteOffset(jssrcnote *sn, unsigned which)
    6982                 : {
    6983                 :     /* Find the offset numbered which (i.e., skip exactly which offsets). */
    6984         1223594 :     JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
    6985         1223594 :     JS_ASSERT((int) which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
    6986         1227959 :     for (sn++; which; sn++, which--) {
    6987            4365 :         if (*sn & SN_3BYTE_OFFSET_FLAG)
    6988               9 :             sn += 2;
    6989                 :     }
    6990         1223594 :     if (*sn & SN_3BYTE_OFFSET_FLAG) {
    6991          293210 :         return (ptrdiff_t)(((uint32_t)(sn[0] & SN_3BYTE_OFFSET_MASK) << 16)
    6992          293210 :                            | (sn[1] << 8)
    6993          586420 :                            | sn[2]);
    6994                 :     }
    6995          930384 :     return (ptrdiff_t)*sn;
    6996                 : }

Generated by: LCOV version 1.7