LCOV - code coverage report
Current view: directory - js/src/frontend - BytecodeEmitter.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 3462 2711 78.3 %
Date: 2012-04-21 Functions: 143 138 96.5 %

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

Generated by: LCOV version 1.7