LCOV - code coverage report
Current view: directory - js/src/frontend - BytecodeEmitter.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 3423 2675 78.1 %
Date: 2012-06-02 Functions: 142 137 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         1109714 : 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         1109714 :     typesetCount(0)
     121                 : {
     122         1109714 :     flags = TCF_COMPILING;
     123         1109714 :     memset(&prolog, 0, sizeof prolog);
     124         1109714 :     memset(&main, 0, sizeof main);
     125         1109714 :     current = &main;
     126         1109714 :     firstLine = prolog.currentLine = main.currentLine = lineno;
     127         1109714 : }
     128                 : 
     129                 : bool
     130         1109714 : BytecodeEmitter::init(JSContext *cx, TreeContext::InitBehavior ib)
     131                 : {
     132         1109714 :     roLexdeps.init();
     133         1109714 :     return TreeContext::init(cx, ib) && constMap.init() && atomIndices.ensureMap(cx);
     134                 : }
     135                 : 
     136         2219428 : BytecodeEmitter::~BytecodeEmitter()
     137                 : {
     138         1109714 :     JSContext *cx = parser->context;
     139                 : 
     140         1109714 :     cx->free_(prolog.base);
     141         1109714 :     cx->free_(prolog.notes);
     142         1109714 :     cx->free_(main.base);
     143         1109714 :     cx->free_(main.notes);
     144         1109714 : }
     145                 : 
     146                 : static ptrdiff_t
     147       108146349 : EmitCheck(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t delta)
     148                 : {
     149       108146349 :     jsbytecode *base = bce->base();
     150                 :     jsbytecode *newbase;
     151       108146349 :     jsbytecode *next = bce->next();
     152       108146349 :     jsbytecode *limit = bce->limit();
     153       108146349 :     ptrdiff_t offset = next - base;
     154       108146349 :     size_t minlength = offset + delta;
     155                 : 
     156       108146349 :     if (next + delta > limit) {
     157                 :         size_t newlength;
     158         1214957 :         if (!base) {
     159         1160777 :             JS_ASSERT(!next && !limit);
     160         1160777 :             newlength = BYTECODE_CHUNK_LENGTH;
     161         1160777 :             if (newlength < minlength)     /* make it bigger if necessary */
     162               0 :                 newlength = RoundUpPow2(minlength);
     163         1160777 :             newbase = (jsbytecode *) cx->malloc_(BYTECODE_SIZE(newlength));
     164                 :         } else {
     165           54180 :             JS_ASSERT(base <= next && next <= limit);
     166           54180 :             newlength = (limit - base) * 2;
     167           54180 :             if (newlength < minlength)     /* make it bigger if necessary */
     168               0 :                 newlength = RoundUpPow2(minlength);
     169           54180 :             newbase = (jsbytecode *) cx->realloc_(base, BYTECODE_SIZE(newlength));
     170                 :         }
     171         1214957 :         if (!newbase) {
     172               0 :             js_ReportOutOfMemory(cx);
     173               0 :             return -1;
     174                 :         }
     175         1214957 :         JS_ASSERT(newlength >= size_t(offset + delta));
     176         1214957 :         bce->current->base = newbase;
     177         1214957 :         bce->current->limit = newbase + newlength;
     178         1214957 :         bce->current->next = newbase + offset;
     179                 :     }
     180       108146349 :     return offset;
     181                 : }
     182                 : 
     183                 : static StaticBlockObject &
     184          446653 : CurrentBlock(BytecodeEmitter *bce)
     185                 : {
     186          446653 :     JS_ASSERT(bce->topStmt->type == STMT_BLOCK || bce->topStmt->type == STMT_SWITCH);
     187          446653 :     JS_ASSERT(bce->topStmt->blockObj->isStaticBlock());
     188          446653 :     return *bce->topStmt->blockObj;
     189                 : }
     190                 : 
     191                 : static void
     192       108146349 : UpdateDepth(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t target)
     193                 : {
     194       108146349 :     jsbytecode *pc = bce->code(target);
     195       108146349 :     JSOp op = (JSOp) *pc;
     196       108146349 :     const JSCodeSpec *cs = &js_CodeSpec[op];
     197                 : 
     198                 : 
     199       108146349 :     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         9046404 :                       ((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT);
     206         9046404 :         if (depth > bce->maxStackDepth)
     207         1163625 :             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       108146349 :     if (op == JSOP_ENTERBLOCK) {
     217          366540 :         nuses = 0;
     218          366540 :         ndefs = CurrentBlock(bce).slotCount();
     219       107779809 :     } else if (op == JSOP_ENTERLET0) {
     220           45212 :         nuses = ndefs = CurrentBlock(bce).slotCount();
     221       107734597 :     } else if (op == JSOP_ENTERLET1) {
     222           34901 :         nuses = ndefs = CurrentBlock(bce).slotCount() + 1;
     223                 :     } else {
     224       107699696 :         nuses = StackUses(NULL, pc);
     225       107699696 :         ndefs = StackDefs(NULL, pc);
     226                 :     }
     227                 : 
     228       108146349 :     bce->stackDepth -= nuses;
     229       108146349 :     JS_ASSERT(bce->stackDepth >= 0);
     230       108146349 :     bce->stackDepth += ndefs;
     231       108146349 :     if ((unsigned)bce->stackDepth > bce->maxStackDepth)
     232         3144375 :         bce->maxStackDepth = bce->stackDepth;
     233       108146349 : }
     234                 : 
     235                 : static inline void
     236         1666489 : UpdateDecomposeLength(BytecodeEmitter *bce, unsigned start)
     237                 : {
     238         1666489 :     unsigned end = bce->offset();
     239         1666489 :     JS_ASSERT(unsigned(end - start) < 256);
     240         1666489 :     bce->code(start)[-1] = end - start;
     241         1666489 : }
     242                 : 
     243                 : ptrdiff_t
     244        51429296 : frontend::Emit1(JSContext *cx, BytecodeEmitter *bce, JSOp op)
     245                 : {
     246        51429296 :     JS_ASSERT_IF(op == JSOP_ARGUMENTS, !bce->mayOverwriteArguments());
     247                 : 
     248        51429296 :     ptrdiff_t offset = EmitCheck(cx, bce, 1);
     249                 : 
     250        51429296 :     if (offset >= 0) {
     251        51429296 :         *bce->current->next++ = (jsbytecode)op;
     252        51429296 :         UpdateDepth(cx, bce, offset);
     253                 :     }
     254        51429296 :     return offset;
     255                 : }
     256                 : 
     257                 : ptrdiff_t
     258         6509118 : frontend::Emit2(JSContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1)
     259                 : {
     260         6509118 :     ptrdiff_t offset = EmitCheck(cx, bce, 2);
     261                 : 
     262         6509118 :     if (offset >= 0) {
     263         6509118 :         jsbytecode *next = bce->next();
     264         6509118 :         next[0] = (jsbytecode)op;
     265         6509118 :         next[1] = op1;
     266         6509118 :         bce->current->next = next + 2;
     267         6509118 :         UpdateDepth(cx, bce, offset);
     268                 :     }
     269         6509118 :     return offset;
     270                 : }
     271                 : 
     272                 : ptrdiff_t
     273        18217419 : frontend::Emit3(JSContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1,
     274                 :                     jsbytecode op2)
     275                 : {
     276        18217419 :     ptrdiff_t offset = EmitCheck(cx, bce, 3);
     277                 : 
     278        18217419 :     if (offset >= 0) {
     279        18217419 :         jsbytecode *next = bce->next();
     280        18217419 :         next[0] = (jsbytecode)op;
     281        18217419 :         next[1] = op1;
     282        18217419 :         next[2] = op2;
     283        18217419 :         bce->current->next = next + 3;
     284        18217419 :         UpdateDepth(cx, bce, offset);
     285                 :     }
     286        18217419 :     return offset;
     287                 : }
     288                 : 
     289                 : ptrdiff_t
     290          273968 : frontend::EmitN(JSContext *cx, BytecodeEmitter *bce, JSOp op, size_t extra)
     291                 : {
     292          273968 :     ptrdiff_t length = 1 + (ptrdiff_t)extra;
     293          273968 :     ptrdiff_t offset = EmitCheck(cx, bce, length);
     294                 : 
     295          273968 :     if (offset >= 0) {
     296          273968 :         jsbytecode *next = bce->next();
     297          273968 :         *next = (jsbytecode)op;
     298          273968 :         memset(next + 1, 0, BYTECODE_SIZE(extra));
     299          273968 :         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          273968 :         if (js_CodeSpec[op].nuses >= 0)
     306          273968 :             UpdateDepth(cx, bce, offset);
     307                 :     }
     308          273968 :     return offset;
     309                 : }
     310                 : 
     311                 : static ptrdiff_t
     312         2490713 : EmitJump(JSContext *cx, BytecodeEmitter *bce, JSOp op, ptrdiff_t off)
     313                 : {
     314         2490713 :     ptrdiff_t offset = EmitCheck(cx, bce, 5);
     315                 : 
     316         2490713 :     if (offset >= 0) {
     317         2490713 :         jsbytecode *next = bce->next();
     318         2490713 :         next[0] = (jsbytecode)op;
     319         2490713 :         SET_JUMP_OFFSET(next, off);
     320         2490713 :         bce->current->next = next + 5;
     321         2490713 :         UpdateDepth(cx, bce, offset);
     322                 :     }
     323         2490713 :     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         1101840 : 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         1101840 :     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         1101840 :     tc->staticLevel = staticLevel;
     402         1101840 :     return true;
     403                 : }
     404                 : 
     405                 : bool
     406         2568619 : frontend::GenerateBlockId(TreeContext *tc, uint32_t &blockid)
     407                 : {
     408         2568619 :     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         2568619 :     blockid = tc->blockidGen++;
     414         2568619 :     return true;
     415                 : }
     416                 : 
     417                 : void
     418         7762704 : frontend::PushStatement(TreeContext *tc, StmtInfo *stmt, StmtType type, ptrdiff_t top)
     419                 : {
     420         7762704 :     stmt->type = type;
     421         7762704 :     stmt->flags = 0;
     422         7762704 :     stmt->blockid = tc->blockid();
     423         7762704 :     SET_STATEMENT_TOP(stmt, top);
     424         7762704 :     stmt->label = NULL;
     425         7762704 :     JS_ASSERT(!stmt->blockObj);
     426         7762704 :     stmt->down = tc->topStmt;
     427         7762704 :     tc->topStmt = stmt;
     428         7762704 :     if (STMT_LINKS_SCOPE(stmt)) {
     429            1323 :         stmt->downScope = tc->topScopeStmt;
     430            1323 :         tc->topScopeStmt = stmt;
     431                 :     } else {
     432         7761381 :         stmt->downScope = NULL;
     433                 :     }
     434         7762704 : }
     435                 : 
     436                 : void
     437          763163 : frontend::PushBlockScope(TreeContext *tc, StmtInfo *stmt, StaticBlockObject &blockObj, ptrdiff_t top)
     438                 : {
     439          763163 :     PushStatement(tc, stmt, STMT_BLOCK, top);
     440          763163 :     stmt->flags |= SIF_SCOPE;
     441          763163 :     blockObj.setEnclosingBlock(tc->blockChain);
     442          763163 :     stmt->downScope = tc->topScopeStmt;
     443          763163 :     tc->topScopeStmt = stmt;
     444          763163 :     tc->blockChain = &blockObj;
     445          763163 :     stmt->blockObj = &blockObj;
     446          763163 : }
     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          749589 : EmitBackPatchOp(JSContext *cx, BytecodeEmitter *bce, JSOp op, ptrdiff_t *lastp)
     454                 : {
     455                 :     ptrdiff_t offset, delta;
     456                 : 
     457          749589 :     offset = bce->offset();
     458          749589 :     delta = offset - *lastp;
     459          749589 :     *lastp = offset;
     460          749589 :     JS_ASSERT(delta > 0);
     461          749589 :     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         2571470 : UpdateLineNumberNotes(JSContext *cx, BytecodeEmitter *bce, unsigned line)
     497                 : {
     498         2571470 :     UPDATE_LINE_NUMBER_NOTES(cx, bce, line);
     499         2571470 :     return JS_TRUE;
     500                 : }
     501                 : 
     502                 : static ptrdiff_t
     503          174187 : EmitLoopHead(JSContext *cx, BytecodeEmitter *bce, ParseNode *nextpn)
     504                 : {
     505          174187 :     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          119571 :         JS_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
     512          119571 :         if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
     513           65084 :             nextpn = nextpn->pn_head;
     514          119571 :         if (!UpdateLineNumberNotes(cx, bce, nextpn->pn_pos.begin.lineno))
     515               0 :             return -1;
     516                 :     }
     517                 : 
     518          174187 :     return Emit1(cx, bce, JSOP_LOOPHEAD);
     519                 : }
     520                 : 
     521                 : static bool
     522          174187 : EmitLoopEntry(JSContext *cx, BytecodeEmitter *bce, ParseNode *nextpn)
     523                 : {
     524          174187 :     if (nextpn) {
     525                 :         /* Update the line number, as for LOOPHEAD. */
     526          119125 :         JS_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
     527          119125 :         if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
     528            1095 :             nextpn = nextpn->pn_head;
     529          119125 :         if (!UpdateLineNumberNotes(cx, bce, nextpn->pn_pos.begin.lineno))
     530               0 :             return false;
     531                 :     }
     532                 : 
     533          174187 :     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        52892002 : CheckTypeSet(JSContext *cx, BytecodeEmitter *bce, JSOp op)
     542                 : {
     543        52892002 :     if (js_CodeSpec[op].format & JOF_TYPESET) {
     544        23300301 :         if (bce->typesetCount < UINT16_MAX)
     545        23300301 :             bce->typesetCount++;
     546                 :     }
     547        52892002 : }
     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            6837 : PopIterator(JSContext *cx, BytecodeEmitter *bce)
     602                 : {
     603            6837 :     if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
     604               0 :         return false;
     605            6837 :     if (Emit1(cx, bce, JSOP_ENDITER) < 0)
     606               0 :         return false;
     607            6837 :     return true;
     608                 : }
     609                 : 
     610                 : /*
     611                 :  * Emit additional bytecode(s) for non-local jumps.
     612                 :  */
     613                 : static JSBool
     614          908329 : 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          908329 :     int depth = bce->stackDepth;
     623          908329 :     int npops = 0;
     624                 : 
     625                 : #define FLUSH_POPS() if (npops && !FlushPops(cx, bce, &npops)) return JS_FALSE
     626                 : 
     627         2498312 :     for (StmtInfo *stmt = bce->topStmt; stmt != toStmt; stmt = stmt->down) {
     628         1595958 :         switch (stmt->type) {
     629                 :           case STMT_FINALLY:
     630            7163 :             FLUSH_POPS();
     631            7163 :             if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
     632               0 :                 return JS_FALSE;
     633            7163 :             if (EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, &GOSUBS(*stmt)) < 0)
     634               0 :                 return JS_FALSE;
     635            7163 :             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            3274 :             FLUSH_POPS();
     648            3274 :             if (!PopIterator(cx, bce))
     649               0 :                 return JS_FALSE;
     650            3274 :             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         1595958 :         if (stmt->flags & SIF_SCOPE) {
     664          122315 :             FLUSH_POPS();
     665          122315 :             unsigned blockObjCount = stmt->blockObj->slotCount();
     666          122315 :             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            9538 :                 JS_ASSERT(stmt->down->type == STMT_FOR_IN_LOOP);
     673            9538 :                 stmt = stmt->down;
     674            9538 :                 if (stmt == toStmt)
     675            5975 :                     break;
     676            3563 :                 if (Emit1(cx, bce, JSOP_LEAVEFORLETIN) < 0)
     677               0 :                     return JS_FALSE;
     678            3563 :                 if (!PopIterator(cx, bce))
     679               0 :                     return JS_FALSE;
     680            3563 :                 if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
     681               0 :                     return JS_FALSE;
     682            3563 :                 EMIT_UINT16_IMM_OP(JSOP_POPN, blockObjCount);
     683                 :             } else {
     684                 :                 /* There is a Block object with locals on the stack to pop. */
     685          112777 :                 if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
     686               0 :                     return JS_FALSE;
     687          112777 :                 EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObjCount);
     688                 :             }
     689                 :         }
     690                 :     }
     691                 : 
     692          908329 :     FLUSH_POPS();
     693          908329 :     bce->stackDepth = depth;
     694          908329 :     return JS_TRUE;
     695                 : 
     696                 : #undef FLUSH_POPS
     697                 : }
     698                 : 
     699                 : static const jsatomid INVALID_ATOMID = -1;
     700                 : 
     701                 : static ptrdiff_t
     702          248243 : 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          248243 :     if (!EmitNonLocalJumpFixup(cx, bce, toStmt))
     708               0 :         return -1;
     709                 : 
     710          248243 :     if (labelIndex != INVALID_ATOMID)
     711             136 :         index = NewSrcNote2(cx, bce, noteType, ptrdiff_t(labelIndex));
     712          248107 :     else if (noteType != SRC_NULL)
     713           91495 :         index = NewSrcNote(cx, bce, noteType);
     714                 :     else
     715          156612 :         index = 0;
     716          248243 :     if (index < 0)
     717               0 :         return -1;
     718                 : 
     719          248243 :     return EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, lastp);
     720                 : }
     721                 : 
     722                 : static JSBool
     723         8196244 : BackPatch(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t last, jsbytecode *target, jsbytecode op)
     724                 : {
     725                 :     jsbytecode *pc, *stop;
     726                 :     ptrdiff_t delta, span;
     727                 : 
     728         8196244 :     pc = bce->code(last);
     729         8196244 :     stop = bce->code(-1);
     730        17142077 :     while (pc != stop) {
     731          749589 :         delta = GET_JUMP_OFFSET(pc);
     732          749589 :         span = target - pc;
     733          749589 :         SET_JUMP_OFFSET(pc, span);
     734          749589 :         *pc = op;
     735          749589 :         pc -= delta;
     736                 :     }
     737         8196244 :     return JS_TRUE;
     738                 : }
     739                 : 
     740                 : void
     741         7761928 : frontend::PopStatementTC(TreeContext *tc)
     742                 : {
     743         7761928 :     StmtInfo *stmt = tc->topStmt;
     744         7761928 :     tc->topStmt = stmt->down;
     745         7761928 :     if (STMT_LINKS_SCOPE(stmt)) {
     746          896899 :         tc->topScopeStmt = stmt->downScope;
     747          896899 :         if (stmt->flags & SIF_SCOPE)
     748          895576 :             tc->blockChain = stmt->blockObj->enclosingBlock();
     749                 :     }
     750         7761928 : }
     751                 : 
     752                 : JSBool
     753         4207606 : frontend::PopStatementBCE(JSContext *cx, BytecodeEmitter *bce)
     754                 : {
     755         4207606 :     StmtInfo *stmt = bce->topStmt;
     756        12140776 :     if (!STMT_IS_TRYING(stmt) &&
     757         3966585 :         (!BackPatch(cx, bce, stmt->breaks, bce->next(), JSOP_GOTO) ||
     758         3966585 :          !BackPatch(cx, bce, stmt->continues, bce->code(stmt->update), JSOP_GOTO)))
     759                 :     {
     760               0 :         return JS_FALSE;
     761                 :     }
     762         4207606 :     PopStatementTC(bce);
     763         4207606 :     return JS_TRUE;
     764                 : }
     765                 : 
     766                 : JSBool
     767          168764 : frontend::DefineCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom *atom, ParseNode *pn)
     768                 : {
     769                 :     /* XXX just do numbers for now */
     770          168764 :     if (pn->isKind(PNK_NUMBER)) {
     771            7973 :         if (!bce->constMap.put(atom, NumberValue(pn->pn_dval)))
     772               0 :             return JS_FALSE;
     773                 :     }
     774          168764 :     return JS_TRUE;
     775                 : }
     776                 : 
     777                 : StmtInfo *
     778        14987965 : frontend::LexicalLookup(TreeContext *tc, JSAtom *atom, int *slotp, StmtInfo *stmt)
     779                 : {
     780        14987965 :     if (!stmt)
     781        14987965 :         stmt = tc->topScopeStmt;
     782        17216708 :     for (; stmt; stmt = stmt->downScope) {
     783         3128904 :         if (stmt->type == STMT_WITH)
     784             783 :             break;
     785                 : 
     786                 :         /* Skip "maybe scope" statements that don't contain let bindings. */
     787         3128121 :         if (!(stmt->flags & SIF_SCOPE))
     788               0 :             continue;
     789                 : 
     790         3128121 :         StaticBlockObject &blockObj = *stmt->blockObj;
     791         3128121 :         const Shape *shape = blockObj.nativeLookup(tc->parser->context, ATOM_TO_JSID(atom));
     792         3128121 :         if (shape) {
     793          899378 :             JS_ASSERT(shape->hasShortID());
     794                 : 
     795          899378 :             if (slotp)
     796               0 :                 *slotp = blockObj.stackDepth() + shape->shortid();
     797          899378 :             return stmt;
     798                 :         }
     799                 :     }
     800                 : 
     801        14088587 :     if (slotp)
     802               0 :         *slotp = -1;
     803        14088587 :     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            2360 : 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            2360 :     constp->setMagic(JS_NO_CONSTANT);
     819            7006 :     do {
     820            4697 :         if (bce->inFunction() || bce->compileAndGo()) {
     821                 :             /* XXX this will need revising if 'const' becomes block-scoped. */
     822            2419 :             StmtInfo *stmt = LexicalLookup(bce, atom, NULL);
     823            2419 :             if (stmt)
     824               0 :                 return JS_TRUE;
     825                 : 
     826            2419 :             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            2410 :             if (bce->inFunction()) {
     840            2356 :                 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            2337 :     } while (bce->parent && (bce = bce->parent->asBytecodeEmitter()));
     865            2351 :     return JS_TRUE;
     866                 : }
     867                 : 
     868                 : static bool
     869         2589295 : EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
     870                 : {
     871         2589295 :     const size_t len = 1 + UINT32_INDEX_LEN;
     872         2589295 :     JS_ASSERT(len == size_t(js_CodeSpec[op].length));
     873         2589295 :     ptrdiff_t offset = EmitCheck(cx, bce, len);
     874         2589295 :     if (offset < 0)
     875               0 :         return false;
     876                 : 
     877         2589295 :     jsbytecode *next = bce->next();
     878         2589295 :     next[0] = jsbytecode(op);
     879         2589295 :     SET_UINT32_INDEX(next, index);
     880         2589295 :     bce->current->next = next + len;
     881         2589295 :     UpdateDepth(cx, bce, offset);
     882         2589295 :     CheckTypeSet(cx, bce, op);
     883         2589295 :     return true;
     884                 : }
     885                 : 
     886                 : static bool
     887        26386629 : EmitIndexOp(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
     888                 : {
     889        26386629 :     const size_t len = js_CodeSpec[op].length;
     890        26386629 :     JS_ASSERT(len >= 1 + UINT32_INDEX_LEN);
     891        26386629 :     ptrdiff_t offset = EmitCheck(cx, bce, len);
     892        26386629 :     if (offset < 0)
     893               0 :         return false;
     894                 : 
     895        26386629 :     jsbytecode *next = bce->next();
     896        26386629 :     next[0] = jsbytecode(op);
     897        26386629 :     SET_UINT32_INDEX(next, index);
     898        26386629 :     bce->current->next = next + len;
     899        26386629 :     UpdateDepth(cx, bce, offset);
     900        26386629 :     CheckTypeSet(cx, bce, op);
     901        26386629 :     return true;
     902                 : }
     903                 : 
     904                 : static bool
     905        25022127 : EmitAtomOp(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce)
     906                 : {
     907        25022127 :     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
     908                 : 
     909        25022127 :     if (op == JSOP_GETPROP && atom == cx->runtime->atomState.lengthAtom) {
     910                 :         /* Specialize length accesses for the interpreter. */
     911          163185 :         op = JSOP_LENGTH;
     912                 :     }
     913                 : 
     914                 :     jsatomid index;
     915        25022127 :     if (!bce->makeAtomIndex(atom, &index))
     916               0 :         return false;
     917                 : 
     918        25022127 :     return EmitIndexOp(cx, op, index, bce);
     919                 : }
     920                 : 
     921                 : static bool
     922        25022010 : EmitAtomOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
     923                 : {
     924        25022010 :     JS_ASSERT(pn->pn_atom != NULL);
     925        25022010 :     return EmitAtomOp(cx, pn->pn_atom, op, bce);
     926                 : }
     927                 : 
     928                 : static bool
     929           22755 : EmitAtomIncDec(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce)
     930                 : {
     931           22755 :     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
     932           22755 :     JS_ASSERT(js_CodeSpec[op].format & (JOF_INC | JOF_DEC));
     933                 : 
     934                 :     jsatomid index;
     935           22755 :     if (!bce->makeAtomIndex(atom, &index))
     936               0 :         return false;
     937                 : 
     938           22755 :     const size_t len = 1 + UINT32_INDEX_LEN + 1;
     939           22755 :     JS_ASSERT(size_t(js_CodeSpec[op].length) == len);
     940           22755 :     ptrdiff_t offset = EmitCheck(cx, bce, len);
     941           22755 :     if (offset < 0)
     942               0 :         return false;
     943                 : 
     944           22755 :     jsbytecode *next = bce->next();
     945           22755 :     next[0] = jsbytecode(op);
     946           22755 :     SET_UINT32_INDEX(next, index);
     947           22755 :     bce->current->next = next + len;
     948           22755 :     UpdateDepth(cx, bce, offset);
     949           22755 :     CheckTypeSet(cx, bce, op);
     950           22755 :     return true;
     951                 : }
     952                 : 
     953                 : static bool
     954          915364 : EmitFunctionOp(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
     955                 : {
     956          915364 :     return EmitIndex32(cx, op, index, bce);
     957                 : }
     958                 : 
     959                 : static bool
     960          453929 : EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
     961                 : {
     962          453929 :     JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
     963          453929 :     return EmitIndex32(cx, op, bce->objectList.index(objbox), bce);
     964                 : }
     965                 : 
     966                 : static bool
     967           34050 : EmitRegExp(JSContext *cx, uint32_t index, BytecodeEmitter *bce)
     968                 : {
     969           34050 :     return EmitIndex32(cx, JSOP_REGEXP, index, bce);
     970                 : }
     971                 : 
     972                 : static bool
     973           40990 : EmitSlotObjectOp(JSContext *cx, JSOp op, unsigned slot, uint32_t index, BytecodeEmitter *bce)
     974                 : {
     975           40990 :     JS_ASSERT(JOF_OPTYPE(op) == JOF_SLOTOBJECT);
     976                 : 
     977           40990 :     ptrdiff_t off = EmitN(cx, bce, op, SLOTNO_LEN + UINT32_INDEX_LEN);
     978           40990 :     if (off < 0)
     979               0 :         return false;
     980                 : 
     981           40990 :     jsbytecode *pc = bce->code(off);
     982           40990 :     SET_SLOTNO(pc, slot);
     983           40990 :     pc += SLOTNO_LEN;
     984           40990 :     SET_UINT32_INDEX(pc, index);
     985           40990 :     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         2076395 : BytecodeEmitter::shouldNoteClosedName(ParseNode *pn)
     998                 : {
     999         2076395 :     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          460642 : AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, int slot)
    1012                 : {
    1013          460642 :     JS_ASSERT((unsigned) slot < bce->maxStackDepth);
    1014          460642 :     if (bce->inFunction()) {
    1015          425594 :         slot += bce->bindings.countVars();
    1016          425594 :         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          460642 :     return slot;
    1023                 : }
    1024                 : 
    1025                 : static bool
    1026          446653 : EmitEnterBlock(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSOp op)
    1027                 : {
    1028          446653 :     JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
    1029          446653 :     if (!EmitObjectOp(cx, pn->pn_objbox, op, bce))
    1030               0 :         return false;
    1031                 : 
    1032          446653 :     StaticBlockObject &blockObj = pn->pn_objbox->object->asStaticBlock();
    1033                 : 
    1034                 :     int depth = bce->stackDepth -
    1035          446653 :                 (blockObj.slotCount() + ((op == JSOP_ENTERLET1) ? 1 : 0));
    1036          446653 :     JS_ASSERT(depth >= 0);
    1037                 : 
    1038          446653 :     blockObj.setStackDepth(depth);
    1039                 : 
    1040          446653 :     int depthPlusFixed = AdjustBlockSlot(cx, bce, depth);
    1041          446653 :     if (depthPlusFixed < 0)
    1042               0 :         return false;
    1043                 : 
    1044         1198996 :     for (unsigned i = 0; i < blockObj.slotCount(); i++) {
    1045          752343 :         Definition *dn = blockObj.maybeDefinitionParseNode(i);
    1046          752343 :         blockObj.poisonDefinitionParseNode(i);
    1047                 : 
    1048                 :         /* Beware the empty destructuring dummy. */
    1049          752343 :         if (!dn) {
    1050            3942 :             JS_ASSERT(i + 1 <= blockObj.slotCount());
    1051            3942 :             continue;
    1052                 :         }
    1053                 : 
    1054          748401 :         JS_ASSERT(dn->isDefn());
    1055          748401 :         JS_ASSERT(unsigned(dn->frameSlot() + depthPlusFixed) < JS_BIT(16));
    1056          748401 :         dn->pn_cookie.set(dn->pn_cookie.level(), uint16_t(dn->frameSlot() + depthPlusFixed));
    1057                 : #ifdef DEBUG
    1058         1788213 :         for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
    1059         1039812 :             JS_ASSERT(pnu->pn_lexdef == dn);
    1060         1039812 :             JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
    1061         1039812 :             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          887450 :     if ((bce->flags & TCF_FUN_EXTENSIBLE_SCOPE) ||
    1072          440797 :         bce->bindings.extensibleParents()) {
    1073            8532 :         Shape *newShape = Shape::setExtensibleParents(cx, blockObj.lastProperty());
    1074            8532 :         if (!newShape)
    1075               0 :             return false;
    1076            8532 :         blockObj.setLastPropertyInfallible(newShape);
    1077                 :     }
    1078                 : 
    1079          446653 :     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        12047030 : TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op)
    1105                 : {
    1106        17729753 :     if (bce->compileAndGo() && 
    1107                 :         bce->globalScope->globalObj &&
    1108         1895387 :         !bce->mightAliasLocals() &&
    1109         1893668 :         !pn->isDeoptimized() &&
    1110         1893668 :         !(bce->flags & TCF_STRICT_MODE_CODE)) { 
    1111         1893050 :         switch (*op) {
    1112         1722596 :           case JSOP_NAME:     *op = JSOP_GETGNAME; break;
    1113          117819 :           case JSOP_SETNAME:  *op = JSOP_SETGNAME; break;
    1114            1552 :           case JSOP_INCNAME:  *op = JSOP_INCGNAME; break;
    1115            4768 :           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           46090 :             return false;
    1122               0 :           default: JS_NOT_REACHED("gname");
    1123                 :         }
    1124         1846960 :         return true;
    1125                 :     }
    1126        10153980 :     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           24133 : 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           24133 :     JS_ASSERT(pn->pn_cookie.isFree());
    1137                 : 
    1138           24133 :     if (bce->mightAliasLocals())
    1139              54 :         return true;
    1140                 : 
    1141           24079 :     GlobalScope *globalScope = bce->globalScope;
    1142                 : 
    1143                 :     jsatomid index;
    1144           24079 :     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           24079 :         AtomIndexPtr p = globalScope->names.lookup(atom);
    1148           24079 :         JS_ASSERT(!!p);
    1149           24079 :         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           24079 :     if (!bce->addGlobalUse(atom, index, &pn->pn_cookie))
    1167               0 :         return false;
    1168                 : 
    1169           24079 :     if (!pn->pn_cookie.isFree())
    1170           24079 :         pn->pn_dflags |= PND_BOUND;
    1171                 : 
    1172           24079 :     return true;
    1173                 : }
    1174                 : 
    1175                 : // See BindKnownGlobal()'s comment.
    1176                 : static bool
    1177          207341 : BindGlobal(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSAtom *atom)
    1178                 : {
    1179          207341 :     pn->pn_cookie.makeFree();
    1180                 : 
    1181                 :     Definition *dn;
    1182          207341 :     if (pn->isUsed()) {
    1183           21745 :         dn = pn->pn_lexdef;
    1184                 :     } else {
    1185          185596 :         if (!pn->isDefn())
    1186               0 :             return true;
    1187          185596 :         dn = (Definition *)pn;
    1188                 :     }
    1189                 : 
    1190                 :     // Only optimize for defined globals.
    1191          207341 :     if (!dn->isGlobal())
    1192          183208 :         return true;
    1193                 : 
    1194           24133 :     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        22417247 : BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    1216                 : {
    1217                 :     Definition *dn;
    1218                 :     JSOp op;
    1219                 :     JSAtom *atom;
    1220                 :     Definition::Kind dn_kind;
    1221                 : 
    1222        22417247 :     JS_ASSERT(pn->isKind(PNK_NAME));
    1223                 : 
    1224                 :     /* Idempotency tests come first, since we may be called more than once. */
    1225        22417247 :     if (pn->pn_dflags & PND_BOUND)
    1226         4230559 :         return JS_TRUE;
    1227                 : 
    1228                 :     /* No cookie initialized for these two, they're pre-bound by definition. */
    1229        18186688 :     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        18186688 :     if (pn->isUsed()) {
    1236        17873826 :         JS_ASSERT(pn->pn_cookie.isFree());
    1237        17873826 :         dn = pn->pn_lexdef;
    1238        17873826 :         JS_ASSERT(dn->isDefn());
    1239        17873826 :         if (pn->isDeoptimized())
    1240           16666 :             return JS_TRUE;
    1241        17857160 :         pn->pn_dflags |= (dn->pn_dflags & PND_CONST);
    1242                 :     } else {
    1243          312862 :         if (!pn->isDefn())
    1244             153 :             return JS_TRUE;
    1245          312709 :         dn = (Definition *) pn;
    1246                 :     }
    1247                 : 
    1248        18169869 :     op = pn->getOp();
    1249        18169869 :     if (op == JSOP_NOP)
    1250               0 :         return JS_TRUE;
    1251                 : 
    1252        18169869 :     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
    1253        18169869 :     atom = pn->pn_atom;
    1254        18169869 :     UpvarCookie cookie = dn->pn_cookie;
    1255        18169869 :     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        18169869 :     switch (op) {
    1267                 :       case JSOP_NAME:
    1268                 :       case JSOP_SETCONST:
    1269        17135688 :         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         1033280 :         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        18169851 :     if (dn->isGlobal()) {
    1295          182343 :         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          126115 :             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          182343 :         cookie.makeFree();
    1315                 :     }
    1316                 : 
    1317        18169851 :     if (cookie.isFree()) {
    1318        12070027 :         StackFrame *caller = bce->parser->callerFrame;
    1319        12070027 :         if (caller) {
    1320           25566 :             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           25566 :             if (bce->flags & TCF_IN_FOR_INIT)
    1327             117 :                 return JS_TRUE;
    1328                 : 
    1329           25449 :             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           25449 :             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           23438 :             return JS_TRUE;
    1350                 :         }
    1351                 : 
    1352                 :         /* Optimize accesses to undeclared globals. */
    1353        12044461 :         if (!TryConvertToGname(bce, pn, &op))
    1354        10199512 :             return JS_TRUE;
    1355                 : 
    1356                 :         jsatomid _;
    1357         1844949 :         if (!bce->makeAtomIndex(atom, &_))
    1358               0 :             return JS_FALSE;
    1359                 : 
    1360         1844949 :         pn->setOp(op);
    1361         1844949 :         pn->pn_dflags |= PND_BOUND;
    1362                 : 
    1363         1844949 :         return JS_TRUE;
    1364                 :     }
    1365                 : 
    1366         6099824 :     uint16_t level = cookie.level();
    1367         6099824 :     JS_ASSERT(bce->staticLevel >= level);
    1368                 : 
    1369         6099824 :     const unsigned skip = bce->staticLevel - level;
    1370         6099824 :     if (skip != 0) {
    1371          637247 :         JS_ASSERT(bce->inFunction());
    1372          637247 :         JS_ASSERT_IF(cookie.slot() != UpvarCookie::CALLEE_SLOT, bce->roLexdeps->lookup(atom));
    1373          637247 :         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          637247 :         if (op != JSOP_NAME)
    1380           37640 :             return JS_TRUE;
    1381          599607 :         if (skip >= UpvarCookie::UPVAR_LEVEL_LIMIT)
    1382               0 :             return JS_TRUE;
    1383          599607 :         if (bce->flags & TCF_FUN_HEAVYWEIGHT)
    1384           44725 :             return JS_TRUE;
    1385                 : 
    1386          554882 :         if (!bce->fun()->isFlatClosure())
    1387          362051 :             return JS_TRUE;
    1388                 : 
    1389          192831 :         if (!bce->upvarIndices.ensureMap(cx))
    1390               0 :             return JS_FALSE;
    1391                 : 
    1392          192831 :         AtomIndexAddPtr p = bce->upvarIndices->lookupForAdd(atom);
    1393                 :         jsatomid index;
    1394          192831 :         if (p) {
    1395           80127 :             index = p.value();
    1396                 :         } else {
    1397          112704 :             if (!bce->bindings.addUpvar(cx, atom))
    1398               0 :                 return JS_FALSE;
    1399                 : 
    1400          112704 :             index = bce->upvarIndices->count();
    1401          112704 :             if (!bce->upvarIndices->add(p, atom, index))
    1402               0 :                 return JS_FALSE;
    1403                 : 
    1404          112704 :             UpvarCookies &upvarMap = bce->upvarMap;
    1405                 :             /* upvarMap should have the same number of UpvarCookies as there are lexdeps. */
    1406          112704 :             size_t lexdepCount = bce->roLexdeps->count();
    1407                 : 
    1408          112704 :             JS_ASSERT_IF(!upvarMap.empty(), lexdepCount == upvarMap.length());
    1409          112704 :             if (upvarMap.empty()) {
    1410                 :                 /* Lazily initialize the upvar map with exactly the necessary capacity. */
    1411           83617 :                 if (lexdepCount <= upvarMap.sMaxInlineStorage) {
    1412           83522 :                     JS_ALWAYS_TRUE(upvarMap.growByUninitialized(lexdepCount));
    1413                 :                 } else {
    1414              95 :                     void *buf = upvarMap.allocPolicy().malloc_(lexdepCount * sizeof(UpvarCookie));
    1415              95 :                     if (!buf)
    1416               0 :                         return JS_FALSE;
    1417              95 :                     upvarMap.replaceRawBuffer(static_cast<UpvarCookie *>(buf), lexdepCount);
    1418                 :                 }
    1419          289527 :                 for (size_t i = 0; i < lexdepCount; ++i)
    1420          205910 :                     upvarMap[i] = UpvarCookie();
    1421                 :             }
    1422                 : 
    1423          112704 :             unsigned slot = cookie.slot();
    1424          112704 :             if (slot != UpvarCookie::CALLEE_SLOT && dn_kind != Definition::ARG) {
    1425           37357 :                 TreeContext *tc = bce;
    1426           37359 :                 do {
    1427           37359 :                     tc = tc->parent;
    1428                 :                 } while (tc->staticLevel != level);
    1429           37357 :                 if (tc->inFunction())
    1430           37327 :                     slot += tc->fun()->nargs;
    1431                 :             }
    1432                 : 
    1433          112704 :             JS_ASSERT(index < upvarMap.length());
    1434          112704 :             upvarMap[index].set(skip, slot);
    1435                 :         }
    1436                 : 
    1437          192831 :         pn->setOp(JSOP_GETFCSLOT);
    1438          192831 :         JS_ASSERT((index & JS_BITMASK(16)) == index);
    1439          192831 :         pn->pn_cookie.set(0, index);
    1440          192831 :         pn->pn_dflags |= PND_BOUND;
    1441          192831 :         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         5462577 :     switch (dn_kind) {
    1450                 :       case Definition::UNKNOWN:
    1451               0 :         return JS_TRUE;
    1452                 : 
    1453                 :       case Definition::LET:
    1454          958066 :         switch (op) {
    1455          841646 :           case JSOP_NAME:     op = JSOP_GETLOCAL; break;
    1456           84626 :           case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
    1457            4561 :           case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
    1458           26027 :           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          958066 :         break;
    1464                 : 
    1465                 :       case Definition::ARG:
    1466         2070654 :         switch (op) {
    1467         2020711 :           case JSOP_NAME:     op = JSOP_GETARG; break;
    1468           48428 :           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         2070654 :         JS_ASSERT(!pn->isConst());
    1476         2070654 :         break;
    1477                 : 
    1478                 :       case Definition::VAR:
    1479         2351764 :         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         2432044 :                      dn_kind == Definition::CONST);
    1523         2432044 :         switch (op) {
    1524         1939216 :           case JSOP_NAME:     op = JSOP_GETLOCAL; break;
    1525          455457 :           case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
    1526               0 :           case JSOP_SETCONST: op = JSOP_SETLOCAL; break;
    1527            7991 :           case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
    1528           28611 :           case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
    1529             314 :           case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
    1530             455 :           case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
    1531               0 :           default: JS_NOT_REACHED("local");
    1532                 :         }
    1533         2432044 :         JS_ASSERT_IF(dn_kind == Definition::CONST, pn->pn_dflags & PND_CONST);
    1534         2432044 :         break;
    1535                 :     }
    1536                 : 
    1537         5460764 :     JS_ASSERT(!pn->isOp(op));
    1538         5460764 :     pn->setOp(op);
    1539         5460764 :     pn->pn_cookie.set(0, cookie.slot());
    1540         5460764 :     pn->pn_dflags |= PND_BOUND;
    1541         5460764 :     return JS_TRUE;
    1542                 : }
    1543                 : 
    1544                 : bool
    1545           24079 : BytecodeEmitter::addGlobalUse(JSAtom *atom, uint32_t slot, UpvarCookie *cookie)
    1546                 : {
    1547           24079 :     if (!globalMap.ensureMap(context()))
    1548               0 :         return false;
    1549                 : 
    1550           24079 :     AtomIndexAddPtr p = globalMap->lookupForAdd(atom);
    1551           24079 :     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           23728 :     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           23728 :     if (!makeAtomIndex(atom, &allAtomIndex))
    1566               0 :         return false;
    1567                 : 
    1568           23728 :     jsatomid globalUseIndex = globalUses.length();
    1569           23728 :     cookie->set(0, globalUseIndex);
    1570                 : 
    1571           23728 :     GlobalSlotArray::Entry entry = { allAtomIndex, slot };
    1572           23728 :     if (!globalUses.append(entry))
    1573               0 :         return false;
    1574                 : 
    1575           23728 :     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         6587134 : CheckSideEffects(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSBool *answer)
    1592                 : {
    1593                 :     JSBool ok;
    1594                 :     ParseNode *pn2;
    1595                 : 
    1596         6587134 :     ok = JS_TRUE;
    1597         6587134 :     if (!pn || *answer)
    1598          154546 :         return ok;
    1599                 : 
    1600         6432588 :     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           37771 :         *answer = JS_FALSE;
    1610           37771 :         break;
    1611                 : 
    1612                 :       case PN_LIST:
    1613         5600967 :         if (pn->isOp(JSOP_NOP) || pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) ||
    1614         3732418 :             pn->isOp(JSOP_STRICTEQ) || pn->isOp(JSOP_STRICTNE)) {
    1615                 :             /*
    1616                 :              * Non-operators along with ||, &&, ===, and !== never invoke
    1617                 :              * toString or valueOf.
    1618                 :              */
    1619            5614 :             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
    1620            3274 :                 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         1866209 :             *answer = JS_TRUE;
    1639                 :         }
    1640         1868549 :         break;
    1641                 : 
    1642                 :       case PN_TERNARY:
    1643            6316 :         ok = CheckSideEffects(cx, bce, pn->pn_kid1, answer) &&
    1644            6316 :              CheckSideEffects(cx, bce, pn->pn_kid2, answer) &&
    1645           12632 :              CheckSideEffects(cx, bce, pn->pn_kid3, answer);
    1646            6316 :         break;
    1647                 : 
    1648                 :       case PN_BINARY:
    1649         2435656 :         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         2377139 :             pn2 = pn->pn_left;
    1660         2377139 :             if (!pn2->isKind(PNK_NAME)) {
    1661         1745557 :                 *answer = JS_TRUE;
    1662                 :             } else {
    1663          631582 :                 if (!BindNameToSlot(cx, bce, pn2))
    1664               0 :                     return JS_FALSE;
    1665          631582 :                 if (!CheckSideEffects(cx, bce, pn->pn_right, answer))
    1666               0 :                     return JS_FALSE;
    1667          631582 :                 if (!*answer && (!pn->isOp(JSOP_NOP) || !pn2->isConst()))
    1668          375508 :                     *answer = JS_TRUE;
    1669                 :             }
    1670                 :         } else {
    1671          109036 :             if (pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) || pn->isOp(JSOP_STRICTEQ) ||
    1672           50519 :                 pn->isOp(JSOP_STRICTNE)) {
    1673                 :                 /*
    1674                 :                  * ||, &&, ===, and !== do not convert their operands via
    1675                 :                  * toString or valueOf method calls.
    1676                 :                  */
    1677            8025 :                 ok = CheckSideEffects(cx, bce, pn->pn_left, answer) &&
    1678            8025 :                      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           50492 :                 *answer = JS_TRUE;
    1685                 :             }
    1686                 :         }
    1687         2435656 :         break;
    1688                 : 
    1689                 :       case PN_UNARY:
    1690         1667139 :         switch (pn->getKind()) {
    1691                 :           case PNK_DELETE:
    1692           37421 :             pn2 = pn->pn_kid;
    1693           37421 :             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           23343 :                 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           37421 :                 *answer = JS_TRUE;
    1713           37421 :                 break;
    1714                 :               default:
    1715               0 :                 ok = CheckSideEffects(cx, bce, pn2, answer);
    1716               0 :                 break;
    1717                 :             }
    1718           37421 :             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         1626313 :             *answer = JS_TRUE;
    1739         1626313 :             break;
    1740                 :         }
    1741         1667139 :         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          139522 :         if (pn->isKind(PNK_NAME) && !pn->isOp(JSOP_NOP)) {
    1750           76275 :             if (!BindNameToSlot(cx, bce, pn))
    1751               0 :                 return JS_FALSE;
    1752          152433 :             if (!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE) &&
    1753           76158 :                 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            6144 :                 *answer = JS_TRUE;
    1760                 :             }
    1761                 :         }
    1762          139522 :         pn2 = pn->maybeExpr();
    1763          139522 :         if (pn->isKind(PNK_DOT)) {
    1764           63247 :             if (pn2->isKind(PNK_NAME) && !BindNameToSlot(cx, bce, pn2))
    1765               0 :                 return JS_FALSE;
    1766          126485 :             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           63238 :                 *answer = JS_TRUE;
    1773                 :             }
    1774                 :         }
    1775          139522 :         ok = CheckSideEffects(cx, bce, pn2, answer);
    1776          139522 :         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          277635 :         if (pn->isKind(PNK_DEBUGGER))
    1784               0 :             *answer = JS_TRUE;
    1785          277635 :         break;
    1786                 :     }
    1787         6432588 :     return ok;
    1788                 : }
    1789                 : 
    1790                 : bool
    1791          674054 : BytecodeEmitter::needsImplicitThis()
    1792                 : {
    1793          674054 :     if (!compileAndGo())
    1794          668631 :         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        13083746 : EmitNameOp(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSBool callContext)
    1816                 : {
    1817                 :     JSOp op;
    1818                 : 
    1819        13083746 :     if (!BindNameToSlot(cx, bce, pn))
    1820               0 :         return JS_FALSE;
    1821        13083746 :     op = pn->getOp();
    1822                 : 
    1823        13083746 :     if (callContext) {
    1824          860698 :         switch (op) {
    1825                 :           case JSOP_NAME:
    1826          674054 :             op = JSOP_CALLNAME;
    1827          674054 :             break;
    1828                 :           case JSOP_GETGNAME:
    1829          102629 :             op = JSOP_CALLGNAME;
    1830          102629 :             break;
    1831                 :           case JSOP_GETARG:
    1832           17061 :             op = JSOP_CALLARG;
    1833           17061 :             break;
    1834                 :           case JSOP_GETLOCAL:
    1835           44945 :             op = JSOP_CALLLOCAL;
    1836           44945 :             break;
    1837                 :           case JSOP_GETFCSLOT:
    1838           21558 :             op = JSOP_CALLFCSLOT;
    1839           21558 :             break;
    1840                 :           default:
    1841             451 :             JS_ASSERT(op == JSOP_ARGUMENTS || op == JSOP_CALLEE);
    1842             451 :             break;
    1843                 :         }
    1844                 :     }
    1845                 : 
    1846        13083746 :     if (op == JSOP_ARGUMENTS) {
    1847           13766 :         if (!EmitArguments(cx, bce))
    1848               0 :             return JS_FALSE;
    1849        13069980 :     } else if (op == JSOP_CALLEE) {
    1850            1774 :         if (Emit1(cx, bce, op) < 0)
    1851               0 :             return JS_FALSE;
    1852                 :     } else {
    1853        13068206 :         if (!pn->pn_cookie.isFree()) {
    1854         4994802 :             JS_ASSERT(JOF_OPTYPE(op) != JOF_ATOM);
    1855         4994802 :             EMIT_UINT16_IMM_OP(op, pn->pn_cookie.slot());
    1856                 :         } else {
    1857         8073404 :             if (!EmitAtomOp(cx, pn, op, bce))
    1858               0 :                 return JS_FALSE;
    1859                 :         }
    1860                 :     }
    1861                 : 
    1862                 :     /* Need to provide |this| value for call */
    1863        13083746 :     if (callContext) {
    1864          860698 :         if (op == JSOP_CALLNAME && bce->needsImplicitThis()) {
    1865          668838 :             if (!EmitAtomOp(cx, pn, JSOP_IMPLICITTHIS, bce))
    1866               0 :                 return false;
    1867                 :         } else {
    1868          191860 :             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    1869               0 :                 return false;
    1870                 :         }
    1871                 :     }
    1872                 : 
    1873        13083746 :     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         5242502 : EmitElemOpBase(JSContext *cx, BytecodeEmitter *bce, JSOp op)
    1903                 : {
    1904         5242502 :     if (Emit1(cx, bce, op) < 0)
    1905               0 :         return false;
    1906         5242502 :     CheckTypeSet(cx, bce, op);
    1907         5242502 :     if (op == JSOP_CALLELEM)
    1908            4731 :         return Emit1(cx, bce, JSOP_SWAP) >= 0;
    1909         5237771 :     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         8183264 : 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         8183264 :     JS_ASSERT(pn->isArity(PN_NAME));
    1940         8183264 :     pn2 = pn->maybeExpr();
    1941                 : 
    1942                 :     /* Special case deoptimization for __proto__. */
    1943         8183264 :     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         8182937 :     if (callContext) {
    1951         2297637 :         JS_ASSERT(pn->isKind(PNK_DOT));
    1952         2297637 :         JS_ASSERT(op == JSOP_GETPROP);
    1953         2297637 :         op = JSOP_CALLPROP;
    1954         5885300 :     } else if (op == JSOP_GETPROP && pn->isKind(PNK_DOT)) {
    1955         5857511 :         if (pn2->isKind(PNK_NAME)) {
    1956         4856575 :             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         8182937 :     if (pn2->isKind(PNK_DOT)) {
    1967         1036214 :         pndot = pn2;
    1968         1036214 :         pnup = NULL;
    1969         1036214 :         top = bce->offset();
    1970           54144 :         for (;;) {
    1971                 :             /* Reverse pndot->pn_expr to point up, not down. */
    1972         1090358 :             pndot->pn_offset = top;
    1973         1090358 :             JS_ASSERT(!pndot->isUsed());
    1974         1090358 :             pndown = pndot->pn_expr;
    1975         1090358 :             pndot->pn_expr = pnup;
    1976         1090358 :             if (!pndown->isKind(PNK_DOT))
    1977                 :                 break;
    1978           54144 :             pnup = pndot;
    1979           54144 :             pndot = pndown;
    1980                 :         }
    1981                 : 
    1982                 :         /* pndown is a primary expression, not a dotted property reference. */
    1983         1036214 :         if (!EmitTree(cx, bce, pndown))
    1984               0 :             return false;
    1985                 : 
    1986         1090358 :         do {
    1987                 :             /* Walk back up the list, emitting annotated name ops. */
    1988         1090358 :             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         1090358 :             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         1090297 :             } else if (!EmitAtomOp(cx, pndot, pndot->getOp(), bce)) {
    1996               0 :                 return false;
    1997                 :             }
    1998                 : 
    1999                 :             /* Reverse the pn_expr link again. */
    2000         1090358 :             pnup = pndot->pn_expr;
    2001         1090358 :             pndot->pn_expr = pndown;
    2002         1090358 :             pndown = pndot;
    2003                 :         } while ((pndot = pnup) != NULL);
    2004                 :     } else {
    2005         7146723 :         if (!EmitTree(cx, bce, pn2))
    2006               0 :             return false;
    2007                 :     }
    2008                 : 
    2009         8182937 :     if (op == JSOP_CALLPROP && Emit1(cx, bce, JSOP_DUP) < 0)
    2010               0 :         return false;
    2011                 : 
    2012         8182937 :     if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pn2->pn_offset) < 0)
    2013               0 :         return false;
    2014                 : 
    2015         8182937 :     if (!EmitAtomOp(cx, pn, op, bce))
    2016               0 :         return false;
    2017                 : 
    2018         8182937 :     if (op == JSOP_CALLPROP && Emit1(cx, bce, JSOP_SWAP) < 0)
    2019               0 :         return false;
    2020                 : 
    2021         8182937 :     return true;
    2022                 : }
    2023                 : 
    2024                 : static bool
    2025            4874 : EmitPropIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
    2026                 : {
    2027            4874 :     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            4874 :     int start = bce->offset();
    2035                 : 
    2036            4874 :     const JSCodeSpec *cs = &js_CodeSpec[op];
    2037            4874 :     JS_ASSERT(cs->format & JOF_PROP);
    2038            4874 :     JS_ASSERT(cs->format & (JOF_INC | JOF_DEC));
    2039                 : 
    2040            4874 :     bool post = (cs->format & JOF_POST);
    2041            4874 :     JSOp binop = (cs->format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
    2042                 : 
    2043                 :                                                     // OBJ
    2044            4874 :     if (Emit1(cx, bce, JSOP_DUP) < 0)               // OBJ OBJ
    2045               0 :         return false;
    2046            4874 :     if (!EmitAtomOp(cx, pn, JSOP_GETPROP, bce))     // OBJ V
    2047               0 :         return false;
    2048            4874 :     if (Emit1(cx, bce, JSOP_POS) < 0)               // OBJ N
    2049               0 :         return false;
    2050            4874 :     if (post && Emit1(cx, bce, JSOP_DUP) < 0)       // OBJ N? N
    2051               0 :         return false;
    2052            4874 :     if (Emit1(cx, bce, JSOP_ONE) < 0)               // OBJ N? N 1
    2053               0 :         return false;
    2054            4874 :     if (Emit1(cx, bce, binop) < 0)                  // OBJ N? N+1
    2055               0 :         return false;
    2056                 : 
    2057            4874 :     if (post) {
    2058            4386 :         if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)   // N? N+1 OBJ
    2059               0 :             return false;
    2060            4386 :         if (Emit1(cx, bce, JSOP_SWAP) < 0)                  // N? OBJ N+1
    2061               0 :             return false;
    2062                 :     }
    2063                 : 
    2064            4874 :     if (!EmitAtomOp(cx, pn, JSOP_SETPROP, bce))     // N? N+1
    2065               0 :         return false;
    2066            4874 :     if (post && Emit1(cx, bce, JSOP_POP) < 0)       // RESULT
    2067               0 :         return false;
    2068                 : 
    2069            4874 :     UpdateDecomposeLength(bce, start);
    2070                 : 
    2071            4874 :     return true;
    2072                 : }
    2073                 : 
    2074                 : static bool
    2075           22755 : EmitNameIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
    2076                 : {
    2077                 :     /* Emit the composite op, including the slack byte at the end. */
    2078           22755 :     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           22755 :     bce->stackDepth--;
    2083                 : 
    2084           22755 :     int start = bce->offset();
    2085                 : 
    2086           22755 :     const JSCodeSpec *cs = &js_CodeSpec[op];
    2087           22755 :     JS_ASSERT((cs->format & JOF_NAME) || (cs->format & JOF_GNAME));
    2088           22755 :     JS_ASSERT(cs->format & (JOF_INC | JOF_DEC));
    2089                 : 
    2090           22755 :     bool global = (cs->format & JOF_GNAME);
    2091           22755 :     bool post = (cs->format & JOF_POST);
    2092           22755 :     JSOp binop = (cs->format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
    2093                 : 
    2094           22755 :     if (!EmitAtomOp(cx, pn, global ? JSOP_BINDGNAME : JSOP_BINDNAME, bce))  // OBJ
    2095               0 :         return false;
    2096           22755 :     if (!EmitAtomOp(cx, pn, global ? JSOP_GETGNAME : JSOP_NAME, bce))       // OBJ V
    2097               0 :         return false;
    2098           22755 :     if (Emit1(cx, bce, JSOP_POS) < 0)               // OBJ N
    2099               0 :         return false;
    2100           22755 :     if (post && Emit1(cx, bce, JSOP_DUP) < 0)       // OBJ N? N
    2101               0 :         return false;
    2102           22755 :     if (Emit1(cx, bce, JSOP_ONE) < 0)               // OBJ N? N 1
    2103               0 :         return false;
    2104           22755 :     if (Emit1(cx, bce, binop) < 0)                  // OBJ N? N+1
    2105               0 :         return false;
    2106                 : 
    2107           22755 :     if (post) {
    2108            9165 :         if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)   // N? N+1 OBJ
    2109               0 :             return false;
    2110            9165 :         if (Emit1(cx, bce, JSOP_SWAP) < 0)                  // N? OBJ N+1
    2111               0 :             return false;
    2112                 :     }
    2113                 : 
    2114           22755 :     if (!EmitAtomOp(cx, pn, global ? JSOP_SETGNAME : JSOP_SETNAME, bce))    // N? N+1
    2115               0 :         return false;
    2116           22755 :     if (post && Emit1(cx, bce, JSOP_POP) < 0)       // RESULT
    2117               0 :         return false;
    2118                 : 
    2119           22755 :     UpdateDecomposeLength(bce, start);
    2120                 : 
    2121           22755 :     return true;
    2122                 : }
    2123                 : 
    2124                 : static JSBool
    2125         1931543 : EmitElemOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
    2126                 : {
    2127                 :     ParseNode *left, *right;
    2128                 : 
    2129         1931543 :     ptrdiff_t top = bce->offset();
    2130                 : 
    2131         1931543 :     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         1930338 :         JS_ASSERT(pn->isArity(PN_BINARY));
    2156         1930338 :         left = pn->pn_left;
    2157         1930338 :         right = pn->pn_right;
    2158                 :     }
    2159                 : 
    2160         1931543 :     if (op == JSOP_GETELEM && left->isKind(PNK_NAME) && right->isKind(PNK_NUMBER)) {
    2161           36733 :         if (!BindNameToSlot(cx, bce, left))
    2162               0 :             return false;
    2163                 :     }
    2164                 : 
    2165         1931543 :     if (!EmitTree(cx, bce, left))
    2166               0 :         return false;
    2167                 : 
    2168         1931543 :     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         1931561 :               right->isOp(JSOP_QNAMEPART));
    2174         1931543 :     if (!EmitTree(cx, bce, right))
    2175               0 :         return false;
    2176         1931543 :     if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - top) < 0)
    2177               0 :         return false;
    2178         1931543 :     return EmitElemOpBase(cx, bce, op);
    2179                 : }
    2180                 : 
    2181                 : static bool
    2182         1638860 : EmitElemIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
    2183                 : {
    2184         1638860 :     if (pn) {
    2185         1638851 :         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         1638860 :     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         1638860 :     bce->stackDepth++;
    2196                 : 
    2197         1638860 :     int start = bce->offset();
    2198                 : 
    2199         1638860 :     const JSCodeSpec *cs = &js_CodeSpec[op];
    2200         1638860 :     JS_ASSERT(cs->format & JOF_ELEM);
    2201         1638860 :     JS_ASSERT(cs->format & (JOF_INC | JOF_DEC));
    2202                 : 
    2203         1638860 :     bool post = (cs->format & JOF_POST);
    2204         1638860 :     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         1638860 :     if (Emit1(cx, bce, JSOP_TOID) < 0)              // OBJ KEY
    2212               0 :         return false;
    2213         1638860 :     if (Emit1(cx, bce, JSOP_DUP2) < 0)              // OBJ KEY OBJ KEY
    2214               0 :         return false;
    2215         1638860 :     if (!EmitElemOpBase(cx, bce, JSOP_GETELEM))     // OBJ KEY V
    2216               0 :         return false;
    2217         1638860 :     if (Emit1(cx, bce, JSOP_POS) < 0)               // OBJ KEY N
    2218               0 :         return false;
    2219         1638860 :     if (post && Emit1(cx, bce, JSOP_DUP) < 0)       // OBJ KEY N? N
    2220               0 :         return false;
    2221         1638860 :     if (Emit1(cx, bce, JSOP_ONE) < 0)               // OBJ KEY N? N 1
    2222               0 :         return false;
    2223         1638860 :     if (Emit1(cx, bce, binop) < 0)                  // OBJ KEY N? N+1
    2224               0 :         return false;
    2225                 : 
    2226         1638860 :     if (post) {
    2227         1638743 :         if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)3) < 0)   // KEY N N+1 OBJ
    2228               0 :             return false;
    2229         1638743 :         if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)3) < 0)   // N N+1 OBJ KEY
    2230               0 :             return false;
    2231         1638743 :         if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)2) < 0)   // N OBJ KEY N+1
    2232               0 :             return false;
    2233                 :     }
    2234                 : 
    2235         1638860 :     if (!EmitElemOpBase(cx, bce, JSOP_SETELEM))     // N? N+1
    2236               0 :         return false;
    2237         1638860 :     if (post && Emit1(cx, bce, JSOP_POP) < 0)       // RESULT
    2238               0 :         return false;
    2239                 : 
    2240         1638860 :     UpdateDecomposeLength(bce, start);
    2241                 : 
    2242         1638860 :     return true;
    2243                 : }
    2244                 : 
    2245                 : static JSBool
    2246        11210671 : 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        11210671 :     if (JSDOUBLE_IS_INT32(dval, &ival)) {
    2254        11199202 :         if (ival == 0)
    2255         2131128 :             return Emit1(cx, bce, JSOP_ZERO) >= 0;
    2256         9068074 :         if (ival == 1)
    2257          298640 :             return Emit1(cx, bce, JSOP_ONE) >= 0;
    2258         8769434 :         if ((int)(int8_t)ival == ival)
    2259         1468828 :             return Emit2(cx, bce, JSOP_INT8, (jsbytecode)(int8_t)ival) >= 0;
    2260                 : 
    2261         7300606 :         u = (uint32_t)ival;
    2262         7300606 :         if (u < JS_BIT(16)) {
    2263         7291105 :             EMIT_UINT16_IMM_OP(JSOP_UINT16, u);
    2264            9501 :         } else if (u < JS_BIT(24)) {
    2265            3392 :             off = EmitN(cx, bce, JSOP_UINT24, 3);
    2266            3392 :             if (off < 0)
    2267               0 :                 return JS_FALSE;
    2268            3392 :             pc = bce->code(off);
    2269            3392 :             SET_UINT24(pc, u);
    2270                 :         } else {
    2271            6109 :             off = EmitN(cx, bce, JSOP_INT32, 4);
    2272            6109 :             if (off < 0)
    2273               0 :                 return JS_FALSE;
    2274            6109 :             pc = bce->code(off);
    2275            6109 :             SET_INT32(pc, ival);
    2276                 :         }
    2277         7300606 :         return JS_TRUE;
    2278                 :     }
    2279                 : 
    2280           11469 :     if (!bce->constList.append(DoubleValue(dval)))
    2281               0 :         return JS_FALSE;
    2282                 : 
    2283           11469 :     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           48116 : AllocateSwitchConstant(JSContext *cx)
    2296                 : {
    2297           48116 :     return cx->tempLifoAlloc().new_<Value>();
    2298                 : }
    2299                 : 
    2300                 : static inline void
    2301         1287127 : SetJumpOffsetAt(BytecodeEmitter *bce, ptrdiff_t off)
    2302                 : {
    2303         1287127 :     SET_JUMP_OFFSET(bce->code(off), bce->offset() - off);
    2304         1287127 : }
    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           17231 : 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           17231 :     switchOp = JSOP_TABLESWITCH;
    2328           17231 :     ok = JS_TRUE;
    2329           17231 :     hasDefault = constPropagated = JS_FALSE;
    2330           17231 :     defaultOffset = -1;
    2331                 : 
    2332           17231 :     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           17231 :     uint32_t blockObjCount = 0;
    2339           17231 :     if (pn2->isKind(PNK_LEXICALSCOPE)) {
    2340            3521 :         blockObjCount = pn2->pn_objbox->object->asStaticBlock().slotCount();
    2341           13957 :         for (uint32_t i = 0; i < blockObjCount; ++i) {
    2342           10436 :             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    2343               0 :                 return JS_FALSE;
    2344                 :         }
    2345                 :     }
    2346                 : #endif
    2347                 : 
    2348                 :     /* Push the discriminant. */
    2349           17231 :     if (!EmitTree(cx, bce, pn->pn_left))
    2350               0 :         return JS_FALSE;
    2351                 : 
    2352                 : #if JS_HAS_BLOCK_SCOPE
    2353           17231 :     if (pn2->isKind(PNK_LEXICALSCOPE)) {
    2354            3521 :         PushBlockScope(bce, &stmtInfo, pn2->pn_objbox->object->asStaticBlock(), -1);
    2355            3521 :         stmtInfo.type = STMT_SWITCH;
    2356            3521 :         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           17231 :     top = bce->offset();
    2363                 : #if !JS_HAS_BLOCK_SCOPE
    2364                 :     PushStatement(bce, &stmtInfo, STMT_SWITCH, top);
    2365                 : #else
    2366           17231 :     if (pn2->isKind(PNK_STATEMENTLIST)) {
    2367           13710 :         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            3521 :         stmtInfo.update = top = bce->offset();
    2374                 : 
    2375                 :         /* Advance pn2 to refer to the switch case list. */
    2376            3521 :         pn2 = pn2->expr();
    2377                 :     }
    2378                 : #endif
    2379                 : 
    2380           17231 :     caseCount = pn2->pn_count;
    2381           17231 :     tableLength = 0;
    2382           17231 :     table = NULL;
    2383                 : 
    2384           17641 :     if (caseCount == 0 ||
    2385                 :         (caseCount == 1 &&
    2386             410 :          (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           17150 :         jsbitmap *intmap = NULL;
    2394           17150 :         int32_t intmap_bitlen = 0;
    2395                 : 
    2396           17150 :         low  = JSVAL_INT_MAX;
    2397           17150 :         high = JSVAL_INT_MIN;
    2398                 : 
    2399          101667 :         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    2400           84517 :             if (pn3->isKind(PNK_DEFAULT)) {
    2401            9477 :                 hasDefault = JS_TRUE;
    2402            9477 :                 caseCount--;    /* one of the "cases" was the default */
    2403            9477 :                 continue;
    2404                 :             }
    2405                 : 
    2406           75040 :             JS_ASSERT(pn3->isKind(PNK_CASE));
    2407           75040 :             if (switchOp == JSOP_CONDSWITCH)
    2408           19911 :                 continue;
    2409                 : 
    2410           55129 :             pn4 = pn3->pn_left;
    2411          110258 :             while (pn4->isKind(PNK_RP))
    2412               0 :                 pn4 = pn4->pn_kid;
    2413                 : 
    2414                 :             Value constVal;
    2415           55129 :             switch (pn4->getKind()) {
    2416                 :               case PNK_NUMBER:
    2417            4958 :                 constVal.setNumber(pn4->pn_dval);
    2418            4958 :                 break;
    2419                 :               case PNK_STRING:
    2420           43027 :                 constVal.setString(pn4->pn_atom);
    2421           43027 :                 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            2360 :                 if (!pn4->maybeExpr()) {
    2433            2360 :                     ok = LookupCompileTimeConstant(cx, bce, pn4->pn_atom, &constVal);
    2434            2360 :                     if (!ok)
    2435               0 :                         goto release;
    2436            2360 :                     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            7013 :                 switchOp = JSOP_CONDSWITCH;
    2452            7013 :                 continue;
    2453                 :             }
    2454           48116 :             JS_ASSERT(constVal.isPrimitive());
    2455                 : 
    2456           48116 :             pn3->pn_pval = AllocateSwitchConstant(cx);
    2457           48116 :             if (!pn3->pn_pval) {
    2458               0 :                 ok = JS_FALSE;
    2459               0 :                 goto release;
    2460                 :             }
    2461                 : 
    2462           48116 :             *pn3->pn_pval = constVal;
    2463                 : 
    2464           48116 :             if (switchOp != JSOP_TABLESWITCH)
    2465           34259 :                 continue;
    2466           13857 :             if (!pn3->pn_pval->isInt32()) {
    2467            8881 :                 switchOp = JSOP_LOOKUPSWITCH;
    2468            8881 :                 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           17150 :         if (intmap && intmap != intmap_space)
    2514              28 :             cx->free_(intmap);
    2515           17150 :         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           17150 :         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           15763 :         } 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            8750 :             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           17231 :     noteIndex = NewSrcNote3(cx, bce, SRC_SWITCH, 0, 0);
    2543           17231 :     if (noteIndex < 0)
    2544               0 :         return JS_FALSE;
    2545                 : 
    2546           17231 :     if (switchOp == JSOP_CONDSWITCH) {
    2547                 :         /*
    2548                 :          * 0 bytes of immediate for unoptimized ECMAv2 switch.
    2549                 :          */
    2550            7013 :         switchSize = 0;
    2551           10218 :     } 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            8910 :                               (UINT32_INDEX_LEN + JUMP_OFFSET_LEN) * caseCount);
    2564                 :     }
    2565                 : 
    2566                 :     /* Emit switchOp followed by switchSize bytes of jump or lookup table. */
    2567           17231 :     if (EmitN(cx, bce, switchOp, switchSize) < 0)
    2568               0 :         return JS_FALSE;
    2569                 : 
    2570           17231 :     off = -1;
    2571           17231 :     if (switchOp == JSOP_CONDSWITCH) {
    2572            7013 :         int caseNoteIndex = -1;
    2573            7013 :         JSBool beforeCases = JS_TRUE;
    2574                 : 
    2575                 :         /* Emit code for evaluating cases and jumping to case statements. */
    2576           37871 :         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    2577           30858 :             pn4 = pn3->pn_left;
    2578           30858 :             if (pn4 && !EmitTree(cx, bce, pn4))
    2579               0 :                 return JS_FALSE;
    2580           30858 :             if (caseNoteIndex >= 0) {
    2581                 :                 /* off is the previous JSOP_CASE's bytecode offset. */
    2582           23457 :                 if (!SetSrcNoteOffset(cx, bce, (unsigned)caseNoteIndex, 0, bce->offset() - off))
    2583               0 :                     return JS_FALSE;
    2584                 :             }
    2585           30858 :             if (!pn4) {
    2586            3776 :                 JS_ASSERT(pn3->isKind(PNK_DEFAULT));
    2587            3776 :                 continue;
    2588                 :             }
    2589           27082 :             caseNoteIndex = NewSrcNote2(cx, bce, SRC_PCDELTA, 0);
    2590           27082 :             if (caseNoteIndex < 0)
    2591               0 :                 return JS_FALSE;
    2592           27082 :             off = EmitJump(cx, bce, JSOP_CASE, 0);
    2593           27082 :             if (off < 0)
    2594               0 :                 return JS_FALSE;
    2595           27082 :             pn3->pn_offset = off;
    2596           27082 :             if (beforeCases) {
    2597                 :                 unsigned noteCount, noteCountDelta;
    2598                 : 
    2599                 :                 /* Switch note's second offset is to first JSOP_CASE. */
    2600            7013 :                 noteCount = bce->noteCount();
    2601            7013 :                 if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 1, off - top))
    2602               0 :                     return JS_FALSE;
    2603            7013 :                 noteCountDelta = bce->noteCount() - noteCount;
    2604            7013 :                 if (noteCountDelta != 0)
    2605               0 :                     caseNoteIndex += noteCountDelta;
    2606            7013 :                 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           10250 :         if (!hasDefault &&
    2617                 :             caseNoteIndex >= 0 &&
    2618            3237 :             !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            7013 :         defaultOffset = EmitJump(cx, bce, JSOP_DEFAULT, 0);
    2625            7013 :         if (defaultOffset < 0)
    2626               0 :             return JS_FALSE;
    2627                 :     } else {
    2628           10218 :         pc = bce->code(top + JUMP_OFFSET_LEN);
    2629                 : 
    2630           10218 :         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            8910 :             JS_ASSERT(switchOp == JSOP_LOOKUPSWITCH);
    2659                 : 
    2660                 :             /* Fill in the number of cases. */
    2661            8910 :             SET_UINT16(pc, caseCount);
    2662            8910 :             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           10218 :         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          101784 :     for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    2720           84553 :         if (switchOp == JSOP_CONDSWITCH && !pn3->isKind(PNK_DEFAULT))
    2721           27082 :             SetJumpOffsetAt(bce, pn3->pn_offset);
    2722           84553 :         pn4 = pn3->pn_right;
    2723           84553 :         ok = EmitTree(cx, bce, pn4);
    2724           84553 :         if (!ok)
    2725               0 :             goto out;
    2726           84553 :         pn3->pn_offset = pn4->pn_offset;
    2727           84553 :         if (pn3->isKind(PNK_DEFAULT))
    2728            9513 :             off = pn3->pn_offset - top;
    2729                 :     }
    2730                 : 
    2731           17231 :     if (!hasDefault) {
    2732                 :         /* If no default case, offset for default is to end of switch. */
    2733            7718 :         off = bce->offset() - top;
    2734                 :     }
    2735                 : 
    2736                 :     /* We better have set "off" by now. */
    2737           17231 :     JS_ASSERT(off != -1);
    2738                 : 
    2739                 :     /* Set the default offset (to end of switch if no default). */
    2740           17231 :     if (switchOp == JSOP_CONDSWITCH) {
    2741            7013 :         pc = NULL;
    2742            7013 :         JS_ASSERT(defaultOffset != -1);
    2743            7013 :         SET_JUMP_OFFSET(bce->code(defaultOffset), off - (defaultOffset - top));
    2744                 :     } else {
    2745           10218 :         pc = bce->code(top);
    2746           10218 :         SET_JUMP_OFFSET(pc, off);
    2747           10218 :         pc += JUMP_OFFSET_LEN;
    2748                 :     }
    2749                 : 
    2750                 :     /* Set the SRC_SWITCH note's offset operand to tell end of switch. */
    2751           17231 :     off = bce->offset() - top;
    2752           17231 :     ok = SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, off);
    2753           17231 :     if (!ok)
    2754               0 :         goto out;
    2755                 : 
    2756           17231 :     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           15923 :     } else if (switchOp == JSOP_LOOKUPSWITCH) {
    2768                 :         /* Skip over the already-initialized number of cases. */
    2769            8910 :         pc += UINT16_LEN;
    2770                 : 
    2771           57413 :         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    2772           48503 :             if (pn3->isKind(PNK_DEFAULT))
    2773            4670 :                 continue;
    2774           43833 :             if (!bce->constList.append(*pn3->pn_pval))
    2775               0 :                 goto bad;
    2776           43833 :             SET_UINT32_INDEX(pc, bce->constList.length() - 1);
    2777           43833 :             pc += UINT32_INDEX_LEN;
    2778                 : 
    2779           43833 :             off = pn3->pn_offset - top;
    2780           43833 :             SET_JUMP_OFFSET(pc, off);
    2781           43833 :             pc += JUMP_OFFSET_LEN;
    2782                 :         }
    2783                 :     }
    2784                 : 
    2785                 : out:
    2786           17231 :     if (table)
    2787            1227 :         cx->free_(table);
    2788           17231 :     if (ok) {
    2789           17231 :         ok = PopStatementBCE(cx, bce);
    2790                 : 
    2791                 : #if JS_HAS_BLOCK_SCOPE
    2792           17231 :         if (ok && pn->pn_right->isKind(PNK_LEXICALSCOPE))
    2793            3521 :             EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObjCount);
    2794                 : #endif
    2795                 :     }
    2796           17231 :     return ok;
    2797                 : 
    2798                 : bad:
    2799               0 :     ok = JS_FALSE;
    2800               0 :     goto out;
    2801                 : }
    2802                 : 
    2803                 : JSBool
    2804          988449 : 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          988449 :     if (bce->flags & TCF_FUN_IS_GENERATOR) {
    2814                 :         /* JSOP_GENERATOR must be the first instruction. */
    2815            3702 :         bce->switchToProlog();
    2816            3702 :         JS_ASSERT(bce->next() == bce->base());
    2817            3702 :         if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
    2818               0 :             return false;
    2819            3702 :         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          988449 :     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          988449 :     return EmitTree(cx, bce, body) &&
    2837          988449 :            Emit1(cx, bce, JSOP_STOP) >= 0 &&
    2838         1976898 :            JSScript::NewScriptFromEmitter(cx, bce);
    2839                 : }
    2840                 : 
    2841                 : static bool
    2842         1656827 : MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn,
    2843                 :                  jsatomid *result)
    2844                 : {
    2845                 :     jsatomid atomIndex;
    2846                 : 
    2847         1656827 :     if (!pn->pn_cookie.isFree()) {
    2848         1343586 :         atomIndex = pn->pn_cookie.slot();
    2849                 :     } else {
    2850          313241 :         if (!bce->makeAtomIndex(pn->pn_atom, &atomIndex))
    2851               0 :             return false;
    2852                 :     }
    2853                 : 
    2854         2283309 :     if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
    2855          313241 :         (!bce->inFunction() || (bce->flags & TCF_FUN_HEAVYWEIGHT)) &&
    2856          313241 :         !(pn->pn_dflags & PND_GVAR))
    2857                 :     {
    2858          267299 :         bce->switchToProlog();
    2859          267299 :         if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
    2860               0 :             return false;
    2861          267299 :         if (!EmitIndexOp(cx, prologOp, atomIndex, bce))
    2862               0 :             return false;
    2863          267299 :         bce->switchToMain();
    2864                 :     }
    2865                 : 
    2866         4900816 :     if (bce->inFunction() &&
    2867         1187194 :         JOF_OPTYPE(pn->getOp()) == JOF_LOCAL &&
    2868         1186555 :         pn->pn_cookie.slot() < bce->bindings.countVars() &&
    2869          870240 :         bce->shouldNoteClosedName(pn))
    2870                 :     {
    2871           80319 :         if (!bce->closedVars.append(pn->pn_cookie.slot()))
    2872               0 :             return false;
    2873                 :     }
    2874                 : 
    2875         1656827 :     if (result)
    2876         1630890 :         *result = atomIndex;
    2877         1656827 :     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           25937 : EmitDestructuringDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
    2902                 : {
    2903           25937 :     JS_ASSERT(pn->isKind(PNK_NAME));
    2904           25937 :     if (!BindNameToSlot(cx, bce, pn))
    2905               0 :         return JS_FALSE;
    2906                 : 
    2907           25937 :     JS_ASSERT(!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE));
    2908           25937 :     return MaybeEmitVarDecl(cx, bce, prologOp, pn, NULL);
    2909                 : }
    2910                 : 
    2911                 : static JSBool
    2912           18769 : EmitDestructuringDecls(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
    2913                 : {
    2914                 :     ParseNode *pn2, *pn3;
    2915                 :     DestructuringDeclEmitter emitter;
    2916                 : 
    2917           18769 :     if (pn->isKind(PNK_RB)) {
    2918           45294 :         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    2919           27641 :             if (pn2->isKind(PNK_COMMA))
    2920             691 :                 continue;
    2921           26950 :             emitter = (pn2->isKind(PNK_NAME))
    2922                 :                       ? EmitDestructuringDecl
    2923           26950 :                       : EmitDestructuringDecls;
    2924           26950 :             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           18769 :     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           34555 : EmitDestructuringLHS(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption)
    2957                 : {
    2958           34555 :     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           34555 :     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           31363 :         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           30463 :         if (pn->isKind(PNK_NAME)) {
    2991           30337 :             if (!BindNameToSlot(cx, bce, pn))
    2992               0 :                 return JS_FALSE;
    2993           30337 :             if (pn->isConst() && !pn->isInitialized())
    2994               0 :                 return Emit1(cx, bce, JSOP_POP) >= 0;
    2995                 :         }
    2996                 : 
    2997           30463 :         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           28615 :             uint16_t slot = pn->pn_cookie.slot();
    3017           28615 :             EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
    3018           28615 :             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           33655 :     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           21505 : EmitDestructuringOpsHelper(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn,
    3067                 :                            VarEmitOption emitOption)
    3068                 : {
    3069           21505 :     JS_ASSERT(emitOption != DefineVars);
    3070                 : 
    3071                 :     unsigned index;
    3072                 :     ParseNode *pn2, *pn3;
    3073                 :     JSBool doElemOp;
    3074                 : 
    3075                 : #ifdef DEBUG
    3076           21505 :     int stackDepth = bce->stackDepth;
    3077           21505 :     JS_ASSERT(stackDepth != 0);
    3078           21505 :     JS_ASSERT(pn->isArity(PN_LIST));
    3079           21505 :     JS_ASSERT(pn->isKind(PNK_RB) || pn->isKind(PNK_RC));
    3080                 : #endif
    3081                 : 
    3082           21505 :     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           21505 :     index = 0;
    3089           55449 :     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           33944 :         if (pn2 != pn->pn_head && NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
    3095               0 :             return JS_FALSE;
    3096           33944 :         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           33944 :         doElemOp = JS_TRUE;
    3106           33944 :         if (pn->isKind(PNK_RB)) {
    3107           31855 :             if (!EmitNumberOp(cx, index, bce))
    3108               0 :                 return JS_FALSE;
    3109           31855 :             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           33944 :         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           31963 :             if (!EmitElemOpBase(cx, bce, JSOP_GETELEM))
    3140               0 :                 return JS_FALSE;
    3141           31963 :             JS_ASSERT(bce->stackDepth >= stackDepth + 1);
    3142                 :         }
    3143                 : 
    3144                 :         /* Nullary comma node makes a hole in the array destructurer. */
    3145           33944 :         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           33244 :             int depthBefore = bce->stackDepth;
    3152           33244 :             if (!EmitDestructuringLHS(cx, bce, pn3, emitOption))
    3153               0 :                 return JS_FALSE;
    3154                 : 
    3155           33244 :             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           33944 :         ++index;
    3181                 :     }
    3182                 : 
    3183           21505 :     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           21505 :     return JS_TRUE;
    3193                 : }
    3194                 : 
    3195                 : static ptrdiff_t
    3196           10215 : OpToDeclType(JSOp op)
    3197                 : {
    3198           10215 :     switch (op) {
    3199                 :       case JSOP_NOP:
    3200            4253 :         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           45212 :     LetNotes(JSContext *cx) : notes(cx), groupAssign(false), updateCalled(false) {}
    3230                 : 
    3231           90424 :     ~LetNotes() {
    3232           45212 :         JS_ASSERT_IF(!notes.allocPolicy().context()->isExceptionPending(), updateCalled);
    3233           45212 :     }
    3234                 : 
    3235             180 :     void setGroupAssign() {
    3236             180 :         JS_ASSERT(notes.empty());
    3237             180 :         groupAssign = true;
    3238             180 :     }
    3239                 : 
    3240           45212 :     bool isGroupAssign() const {
    3241           45212 :         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           45212 :     bool update(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t offset) {
    3262           45212 :         JS_ASSERT(!updateCalled);
    3263           49370 :         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           45212 :         updateCalled = true;
    3271           45212 :         return true;
    3272                 :     }
    3273                 : };
    3274                 : 
    3275                 : static JSBool
    3276           18313 : 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           18313 :     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           14155 :         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           18313 :     VarEmitOption emitOption = letNotes ? PushInitialValues : InitializeVars;
    3299           18313 :     return EmitDestructuringOpsHelper(cx, bce, pn, emitOption);
    3300                 : }
    3301                 : 
    3302                 : static JSBool
    3303             675 : EmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp,
    3304                 :                     ParseNode *lhs, ParseNode *rhs)
    3305                 : {
    3306                 :     unsigned depth, limit, i, nslots;
    3307                 :     ParseNode *pn;
    3308                 : 
    3309             675 :     depth = limit = (unsigned) bce->stackDepth;
    3310            1986 :     for (pn = rhs->pn_head; pn; pn = pn->pn_next) {
    3311            1311 :         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            1311 :         JS_ASSERT(!(pn->isKind(PNK_COMMA) && pn->isArity(PN_NULLARY)));
    3319            1311 :         if (!EmitTree(cx, bce, pn))
    3320               0 :             return JS_FALSE;
    3321            1311 :         ++limit;
    3322                 :     }
    3323                 : 
    3324             675 :     if (NewSrcNote2(cx, bce, SRC_GROUPASSIGN, OpToDeclType(prologOp)) < 0)
    3325               0 :         return JS_FALSE;
    3326                 : 
    3327             675 :     i = depth;
    3328            1986 :     for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) {
    3329                 :         /* MaybeEmitGroupAssignment requires lhs->pn_count <= rhs->pn_count. */
    3330            1311 :         JS_ASSERT(i < limit);
    3331            1311 :         int slot = AdjustBlockSlot(cx, bce, i);
    3332            1311 :         if (slot < 0)
    3333               0 :             return JS_FALSE;
    3334            1311 :         EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot);
    3335                 : 
    3336            1311 :         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            1311 :             if (!EmitDestructuringLHS(cx, bce, pn, InitializeVars))
    3341               0 :                 return JS_FALSE;
    3342                 :         }
    3343                 :     }
    3344                 : 
    3345             675 :     nslots = limit - depth;
    3346             675 :     EMIT_UINT16_IMM_OP(JSOP_POPN, nslots);
    3347             675 :     bce->stackDepth = (unsigned) depth;
    3348             675 :     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         2307736 : MaybeEmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn,
    3358                 :                          JSOp *pop)
    3359                 : {
    3360         2307736 :     JS_ASSERT(pn->isKind(PNK_ASSIGN));
    3361         2307736 :     JS_ASSERT(pn->isOp(JSOP_NOP));
    3362         2307736 :     JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV);
    3363                 : 
    3364         2307736 :     ParseNode *lhs = pn->pn_left;
    3365         2307736 :     ParseNode *rhs = pn->pn_right;
    3366         2308411 :     if (lhs->isKind(PNK_RB) && rhs->isKind(PNK_RB) &&
    3367             675 :         !(rhs->pn_xflags & PNX_HOLEY) &&
    3368                 :         lhs->pn_count <= rhs->pn_count) {
    3369             675 :         if (!EmitGroupAssignment(cx, bce, prologOp, lhs, rhs))
    3370               0 :             return JS_FALSE;
    3371             675 :         *pop = JSOP_NOP;
    3372                 :     }
    3373         2307736 :     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         1326954 : EmitVariables(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption,
    3421                 :               LetNotes *letNotes = NULL)
    3422                 : {
    3423         1326954 :     JS_ASSERT(pn->isArity(PN_LIST));
    3424         1326954 :     JS_ASSERT(!!letNotes == (emitOption == PushInitialValues));
    3425                 : 
    3426         1326954 :     ptrdiff_t off = -1, noteIndex = -1;
    3427                 :     ParseNode *next;
    3428         1647352 :     for (ParseNode *pn2 = pn->pn_head; ; pn2 = next) {
    3429         1647352 :         bool first = pn2 == pn->pn_head;
    3430         1647352 :         next = pn2->pn_next;
    3431                 : 
    3432                 :         ParseNode *pn3;
    3433         1647352 :         if (!pn2->isKind(PNK_NAME)) {
    3434                 : #if JS_HAS_DESTRUCTURING
    3435           23910 :             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           20942 :             JS_ASSERT(pn2->isKind(PNK_ASSIGN));
    3459           20942 :             JS_ASSERT(pn2->isOp(JSOP_NOP));
    3460           20942 :             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           20942 :             if (pn2->pn_left->isKind(PNK_NAME))
    3471                 : #endif
    3472                 :             {
    3473            7448 :                 pn3 = pn2->pn_right;
    3474            7448 :                 pn2 = pn2->pn_left;
    3475            7448 :                 goto do_name;
    3476                 :             }
    3477                 : 
    3478                 : #if JS_HAS_DESTRUCTURING
    3479           13494 :             ptrdiff_t stackDepthBefore = bce->stackDepth;
    3480           13494 :             JSOp op = JSOP_POP;
    3481           13494 :             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            9822 :                 JS_ASSERT(noteIndex < 0 && !pn2->pn_next);
    3489            9822 :                 if (letNotes) {
    3490            1026 :                     if (!MaybeEmitLetGroupDecl(cx, bce, pn2, letNotes, &op))
    3491               0 :                         return JS_FALSE;
    3492                 :                 } else {
    3493            8796 :                     if (!MaybeEmitGroupAssignment(cx, bce, pn->getOp(), pn2, &op))
    3494               0 :                         return JS_FALSE;
    3495                 :                 }
    3496                 :             }
    3497           13494 :             if (op == JSOP_NOP) {
    3498             534 :                 pn->pn_xflags = (pn->pn_xflags & ~PNX_POPVAR) | PNX_GROUPINIT;
    3499                 :             } else {
    3500           12960 :                 pn3 = pn2->pn_left;
    3501           12960 :                 if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn3))
    3502               0 :                     return JS_FALSE;
    3503                 : 
    3504           12960 :                 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            9540 :                                      ? OpToDeclType(pn->getOp())
    3510           22500 :                                      : SRC_DECL_NONE;
    3511                 : 
    3512           12960 :                 if (!EmitDestructuringOps(cx, bce, declType, pn3, letNotes))
    3513               0 :                     return JS_FALSE;
    3514                 :             }
    3515           13494 :             ptrdiff_t stackDepthAfter = bce->stackDepth;
    3516                 : 
    3517                 :             /* Give let ([] = x) a slot (see CheckDestructuring). */
    3518           13494 :             JS_ASSERT(stackDepthBefore <= stackDepthAfter);
    3519           13494 :             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           13494 :             if (emitOption != InitializeVars) {
    3526            4338 :                 if (next)
    3527            3159 :                     continue;
    3528            1179 :                 break;
    3529                 :             }
    3530            9156 :             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         1623442 :         pn3 = pn2->maybeExpr();
    3541                 : 
    3542                 :      do_name:
    3543         1630890 :         if (!BindNameToSlot(cx, bce, pn2))
    3544               0 :             return JS_FALSE;
    3545                 : 
    3546                 :         JSOp op;
    3547                 :         jsatomid atomIndex;
    3548                 : 
    3549         1630890 :         op = pn2->getOp();
    3550         1630890 :         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         1630890 :             JS_ASSERT(op != JSOP_CALLEE);
    3557         1630890 :             JS_ASSERT(!pn2->pn_cookie.isFree() || !pn->isOp(JSOP_NOP));
    3558         1630890 :             if (!MaybeEmitVarDecl(cx, bce, pn->getOp(), pn2, &atomIndex))
    3559               0 :                 return JS_FALSE;
    3560                 : 
    3561         1630890 :             if (pn3) {
    3562         1245384 :                 JS_ASSERT(emitOption != DefineVars);
    3563         1245384 :                 JS_ASSERT_IF(emitOption == PushInitialValues, op == JSOP_SETLOCAL);
    3564         1245384 :                 if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
    3565          156087 :                     JSOp bindOp = (op == JSOP_SETNAME) ? JSOP_BINDNAME : JSOP_BINDGNAME;
    3566          156087 :                     if (!EmitIndex32(cx, bindOp, atomIndex, bce))
    3567               0 :                         return false;
    3568                 :                 }
    3569         1414148 :                 if (pn->isOp(JSOP_DEFCONST) &&
    3570          168764 :                     !DefineCompileTimeConstant(cx, bce, pn2->pn_atom, pn3))
    3571                 :                 {
    3572               0 :                     return JS_FALSE;
    3573                 :                 }
    3574                 : 
    3575         1245384 :                 unsigned oldflags = bce->flags;
    3576         1245384 :                 bce->flags &= ~TCF_IN_FOR_INIT;
    3577         1245384 :                 if (!EmitTree(cx, bce, pn3))
    3578               0 :                     return JS_FALSE;
    3579         1245384 :                 bce->flags |= oldflags & TCF_IN_FOR_INIT;
    3580          385506 :             } 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         1630890 :         if (emitOption != InitializeVars) {
    3589          240804 :             if (next)
    3590          147788 :                 continue;
    3591           93016 :             break;
    3592                 :         }
    3593                 : 
    3594         1390086 :         JS_ASSERT_IF(pn2->isDefn(), pn3 == pn2->pn_expr);
    3595         2610946 :         if (first && NewSrcNote2(cx, bce, SRC_DECL,
    3596         1220860 :                                  (pn->isOp(JSOP_DEFCONST))
    3597                 :                                  ? SRC_DECL_CONST
    3598         1052101 :                                  : (pn->isOp(JSOP_DEFVAR))
    3599                 :                                  ? SRC_DECL_VAR
    3600         2272961 :                                  : SRC_DECL_LET) < 0) {
    3601               0 :             return JS_FALSE;
    3602                 :         }
    3603         1390086 :         if (op == JSOP_ARGUMENTS) {
    3604               0 :             if (!EmitArguments(cx, bce))
    3605               0 :                 return JS_FALSE;
    3606         1390086 :         } else if (!pn2->pn_cookie.isFree()) {
    3607         1078214 :             EMIT_UINT16_IMM_OP(op, atomIndex);
    3608                 :         } else {
    3609          311872 :             if (!EmitIndexOp(cx, op, atomIndex, bce))
    3610               0 :                 return false;
    3611                 :         }
    3612                 : 
    3613                 : #if JS_HAS_DESTRUCTURING
    3614                 :     emit_note_pop:
    3615                 : #endif
    3616         1399242 :         ptrdiff_t tmp = bce->offset();
    3617         1399242 :         if (noteIndex >= 0) {
    3618          169451 :             if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, tmp-off))
    3619               0 :                 return JS_FALSE;
    3620                 :         }
    3621         1399242 :         if (!next)
    3622         1229791 :             break;
    3623          169451 :         off = tmp;
    3624          169451 :         noteIndex = NewSrcNote2(cx, bce, SRC_PCDELTA, 0);
    3625          169451 :         if (noteIndex < 0 || Emit1(cx, bce, JSOP_POP) < 0)
    3626               0 :             return JS_FALSE;
    3627                 :     }
    3628                 : 
    3629         1326954 :     if (pn->pn_xflags & PNX_POPVAR) {
    3630         1196300 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    3631               0 :             return JS_FALSE;
    3632                 :     }
    3633                 : 
    3634         1326954 :     return JS_TRUE;
    3635                 : }
    3636                 : 
    3637                 : static bool
    3638         3073274 : EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, ParseNode *rhs)
    3639                 : {
    3640         3073274 :     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         3073274 :     jsatomid atomIndex = (jsatomid) -1;              /* quell GCC overwarning */
    3648         3073274 :     jsbytecode offset = 1;
    3649                 : 
    3650         3073274 :     switch (lhs->getKind()) {
    3651                 :       case PNK_NAME:
    3652          708871 :         if (!BindNameToSlot(cx, bce, lhs))
    3653               0 :             return false;
    3654          708871 :         if (!lhs->pn_cookie.isFree()) {
    3655          571748 :             JS_ASSERT(lhs->pn_cookie.level() == 0);
    3656          571748 :             atomIndex = lhs->pn_cookie.slot();
    3657                 :         } else {
    3658          137123 :             if (!bce->makeAtomIndex(lhs->pn_atom, &atomIndex))
    3659               0 :                 return false;
    3660          137123 :             if (!lhs->isConst()) {
    3661          137123 :                 JSOp op = lhs->isOp(JSOP_SETGNAME) ? JSOP_BINDGNAME : JSOP_BINDNAME;
    3662          137123 :                 if (!EmitIndex32(cx, op, atomIndex, bce))
    3663               0 :                     return false;
    3664          137123 :                 offset++;
    3665                 :             }
    3666                 :         }
    3667          708871 :         break;
    3668                 :       case PNK_DOT:
    3669          648208 :         if (!EmitTree(cx, bce, lhs->expr()))
    3670               0 :             return false;
    3671          648208 :         offset++;
    3672          648208 :         if (!bce->makeAtomIndex(lhs->pn_atom, &atomIndex))
    3673               0 :             return false;
    3674          648208 :         break;
    3675                 :       case PNK_LB:
    3676         1710806 :         JS_ASSERT(lhs->isArity(PN_BINARY));
    3677         1710806 :         if (!EmitTree(cx, bce, lhs->pn_left))
    3678               0 :             return false;
    3679         1710806 :         if (!EmitTree(cx, bce, lhs->pn_right))
    3680               0 :             return false;
    3681         1710806 :         offset += 2;
    3682         1710806 :         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         3073274 :     if (op != JSOP_NOP) {
    3709           81366 :         JS_ASSERT(rhs);
    3710           81366 :         switch (lhs->getKind()) {
    3711                 :           case PNK_NAME:
    3712           73848 :             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           73848 :             } else if (lhs->isOp(JSOP_SETNAME)) {
    3724           10144 :                 if (Emit1(cx, bce, JSOP_DUP) < 0)
    3725               0 :                     return false;
    3726           10144 :                 if (!EmitIndex32(cx, JSOP_GETXPROP, atomIndex, bce))
    3727               0 :                     return false;
    3728           63704 :             } else if (lhs->isOp(JSOP_SETGNAME)) {
    3729           21745 :                 if (!BindGlobal(cx, bce, lhs, lhs->pn_atom))
    3730               0 :                     return false;
    3731           21745 :                 if (!EmitAtomOp(cx, lhs, JSOP_GETGNAME, bce))
    3732               0 :                     return false;
    3733                 :             } else {
    3734           41959 :                 EMIT_UINT16_IMM_OP(lhs->isOp(JSOP_SETARG) ? JSOP_GETARG : JSOP_GETLOCAL, atomIndex);
    3735                 :             }
    3736           73848 :             break;
    3737                 :           case PNK_DOT:
    3738            6639 :             if (Emit1(cx, bce, JSOP_DUP) < 0)
    3739               0 :                 return false;
    3740            6639 :             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            6639 :                 bool isLength = (lhs->pn_atom == cx->runtime->atomState.lengthAtom);
    3747            6639 :                 if (!EmitIndex32(cx, isLength ? JSOP_LENGTH : JSOP_GETPROP, atomIndex, bce))
    3748               0 :                     return false;
    3749                 :             }
    3750            6639 :             break;
    3751                 :           case PNK_LB:
    3752                 :           case PNK_LP:
    3753                 : #if JS_HAS_XML_SUPPORT
    3754                 :           case PNK_XMLUNARY:
    3755                 : #endif
    3756             879 :             if (Emit1(cx, bce, JSOP_DUP2) < 0)
    3757               0 :                 return false;
    3758             879 :             if (!EmitElemOpBase(cx, bce, JSOP_GETELEM))
    3759               0 :                 return false;
    3760             879 :             break;
    3761                 :           default:;
    3762                 :         }
    3763                 :     }
    3764                 : 
    3765                 :     /* Now emit the right operand (it may affect the namespace). */
    3766         3073274 :     if (rhs) {
    3767         3018658 :         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           54616 :         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         3073274 :     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           81366 :         if (!lhs->isKind(PNK_NAME) || !lhs->isConst()) {
    3783           81366 :             if (NewSrcNote(cx, bce, SRC_ASSIGNOP) < 0)
    3784               0 :                 return false;
    3785                 :         }
    3786           81366 :         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        10155977 :     if (!lhs->isKind(PNK_NAME) &&
    3792                 : #if JS_HAS_DESTRUCTURING
    3793         2364403 :         !lhs->isKind(PNK_RB) &&
    3794         2359250 :         !lhs->isKind(PNK_RC) &&
    3795                 : #endif
    3796         2359050 :         NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - top) < 0)
    3797                 :     {
    3798               0 :         return false;
    3799                 :     }
    3800                 : 
    3801                 :     /* Finally, emit the specialized assignment bytecode. */
    3802         3073274 :     switch (lhs->getKind()) {
    3803                 :       case PNK_NAME:
    3804          708871 :         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          708871 :         if (lhs->isOp(JSOP_SETARG) || lhs->isOp(JSOP_SETLOCAL)) {
    3813          571748 :             JS_ASSERT(atomIndex < UINT16_MAX);
    3814          571748 :             EMIT_UINT16_IMM_OP(lhs->getOp(), atomIndex);
    3815                 :         } else {
    3816          137123 :             if (!EmitIndexOp(cx, lhs->getOp(), atomIndex, bce))
    3817               0 :                 return false;
    3818                 :         }
    3819          708871 :         break;
    3820                 :       case PNK_DOT:
    3821          648208 :         if (!EmitIndexOp(cx, lhs->getOp(), atomIndex, bce))
    3822               0 :             return false;
    3823          648208 :         break;
    3824                 :       case PNK_LB:
    3825                 :       case PNK_LP:
    3826         1710824 :         if (Emit1(cx, bce, JSOP_SETELEM) < 0)
    3827               0 :             return false;
    3828         1710824 :         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         3073274 :     return true;
    3847                 : }
    3848                 : 
    3849                 : #ifdef DEBUG
    3850                 : static JSBool
    3851           28589 : GettableNoteForNextOp(BytecodeEmitter *bce)
    3852                 : {
    3853                 :     ptrdiff_t offset, target;
    3854                 :     jssrcnote *sn, *end;
    3855                 : 
    3856           28589 :     offset = 0;
    3857           28589 :     target = bce->offset();
    3858         4110963 :     for (sn = bce->notes(), end = sn + bce->noteCount(); sn < end;
    3859         4082374 :          sn = SN_NEXT(sn)) {
    3860         4082374 :         if (offset == target && SN_IS_GETTABLE(sn))
    3861               0 :             return JS_TRUE;
    3862         4082374 :         offset += SN_DELTA(sn);
    3863                 :     }
    3864           28589 :     return JS_FALSE;
    3865                 : }
    3866                 : #endif
    3867                 : 
    3868                 : /* Top-level named functions need a nop for decompilation. */
    3869                 : static JSBool
    3870          226586 : EmitFunctionDefNop(JSContext *cx, BytecodeEmitter *bce, unsigned index)
    3871                 : {
    3872          226586 :     return NewSrcNote2(cx, bce, SRC_FUNCDEF, (ptrdiff_t)index) >= 0 &&
    3873          226586 :            Emit1(cx, bce, JSOP_NOP) >= 0;
    3874                 : }
    3875                 : 
    3876                 : static bool
    3877          227156 : EmitNewInit(JSContext *cx, BytecodeEmitter *bce, JSProtoKey key, ParseNode *pn)
    3878                 : {
    3879          227156 :     const size_t len = 1 + UINT32_INDEX_LEN;
    3880          227156 :     ptrdiff_t offset = EmitCheck(cx, bce, len);
    3881          227156 :     if (offset < 0)
    3882               0 :         return false;
    3883                 : 
    3884          227156 :     jsbytecode *next = bce->next();
    3885          227156 :     next[0] = JSOP_NEWINIT;
    3886          227156 :     next[1] = jsbytecode(key);
    3887          227156 :     next[2] = 0;
    3888          227156 :     next[3] = 0;
    3889          227156 :     next[4] = 0;
    3890          227156 :     bce->current->next = next + len;
    3891          227156 :     UpdateDepth(cx, bce, offset);
    3892          227156 :     CheckTypeSet(cx, bce, JSOP_NEWINIT);
    3893          227156 :     return true;
    3894                 : }
    3895                 : 
    3896                 : bool
    3897           29743 : ParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
    3898                 : {
    3899           29743 :     switch (getKind()) {
    3900                 :       case PNK_NUMBER:
    3901           13988 :         vp->setNumber(pn_dval);
    3902           13988 :         return true;
    3903                 :       case PNK_STRING:
    3904            6643 :         vp->setString(pn_atom);
    3905            6643 :         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            5767 :         JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
    3917                 : 
    3918            5767 :         JSObject *obj = NewDenseAllocatedArray(cx, pn_count);
    3919            5767 :         if (!obj)
    3920               0 :             return false;
    3921                 : 
    3922            5767 :         unsigned idx = 0;
    3923           22900 :         for (ParseNode *pn = pn_head; pn; idx++, pn = pn->pn_next) {
    3924                 :             Value value;
    3925           17133 :             if (!pn->getConstantValue(cx, strictChecks, &value))
    3926               0 :                 return false;
    3927           17133 :             if (!obj->defineGeneric(cx, INT_TO_JSID(idx), value, NULL, NULL, JSPROP_ENUMERATE))
    3928               0 :                 return false;
    3929                 :         }
    3930            5767 :         JS_ASSERT(idx == pn_count);
    3931                 : 
    3932            5767 :         types::FixArrayType(cx, obj);
    3933            5767 :         vp->setObject(*obj);
    3934            5767 :         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            7276 : EmitSingletonInitialiser(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    3982                 : {
    3983                 :     Value value;
    3984            7276 :     if (!pn->getConstantValue(cx, bce->needStrictChecks(), &value))
    3985               0 :         return false;
    3986                 : 
    3987            7276 :     JS_ASSERT(value.isObject());
    3988            7276 :     ObjectBox *objbox = bce->parser->newObjectBox(&value.toObject());
    3989            7276 :     if (!objbox)
    3990               0 :         return false;
    3991                 : 
    3992            7276 :     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        59282303 :     EmitLevelManager(BytecodeEmitter *bce) : bce(bce) { bce->emitLevel++; }
    4004        59282303 :     ~EmitLevelManager() { bce->emitLevel--; }
    4005                 : };
    4006                 : 
    4007                 : static bool
    4008          225154 : 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          225154 :     StmtInfo *stmt = bce->topStmt;
    4017          225154 :     JS_ASSERT(stmt->type == STMT_BLOCK && (stmt->flags & SIF_SCOPE));
    4018          225154 :     stmt->type = STMT_CATCH;
    4019          225154 :     catchStart = stmt->update;
    4020                 : 
    4021                 :     /* Go up one statement info record to the TRY or FINALLY record. */
    4022          225154 :     stmt = stmt->down;
    4023          225154 :     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          225154 :     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          225154 :     if (pn->pn_kid2 && Emit1(cx, bce, JSOP_DUP) < 0)
    4034               0 :         return false;
    4035                 : 
    4036          225154 :     ParseNode *pn2 = pn->pn_kid1;
    4037          225154 :     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          225154 :         JS_ASSERT(!pn2->pn_cookie.isFree());
    4051          225154 :         EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, pn2->pn_cookie.asInteger());
    4052          225154 :         break;
    4053                 : 
    4054                 :       default:
    4055               0 :         JS_ASSERT(0);
    4056                 :     }
    4057                 : 
    4058                 :     /* Emit the guard expression, if there is one. */
    4059          225154 :     if (pn->pn_kid2) {
    4060            1217 :         if (!EmitTree(cx, bce, pn->pn_kid2))
    4061               0 :             return false;
    4062            1217 :         if (!SetSrcNoteOffset(cx, bce, CATCHNOTE(*stmt), 0, bce->offset() - catchStart))
    4063               0 :             return false;
    4064                 :         /* ifeq <next block> */
    4065            1217 :         guardJump = EmitJump(cx, bce, JSOP_IFEQ, 0);
    4066            1217 :         if (guardJump < 0)
    4067               0 :             return false;
    4068            1217 :         GUARDJUMP(*stmt) = guardJump;
    4069                 : 
    4070                 :         /* Pop duplicated exception object as we no longer need it. */
    4071            1217 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    4072               0 :             return false;
    4073                 :     }
    4074                 : 
    4075                 :     /* Emit the catch body. */
    4076          225154 :     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          225154 :     ptrdiff_t off = bce->stackDepth;
    4084          225154 :     if (NewSrcNote2(cx, bce, SRC_CATCH, off) < 0)
    4085               0 :         return false;
    4086          225154 :     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          241021 : EmitTry(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    4095                 : {
    4096                 :     StmtInfo stmtInfo;
    4097          241021 :     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          241021 :     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          241021 :     int depth = bce->stackDepth;
    4120                 : 
    4121                 :     /* Mark try location for decompilation, then emit try block. */
    4122          241021 :     if (Emit1(cx, bce, JSOP_TRY) < 0)
    4123               0 :         return false;
    4124          241021 :     ptrdiff_t tryStart = bce->offset();
    4125          241021 :     if (!EmitTree(cx, bce, pn->pn_kid1))
    4126               0 :         return false;
    4127          241021 :     JS_ASSERT(depth == bce->stackDepth);
    4128                 : 
    4129                 :     /* GOSUB to finally, if present. */
    4130          241021 :     if (pn->pn_kid3) {
    4131           22053 :         if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
    4132               0 :             return false;
    4133           22053 :         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          241021 :     if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
    4139               0 :         return false;
    4140          241021 :     if (EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, &catchJump) < 0)
    4141               0 :         return false;
    4142                 : 
    4143          241021 :     ptrdiff_t tryEnd = bce->offset();
    4144                 : 
    4145                 :     /* If this try has a catch block, emit it. */
    4146          241021 :     ParseNode *lastCatch = NULL;
    4147          241021 :     if (ParseNode *pn2 = pn->pn_kid2) {
    4148          224923 :         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          450077 :         for (ParseNode *pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
    4173                 :             ptrdiff_t guardJump, catchNote;
    4174                 : 
    4175          225154 :             JS_ASSERT(bce->stackDepth == depth);
    4176          225154 :             guardJump = GUARDJUMP(stmtInfo);
    4177          225154 :             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          225154 :             catchNote = NewSrcNote2(cx, bce, SRC_CATCH, 0);
    4212          225154 :             if (catchNote < 0)
    4213               0 :                 return false;
    4214          225154 :             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          225154 :             JS_ASSERT(pn3->isKind(PNK_LEXICALSCOPE));
    4222          225154 :             count = pn3->pn_objbox->object->asStaticBlock().slotCount();
    4223          225154 :             if (!EmitTree(cx, bce, pn3))
    4224               0 :                 return false;
    4225                 : 
    4226                 :             /* gosub <finally>, if required */
    4227          225154 :             if (pn->pn_kid3) {
    4228            5955 :                 if (EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, &GOSUBS(stmtInfo)) < 0)
    4229               0 :                     return false;
    4230            5955 :                 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          225154 :             if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
    4238               0 :                 return false;
    4239          225154 :             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          225154 :             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          241021 :     if (lastCatch && lastCatch->pn_kid2) {
    4257             986 :         SetJumpOffsetAt(bce, GUARDJUMP(stmtInfo));
    4258                 : 
    4259                 :         /* Sync the stack to take into account pushed exception. */
    4260             986 :         JS_ASSERT(bce->stackDepth == depth);
    4261             986 :         bce->stackDepth = depth + 1;
    4262                 : 
    4263                 :         /*
    4264                 :          * Rethrow the exception, delegating executing of finally if any
    4265                 :          * to the exception handler.
    4266                 :          */
    4267             986 :         if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0 || Emit1(cx, bce, JSOP_THROW) < 0)
    4268               0 :             return false;
    4269                 :     }
    4270                 : 
    4271          241021 :     JS_ASSERT(bce->stackDepth == depth);
    4272                 : 
    4273                 :     /* Emit finally handler if any. */
    4274          241021 :     ptrdiff_t finallyStart = 0;   /* to quell GCC uninitialized warnings */
    4275          241021 :     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           22053 :         if (!BackPatch(cx, bce, GOSUBS(stmtInfo), bce->next(), JSOP_GOSUB))
    4281               0 :             return false;
    4282                 : 
    4283           22053 :         finallyStart = bce->offset();
    4284                 : 
    4285                 :         /* Indicate that we're emitting a subroutine body. */
    4286           22053 :         stmtInfo.type = STMT_SUBROUTINE;
    4287           22053 :         if (!UpdateLineNumberNotes(cx, bce, pn->pn_kid3->pn_pos.begin.lineno))
    4288               0 :             return false;
    4289           66159 :         if (Emit1(cx, bce, JSOP_FINALLY) < 0 ||
    4290           22053 :             !EmitTree(cx, bce, pn->pn_kid3) ||
    4291           22053 :             Emit1(cx, bce, JSOP_RETSUB) < 0)
    4292                 :         {
    4293               0 :             return false;
    4294                 :         }
    4295           22053 :         JS_ASSERT(bce->stackDepth == depth);
    4296                 :     }
    4297          241021 :     if (!PopStatementBCE(cx, bce))
    4298               0 :         return false;
    4299                 : 
    4300          241021 :     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          241021 :     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          241021 :     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          241021 :     if (pn->pn_kid3 && !NewTryNote(cx, bce, JSTRY_FINALLY, depth, tryStart, finallyStart))
    4320               0 :         return false;
    4321                 : 
    4322          241021 :     return true;
    4323                 : }
    4324                 : 
    4325                 : static bool
    4326          929543 : 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          929543 :     stmtInfo.type = STMT_IF;
    4332          929543 :     ptrdiff_t beq = -1;
    4333          929543 :     ptrdiff_t jmp = -1;
    4334          929543 :     ptrdiff_t noteIndex = -1;
    4335                 : 
    4336                 :   if_again:
    4337                 :     /* Emit code for the condition before pushing stmtInfo. */
    4338          949320 :     if (!EmitTree(cx, bce, pn->pn_kid1))
    4339               0 :         return JS_FALSE;
    4340          949320 :     ptrdiff_t top = bce->offset();
    4341          949320 :     if (stmtInfo.type == STMT_IF) {
    4342          929543 :         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          949320 :     ParseNode *pn3 = pn->pn_kid3;
    4364          949320 :     noteIndex = NewSrcNote(cx, bce, pn3 ? SRC_IF_ELSE : SRC_IF);
    4365          949320 :     if (noteIndex < 0)
    4366               0 :         return JS_FALSE;
    4367          949320 :     beq = EmitJump(cx, bce, JSOP_IFEQ, 0);
    4368          949320 :     if (beq < 0)
    4369               0 :         return JS_FALSE;
    4370                 : 
    4371                 :     /* Emit code for the then and optional else parts. */
    4372          949320 :     if (!EmitTree(cx, bce, pn->pn_kid2))
    4373               0 :         return JS_FALSE;
    4374          949320 :     if (pn3) {
    4375                 :         /* Modify stmtInfo so we know we're in the else part. */
    4376          156612 :         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          156612 :         jmp = EmitGoto(cx, bce, &stmtInfo, &stmtInfo.breaks);
    4385          156612 :         if (jmp < 0)
    4386               0 :             return JS_FALSE;
    4387                 : 
    4388                 :         /* Ensure the branch-if-false comes here, then emit the else. */
    4389          156612 :         SetJumpOffsetAt(bce, beq);
    4390          156612 :         if (pn3->isKind(PNK_IF)) {
    4391           19777 :             pn = pn3;
    4392           19777 :             goto if_again;
    4393                 :         }
    4394                 : 
    4395          136835 :         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          136835 :         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          792708 :         SetJumpOffsetAt(bce, beq);
    4410                 :     }
    4411          929543 :     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           45212 : EmitLet(JSContext *cx, BytecodeEmitter *bce, ParseNode *pnLet)
    4459                 : {
    4460           45212 :     JS_ASSERT(pnLet->isArity(PN_BINARY));
    4461           45212 :     ParseNode *varList = pnLet->pn_left;
    4462           45212 :     JS_ASSERT(varList->isArity(PN_LIST));
    4463           45212 :     ParseNode *letBody = pnLet->pn_right;
    4464           45212 :     JS_ASSERT(letBody->isLet() && letBody->isKind(PNK_LEXICALSCOPE));
    4465           45212 :     StaticBlockObject &blockObj = letBody->pn_objbox->object->asStaticBlock();
    4466                 : 
    4467           45212 :     ptrdiff_t letHeadOffset = bce->offset();
    4468           45212 :     int letHeadDepth = bce->stackDepth;
    4469                 : 
    4470           90424 :     LetNotes letNotes(cx);
    4471           45212 :     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           45212 :     uint32_t alreadyPushed = unsigned(bce->stackDepth - letHeadDepth);
    4476           45212 :     uint32_t blockObjCount = blockObj.slotCount();
    4477           56947 :     for (uint32_t i = alreadyPushed; i < blockObjCount; ++i) {
    4478                 :         /* Tell the decompiler not to print the decl in the let head. */
    4479           11735 :         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
    4480               0 :             return false;
    4481           11735 :         if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    4482               0 :             return false;
    4483                 :     }
    4484                 : 
    4485                 :     StmtInfo stmtInfo;
    4486           45212 :     PushBlockScope(bce, &stmtInfo, blockObj, bce->offset());
    4487                 : 
    4488           45212 :     if (!letNotes.update(cx, bce, bce->offset()))
    4489               0 :         return false;
    4490                 : 
    4491           45212 :     ptrdiff_t declNote = NewSrcNote(cx, bce, SRC_DECL);
    4492           45212 :     if (declNote < 0)
    4493               0 :         return false;
    4494                 : 
    4495           45212 :     ptrdiff_t bodyBegin = bce->offset();
    4496           45212 :     if (!EmitEnterBlock(cx, bce, letBody, JSOP_ENTERLET0))
    4497               0 :         return false;
    4498                 : 
    4499           45212 :     if (!EmitTree(cx, bce, letBody->pn_expr))
    4500               0 :         return false;
    4501                 : 
    4502           45212 :     JSOp leaveOp = letBody->getOp();
    4503           45212 :     if (leaveOp == JSOP_LEAVEBLOCKEXPR) {
    4504            1538 :         if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - letHeadOffset) < 0)
    4505               0 :             return false;
    4506                 :     }
    4507                 : 
    4508           45212 :     JS_ASSERT(leaveOp == JSOP_LEAVEBLOCK || leaveOp == JSOP_LEAVEBLOCKEXPR);
    4509           45212 :     EMIT_UINT16_IMM_OP(leaveOp, blockObj.slotCount());
    4510                 : 
    4511           45212 :     ptrdiff_t bodyEnd = bce->offset();
    4512           45212 :     JS_ASSERT(bodyEnd > bodyBegin);
    4513                 : 
    4514           45212 :     if (!PopStatementBCE(cx, bce))
    4515               0 :         return false;
    4516                 : 
    4517                 :     ptrdiff_t o = PackLetData((bodyEnd - bodyBegin) -
    4518                 :                               (JSOP_ENTERLET0_LENGTH + JSOP_LEAVEBLOCK_LENGTH),
    4519           45212 :                               letNotes.isGroupAssign());
    4520           45212 :     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          366540 : EmitLexicalScope(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    4607                 : {
    4608          366540 :     JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
    4609          366540 :     JS_ASSERT(pn->getOp() == JSOP_LEAVEBLOCK);
    4610                 : 
    4611                 :     StmtInfo stmtInfo;
    4612          366540 :     ObjectBox *objbox = pn->pn_objbox;
    4613          366540 :     StaticBlockObject &blockObj = objbox->object->asStaticBlock();
    4614          366540 :     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          366540 :     ptrdiff_t noteIndex = -1;
    4624          752875 :     if (pn->expr()->getKind() != PNK_FOR &&
    4625          353685 :         pn->expr()->getKind() != PNK_CATCH &&
    4626                 :         (stmtInfo.down
    4627                 :          ? stmtInfo.down->type == STMT_BLOCK &&
    4628           32578 :            (!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           85956 :         JS_ASSERT(bce->noteCount() == 0 ||
    4633                 :                   bce->lastNoteOffset() != bce->offset() ||
    4634           85956 :                   !GettableNoteForNextOp(bce));
    4635           28724 :         noteIndex = NewSrcNote2(cx, bce, SRC_BRACE, 0);
    4636           28724 :         if (noteIndex < 0)
    4637               0 :             return false;
    4638                 :     }
    4639                 : 
    4640          366540 :     ptrdiff_t bodyBegin = bce->offset();
    4641          366540 :     if (!EmitEnterBlock(cx, bce, pn, JSOP_ENTERBLOCK))
    4642               0 :         return false;
    4643                 : 
    4644          366540 :     if (!EmitTree(cx, bce, pn->pn_expr))
    4645               0 :         return false;
    4646                 : 
    4647          366540 :     if (noteIndex >= 0) {
    4648           28724 :         if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, bce->offset() - bodyBegin))
    4649               0 :             return false;
    4650                 :     }
    4651                 : 
    4652          366540 :     EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, blockObj.slotCount());
    4653                 : 
    4654          366540 :     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           54616 : EmitForIn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    4676                 : {
    4677                 :     StmtInfo stmtInfo;
    4678           54616 :     PushStatement(bce, &stmtInfo, STMT_FOR_IN_LOOP, top);
    4679                 : 
    4680           54616 :     ParseNode *forHead = pn->pn_left;
    4681           54616 :     ParseNode *forBody = pn->pn_right;
    4682                 : 
    4683           54616 :     ParseNode *pn1 = forHead->pn_kid1;
    4684           54616 :     bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
    4685           54616 :     JS_ASSERT_IF(letDecl, pn1->isLet());
    4686                 : 
    4687           54616 :     StaticBlockObject *blockObj = letDecl ? &pn1->pn_objbox->object->asStaticBlock() : NULL;
    4688           54616 :     uint32_t blockObjCount = blockObj ? blockObj->slotCount() : 0;
    4689                 : 
    4690           54616 :     if (letDecl) {
    4691                 :         /*
    4692                 :          * The let's slot(s) will be under the iterator, but the block must not
    4693                 :          * be entered (i.e. fp->blockChain set) until after evaluating the rhs.
    4694                 :          * Thus, push to reserve space and enterblock after. The same argument
    4695                 :          * applies when leaving the loop. Thus, a for-let-in loop looks like:
    4696                 :          *
    4697                 :          *   push x N
    4698                 :          *   eval rhs
    4699                 :          *   iter
    4700                 :          *   enterlet1
    4701                 :          *   goto
    4702                 :          *     ... loop body
    4703                 :          *   ifne
    4704                 :          *   leaveforinlet
    4705                 :          *   enditer
    4706                 :          *   popn(N)
    4707                 :          */
    4708           65056 :         for (uint32_t i = 0; i < blockObjCount; ++i) {
    4709           33676 :             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    4710               0 :                 return false;
    4711                 :         }
    4712                 :     }
    4713                 : 
    4714                 :     /*
    4715                 :      * If the left part is 'var x', emit code to define x if necessary
    4716                 :      * using a prolog opcode, but do not emit a pop. If the left part was
    4717                 :      * originally 'var x = i', the parser will have rewritten it; see
    4718                 :      * Parser::forStatement. 'for (let x = i in o)' is mercifully banned.
    4719                 :      */
    4720           54616 :     if (pn1) {
    4721           51951 :         ParseNode *decl = letDecl ? pn1->pn_expr : pn1;
    4722           51951 :         JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET));
    4723           51951 :         bce->flags |= TCF_IN_FOR_INIT;
    4724           51951 :         if (!EmitVariables(cx, bce, decl, DefineVars))
    4725               0 :             return false;
    4726           51951 :         bce->flags &= ~TCF_IN_FOR_INIT;
    4727                 :     }
    4728                 : 
    4729                 :     /* Compile the object expression to the right of 'in'. */
    4730           54616 :     if (!EmitTree(cx, bce, forHead->pn_kid3))
    4731               0 :         return JS_FALSE;
    4732                 : 
    4733                 :     /*
    4734                 :      * Emit a bytecode to convert top of stack value to the iterator
    4735                 :      * object depending on the loop variant (for-in, for-each-in, or
    4736                 :      * destructuring for-in).
    4737                 :      */
    4738           54616 :     JS_ASSERT(pn->isOp(JSOP_ITER));
    4739           54616 :     if (Emit2(cx, bce, JSOP_ITER, (uint8_t) pn->pn_iflags) < 0)
    4740               0 :         return false;
    4741                 : 
    4742                 :     /* Enter the block before the loop body, after evaluating the obj. */
    4743                 :     StmtInfo letStmt;
    4744           54616 :     if (letDecl) {
    4745           31380 :         PushBlockScope(bce, &letStmt, *blockObj, bce->offset());
    4746           31380 :         letStmt.flags |= SIF_FOR_BLOCK;
    4747           31380 :         if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1))
    4748               0 :             return false;
    4749                 :     }
    4750                 : 
    4751                 :     /* Annotate so the decompiler can find the loop-closing jump. */
    4752           54616 :     int noteIndex = NewSrcNote(cx, bce, SRC_FOR_IN);
    4753           54616 :     if (noteIndex < 0)
    4754               0 :         return false;
    4755                 : 
    4756                 :     /*
    4757                 :      * Jump down to the loop condition to minimize overhead assuming at
    4758                 :      * least one iteration, as the other loop forms do.
    4759                 :      */
    4760           54616 :     ptrdiff_t jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
    4761           54616 :     if (jmp < 0)
    4762               0 :         return false;
    4763                 : 
    4764           54616 :     top = bce->offset();
    4765           54616 :     SET_STATEMENT_TOP(&stmtInfo, top);
    4766           54616 :     if (EmitLoopHead(cx, bce, NULL) < 0)
    4767               0 :         return false;
    4768                 : 
    4769                 : #ifdef DEBUG
    4770           54616 :     int loopDepth = bce->stackDepth;
    4771                 : #endif
    4772                 : 
    4773                 :     /*
    4774                 :      * Emit code to get the next enumeration value and assign it to the
    4775                 :      * left hand side. The JSOP_POP after this assignment is annotated
    4776                 :      * so that the decompiler can distinguish 'for (x in y)' from
    4777                 :      * 'for (var x in y)'.
    4778                 :      */
    4779           54616 :     if (!EmitAssignment(cx, bce, forHead->pn_kid2, JSOP_NOP, NULL))
    4780               0 :         return false;
    4781                 : 
    4782           54616 :     ptrdiff_t tmp2 = bce->offset();
    4783          106567 :     if (forHead->pn_kid1 && NewSrcNote2(cx, bce, SRC_DECL,
    4784           51951 :                                         (forHead->pn_kid1->isOp(JSOP_DEFVAR))
    4785                 :                                         ? SRC_DECL_VAR
    4786           51951 :                                         : SRC_DECL_LET) < 0) {
    4787               0 :         return false;
    4788                 :     }
    4789           54616 :     if (Emit1(cx, bce, JSOP_POP) < 0)
    4790               0 :         return false;
    4791                 : 
    4792                 :     /* The stack should be balanced around the assignment opcode sequence. */
    4793           54616 :     JS_ASSERT(bce->stackDepth == loopDepth);
    4794                 : 
    4795                 :     /* Emit code for the loop body. */
    4796           54616 :     if (!EmitTree(cx, bce, forBody))
    4797               0 :         return false;
    4798                 : 
    4799                 :     /* Set loop and enclosing "update" offsets, for continue. */
    4800           54616 :     StmtInfo *stmt = &stmtInfo;
    4801           54726 :     do {
    4802           54726 :         stmt->update = bce->offset();
    4803                 :     } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
    4804                 : 
    4805                 :     /*
    4806                 :      * Fixup the goto that starts the loop to jump down to JSOP_MOREITER.
    4807                 :      */
    4808           54616 :     SetJumpOffsetAt(bce, jmp);
    4809           54616 :     if (!EmitLoopEntry(cx, bce, NULL))
    4810               0 :         return false;
    4811           54616 :     if (Emit1(cx, bce, JSOP_MOREITER) < 0)
    4812               0 :         return false;
    4813           54616 :     ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFNE, top - bce->offset());
    4814           54616 :     if (beq < 0)
    4815               0 :         return false;
    4816                 : 
    4817                 :     /* Set the first srcnote offset so we can find the start of the loop body. */
    4818           54616 :     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, tmp2 - jmp))
    4819               0 :         return false;
    4820                 :     /* Set the second srcnote offset so we can find the closing jump. */
    4821           54616 :     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 1, beq - jmp))
    4822               0 :         return false;
    4823                 : 
    4824                 :     /* Fixup breaks and continues before JSOP_ITER (and JSOP_LEAVEFORINLET). */
    4825           54616 :     if (!PopStatementBCE(cx, bce))
    4826               0 :         return false;
    4827                 : 
    4828           54616 :     if (letDecl) {
    4829           31380 :         if (!PopStatementBCE(cx, bce))
    4830               0 :             return false;
    4831           31380 :         if (Emit1(cx, bce, JSOP_LEAVEFORLETIN) < 0)
    4832               0 :             return false;
    4833                 :     }
    4834                 : 
    4835           54616 :     if (!NewTryNote(cx, bce, JSTRY_ITER, bce->stackDepth, top, bce->offset()))
    4836               0 :         return false;
    4837           54616 :     if (Emit1(cx, bce, JSOP_ENDITER) < 0)
    4838               0 :         return false;
    4839                 : 
    4840           54616 :     if (letDecl) {
    4841                 :         /* Tell the decompiler to pop but not to print. */
    4842           31380 :         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
    4843               0 :             return false;
    4844           31380 :         EMIT_UINT16_IMM_OP(JSOP_POPN, blockObjCount);
    4845                 :     }
    4846                 : 
    4847           54616 :     return true;
    4848                 : }
    4849                 : 
    4850                 : static bool
    4851           67487 : EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    4852                 : {
    4853                 :     StmtInfo stmtInfo;
    4854           67487 :     PushStatement(bce, &stmtInfo, STMT_FOR_LOOP, top);
    4855                 : 
    4856           67487 :     ParseNode *forHead = pn->pn_left;
    4857           67487 :     ParseNode *forBody = pn->pn_right;
    4858                 : 
    4859                 :     /* C-style for (init; cond; update) ... loop. */
    4860           67487 :     JSOp op = JSOP_POP;
    4861           67487 :     ParseNode *pn3 = forHead->pn_kid1;
    4862           67487 :     if (!pn3) {
    4863                 :         /* No initializer: emit an annotated nop for the decompiler. */
    4864           32609 :         op = JSOP_NOP;
    4865                 :     } else {
    4866           34878 :         bce->flags |= TCF_IN_FOR_INIT;
    4867                 : #if JS_HAS_DESTRUCTURING
    4868           34878 :         if (pn3->isKind(PNK_ASSIGN)) {
    4869            3144 :             JS_ASSERT(pn3->isOp(JSOP_NOP));
    4870            3144 :             if (!MaybeEmitGroupAssignment(cx, bce, op, pn3, &op))
    4871               0 :                 return false;
    4872                 :         }
    4873                 : #endif
    4874           34878 :         if (op == JSOP_POP) {
    4875           34878 :             if (!EmitTree(cx, bce, pn3))
    4876               0 :                 return false;
    4877           34878 :             if (pn3->isKind(PNK_VAR) || pn3->isKind(PNK_CONST) || pn3->isKind(PNK_LET)) {
    4878                 :                 /*
    4879                 :                  * Check whether a destructuring-initialized var decl
    4880                 :                  * was optimized to a group assignment.  If so, we do
    4881                 :                  * not need to emit a pop below, so switch to a nop,
    4882                 :                  * just for the decompiler.
    4883                 :                  */
    4884           31653 :                 JS_ASSERT(pn3->isArity(PN_LIST) || pn3->isArity(PN_BINARY));
    4885           31653 :                 if (pn3->pn_xflags & PNX_GROUPINIT)
    4886               0 :                     op = JSOP_NOP;
    4887                 :             }
    4888                 :         }
    4889           34878 :         bce->flags &= ~TCF_IN_FOR_INIT;
    4890                 :     }
    4891                 : 
    4892                 :     /*
    4893                 :      * NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH).
    4894                 :      * Use tmp to hold the biased srcnote "top" offset, which differs
    4895                 :      * from the top local variable by the length of the JSOP_GOTO
    4896                 :      * emitted in between tmp and top if this loop has a condition.
    4897                 :      */
    4898           67487 :     int noteIndex = NewSrcNote(cx, bce, SRC_FOR);
    4899           67487 :     if (noteIndex < 0 || Emit1(cx, bce, op) < 0)
    4900               0 :         return false;
    4901           67487 :     ptrdiff_t tmp = bce->offset();
    4902                 : 
    4903           67487 :     ptrdiff_t jmp = -1;
    4904           67487 :     if (forHead->pn_kid2) {
    4905                 :         /* Goto the loop condition, which branches back to iterate. */
    4906           66256 :         jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
    4907           66256 :         if (jmp < 0)
    4908               0 :             return false;
    4909                 :     } else {
    4910            1231 :         if (op != JSOP_NOP && Emit1(cx, bce, JSOP_NOP) < 0)
    4911               0 :             return false;
    4912                 :     }
    4913                 : 
    4914           67487 :     top = bce->offset();
    4915           67487 :     SET_STATEMENT_TOP(&stmtInfo, top);
    4916                 : 
    4917                 :     /* Emit code for the loop body. */
    4918           67487 :     if (EmitLoopHead(cx, bce, forBody) < 0)
    4919               0 :         return false;
    4920           67487 :     if (jmp == -1 && !EmitLoopEntry(cx, bce, forBody))
    4921               0 :         return false;
    4922           67487 :     if (!EmitTree(cx, bce, forBody))
    4923               0 :         return false;
    4924                 : 
    4925                 :     /* Set the second note offset so we can find the update part. */
    4926           67487 :     JS_ASSERT(noteIndex != -1);
    4927           67487 :     ptrdiff_t tmp2 = bce->offset();
    4928                 : 
    4929                 :     /* Set loop and enclosing "update" offsets, for continue. */
    4930           67487 :     StmtInfo *stmt = &stmtInfo;
    4931           67507 :     do {
    4932           67507 :         stmt->update = bce->offset();
    4933                 :     } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
    4934                 : 
    4935                 :     /* Check for update code to do before the condition (if any). */
    4936           67487 :     pn3 = forHead->pn_kid3;
    4937           67487 :     if (pn3) {
    4938           65453 :         op = JSOP_POP;
    4939                 : #if JS_HAS_DESTRUCTURING
    4940           65453 :         if (pn3->isKind(PNK_ASSIGN)) {
    4941            1152 :             JS_ASSERT(pn3->isOp(JSOP_NOP));
    4942            1152 :             if (!MaybeEmitGroupAssignment(cx, bce, op, pn3, &op))
    4943               0 :                 return false;
    4944                 :         }
    4945                 : #endif
    4946           65453 :         if (op == JSOP_POP && !EmitTree(cx, bce, pn3))
    4947               0 :             return false;
    4948                 : 
    4949                 :         /* Always emit the POP or NOP, to help the decompiler. */
    4950           65453 :         if (Emit1(cx, bce, op) < 0)
    4951               0 :             return false;
    4952                 : 
    4953                 :         /* Restore the absolute line number for source note readers. */
    4954           65453 :         ptrdiff_t lineno = pn->pn_pos.end.lineno;
    4955           65453 :         if (bce->currentLine() != (unsigned) lineno) {
    4956           63153 :             if (NewSrcNote2(cx, bce, SRC_SETLINE, lineno) < 0)
    4957               0 :                 return false;
    4958           63153 :             bce->current->currentLine = (unsigned) lineno;
    4959                 :         }
    4960                 :     }
    4961                 : 
    4962           67487 :     ptrdiff_t tmp3 = bce->offset();
    4963                 : 
    4964           67487 :     if (forHead->pn_kid2) {
    4965                 :         /* Fix up the goto from top to target the loop condition. */
    4966           66256 :         JS_ASSERT(jmp >= 0);
    4967           66256 :         SetJumpOffsetAt(bce, jmp);
    4968           66256 :         if (!EmitLoopEntry(cx, bce, forHead->pn_kid2))
    4969               0 :             return false;
    4970                 : 
    4971           66256 :         if (!EmitTree(cx, bce, forHead->pn_kid2))
    4972               0 :             return false;
    4973                 :     }
    4974                 : 
    4975                 :     /* Set the first note offset so we can find the loop condition. */
    4976           67487 :     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, tmp3 - tmp))
    4977               0 :         return false;
    4978           67487 :     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 1, tmp2 - tmp))
    4979               0 :         return false;
    4980                 :     /* The third note offset helps us find the loop-closing jump. */
    4981           67487 :     if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 2, bce->offset() - tmp))
    4982               0 :         return false;
    4983                 : 
    4984                 :     /* If no loop condition, just emit a loop-closing jump. */
    4985           67487 :     op = forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO;
    4986           67487 :     if (EmitJump(cx, bce, op, top - bce->offset()) < 0)
    4987               0 :         return false;
    4988                 : 
    4989                 :     /* Now fixup all breaks and continues. */
    4990           67487 :     return PopStatementBCE(cx, bce);
    4991                 : }
    4992                 : 
    4993                 : static inline bool
    4994          122103 : EmitFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    4995                 : {
    4996          122103 :     JS_ASSERT(pn->pn_left->isKind(PNK_FORIN) || pn->pn_left->isKind(PNK_FORHEAD));
    4997          122103 :     return pn->pn_left->isKind(PNK_FORIN)
    4998                 :            ? EmitForIn(cx, bce, pn, top)
    4999          122103 :            : EmitNormalFor(cx, bce, pn, top);
    5000                 : }
    5001                 : 
    5002                 : static bool
    5003         1019370 : EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5004                 : {
    5005                 : #if JS_HAS_XML_SUPPORT
    5006         1019370 :     if (pn->isArity(PN_NULLARY))
    5007              36 :         return Emit1(cx, bce, JSOP_GETFUNNS) >= 0;
    5008                 : #endif
    5009                 : 
    5010         1019334 :     JSFunction *fun = pn->pn_funbox->function();
    5011         1019334 :     JS_ASSERT(fun->isInterpreted());
    5012         1019334 :     if (fun->script()) {
    5013                 :         /*
    5014                 :          * This second pass is needed to emit JSOP_NOP with a source note
    5015                 :          * for the already-emitted function definition prolog opcode. See
    5016                 :          * comments in the PNK_STATEMENTLIST case.
    5017                 :          */
    5018           40990 :         JS_ASSERT(pn->isOp(JSOP_NOP));
    5019           40990 :         JS_ASSERT(bce->inFunction());
    5020           40990 :         return EmitFunctionDefNop(cx, bce, pn->pn_index);
    5021                 :     }
    5022                 : 
    5023           68191 :     JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
    5024         1046535 :                  fun->kind() == JSFUN_INTERPRETED);
    5025                 : 
    5026                 :     {
    5027                 :         /*
    5028                 :          * Generate code for the function's body.  bce2 is not allocated on the
    5029                 :          * stack because doing so significantly reduces the maximum depth of
    5030                 :          * nested functions we can handle.  See bug 696284.
    5031                 :          */
    5032         1956688 :         AutoPtr<BytecodeEmitter> bce2(cx);
    5033          978344 :         bce2 = cx->new_<BytecodeEmitter>(bce->parser, pn->pn_pos.begin.lineno);
    5034          978344 :         if (!bce2 || !bce2->init(cx))
    5035               0 :             return false;
    5036                 : 
    5037          978344 :         bce2->flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION |
    5038          978344 :                      (bce->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
    5039          978344 :         bce2->bindings.transfer(cx, &pn->pn_funbox->bindings);
    5040          978344 :         bce2->setFunction(fun);
    5041          978344 :         bce2->funbox = pn->pn_funbox;
    5042          978344 :         bce2->parent = bce;
    5043          978344 :         bce2->globalScope = bce->globalScope;
    5044                 : 
    5045                 :         /*
    5046                 :          * js::frontend::SetStaticLevel limited static nesting depth to fit in
    5047                 :          * 16 bits and to reserve the all-ones value, thereby reserving the
    5048                 :          * magic FREE_UPVAR_COOKIE value. Note the bce2->staticLevel assignment
    5049                 :          * below.
    5050                 :          */
    5051          978344 :         JS_ASSERT(bce->staticLevel < JS_BITMASK(16) - 1);
    5052          978344 :         bce2->staticLevel = bce->staticLevel + 1;
    5053                 : 
    5054                 :         /* We measured the max scope depth when we parsed the function. */
    5055          978344 :         if (!EmitFunctionScript(cx, bce2.get(), pn->pn_body))
    5056               0 :             return false;
    5057                 :     }
    5058                 : 
    5059                 :     /* Make the function object a literal in the outer script's pool. */
    5060          978344 :     unsigned index = bce->objectList.index(pn->pn_funbox);
    5061                 : 
    5062                 :     /* Emit a bytecode pointing to the closure object in its immediate. */
    5063          978344 :     if (pn->getOp() != JSOP_NOP) {
    5064          751935 :         if ((pn->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) &&
    5065             177 :             NewSrcNote(cx, bce, SRC_GENEXP) < 0)
    5066                 :         {
    5067               0 :             return false;
    5068                 :         }
    5069                 : 
    5070          751758 :         return EmitFunctionOp(cx, pn->getOp(), index, bce);
    5071                 :     }
    5072                 : 
    5073                 :     /*
    5074                 :      * For a script we emit the code as we parse. Thus the bytecode for
    5075                 :      * top-level functions should go in the prolog to predefine their
    5076                 :      * names in the variable object before the already-generated main code
    5077                 :      * is executed. This extra work for top-level scripts is not necessary
    5078                 :      * when we emit the code for a function. It is fully parsed prior to
    5079                 :      * invocation of the emitter and calls to EmitTree for function
    5080                 :      * definitions can be scheduled before generating the rest of code.
    5081                 :      */
    5082          226586 :     if (!bce->inFunction()) {
    5083          185596 :         JS_ASSERT(!bce->topStmt);
    5084          185596 :         if (!BindGlobal(cx, bce, pn, fun->atom))
    5085               0 :             return false;
    5086          185596 :         if (pn->pn_cookie.isFree()) {
    5087          163606 :             bce->switchToProlog();
    5088          163606 :             MOZ_ASSERT(!fun->isFlatClosure(),
    5089          163606 :                        "global functions can't have upvars, so they are never flat");
    5090          163606 :             if (!EmitFunctionOp(cx, JSOP_DEFFUN, index, bce))
    5091               0 :                 return false;
    5092          163606 :             if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
    5093               0 :                 return false;
    5094          163606 :             bce->switchToMain();
    5095                 :         }
    5096                 : 
    5097                 :         /* Emit NOP for the decompiler. */
    5098          185596 :         if (!EmitFunctionDefNop(cx, bce, index))
    5099               0 :             return false;
    5100                 :     } else {
    5101                 :         unsigned slot;
    5102           81980 :         DebugOnly<BindingKind> kind = bce->bindings.lookup(cx, fun->atom, &slot);
    5103           40990 :         JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
    5104           40990 :         JS_ASSERT(index < JS_BIT(20));
    5105           40990 :         pn->pn_index = index;
    5106           40990 :         JSOp op = fun->isFlatClosure() ? JSOP_DEFLOCALFUN_FC : JSOP_DEFLOCALFUN;
    5107           81203 :         if (pn->isClosed() &&
    5108           20165 :             !bce->callsEval() &&
    5109           20048 :             !bce->closedVars.append(pn->pn_cookie.slot()))
    5110                 :         {
    5111               0 :             return false;
    5112                 :         }
    5113           40990 :         return EmitSlotObjectOp(cx, op, slot, index, bce);
    5114                 :     }
    5115                 : 
    5116          185596 :     return true;
    5117                 : }
    5118                 : 
    5119                 : static bool
    5120             383 : EmitDo(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5121                 : {
    5122                 :     /* Emit an annotated nop so we know to decompile a 'do' keyword. */
    5123             383 :     ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_WHILE);
    5124             383 :     if (noteIndex < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
    5125               0 :         return false;
    5126                 : 
    5127             383 :     ptrdiff_t noteIndex2 = NewSrcNote(cx, bce, SRC_WHILE);
    5128             383 :     if (noteIndex2 < 0)
    5129               0 :         return false;
    5130                 : 
    5131                 :     /* Compile the loop body. */
    5132             383 :     ptrdiff_t top = EmitLoopHead(cx, bce, pn->pn_left);
    5133             383 :     if (top < 0)
    5134               0 :         return false;
    5135             383 :     if (!EmitLoopEntry(cx, bce, NULL))
    5136               0 :         return false;
    5137                 : 
    5138                 :     StmtInfo stmtInfo;
    5139             383 :     PushStatement(bce, &stmtInfo, STMT_DO_LOOP, top);
    5140             383 :     if (!EmitTree(cx, bce, pn->pn_left))
    5141               0 :         return false;
    5142                 : 
    5143                 :     /* Set loop and enclosing label update offsets, for continue. */
    5144             383 :     ptrdiff_t off = bce->offset();
    5145             383 :     StmtInfo *stmt = &stmtInfo;
    5146             383 :     do {
    5147             383 :         stmt->update = off;
    5148                 :     } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
    5149                 : 
    5150                 :     /* Compile the loop condition, now that continues know where to go. */
    5151             383 :     if (!EmitTree(cx, bce, pn->pn_right))
    5152               0 :         return false;
    5153                 : 
    5154                 :     /*
    5155                 :      * Since we use JSOP_IFNE for other purposes as well as for do-while
    5156                 :      * loops, we must store 1 + (beq - top) in the SRC_WHILE note offset,
    5157                 :      * and the decompiler must get that delta and decompile recursively.
    5158                 :      */
    5159             383 :     ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFNE, top - bce->offset());
    5160             383 :     if (beq < 0)
    5161               0 :         return false;
    5162                 : 
    5163                 :     /*
    5164                 :      * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
    5165                 :      * note gets bigger.
    5166                 :      */
    5167             383 :     if (!SetSrcNoteOffset(cx, bce, noteIndex2, 0, beq - top))
    5168               0 :         return false;
    5169             383 :     if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, 1 + (off - top)))
    5170               0 :         return false;
    5171                 : 
    5172             383 :     return PopStatementBCE(cx, bce);
    5173                 : }
    5174                 : 
    5175                 : static bool
    5176           51638 : EmitWhile(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    5177                 : {
    5178                 :     /*
    5179                 :      * Minimize bytecodes issued for one or more iterations by jumping to
    5180                 :      * the condition below the body and closing the loop if the condition
    5181                 :      * is true with a backward branch. For iteration count i:
    5182                 :      *
    5183                 :      *  i    test at the top                 test at the bottom
    5184                 :      *  =    ===============                 ==================
    5185                 :      *  0    ifeq-pass                       goto; ifne-fail
    5186                 :      *  1    ifeq-fail; goto; ifne-pass      goto; ifne-pass; ifne-fail
    5187                 :      *  2    2*(ifeq-fail; goto); ifeq-pass  goto; 2*ifne-pass; ifne-fail
    5188                 :      *  . . .
    5189                 :      *  N    N*(ifeq-fail; goto); ifeq-pass  goto; N*ifne-pass; ifne-fail
    5190                 :      */
    5191                 :     StmtInfo stmtInfo;
    5192           51638 :     PushStatement(bce, &stmtInfo, STMT_WHILE_LOOP, top);
    5193                 : 
    5194           51638 :     ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_WHILE);
    5195           51638 :     if (noteIndex < 0)
    5196               0 :         return false;
    5197                 : 
    5198           51638 :     ptrdiff_t jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
    5199           51638 :     if (jmp < 0)
    5200               0 :         return false;
    5201                 : 
    5202           51638 :     top = EmitLoopHead(cx, bce, pn->pn_right);
    5203           51638 :     if (top < 0)
    5204               0 :         return false;
    5205                 : 
    5206           51638 :     if (!EmitTree(cx, bce, pn->pn_right))
    5207               0 :         return false;
    5208                 : 
    5209           51638 :     SetJumpOffsetAt(bce, jmp);
    5210           51638 :     if (!EmitLoopEntry(cx, bce, pn->pn_left))
    5211               0 :         return false;
    5212           51638 :     if (!EmitTree(cx, bce, pn->pn_left))
    5213               0 :         return false;
    5214                 : 
    5215           51638 :     ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFNE, top - bce->offset());
    5216           51638 :     if (beq < 0)
    5217               0 :         return false;
    5218                 : 
    5219           51638 :     if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, beq - jmp))
    5220               0 :         return false;
    5221                 : 
    5222           51638 :     return PopStatementBCE(cx, bce);
    5223                 : }
    5224                 : 
    5225                 : static bool
    5226           53010 : EmitBreak(JSContext *cx, BytecodeEmitter *bce, PropertyName *label)
    5227                 : {
    5228           53010 :     StmtInfo *stmt = bce->topStmt;
    5229                 :     SrcNoteType noteType;
    5230                 :     jsatomid labelIndex;
    5231           53010 :     if (label) {
    5232              90 :         if (!bce->makeAtomIndex(label, &labelIndex))
    5233               0 :             return false;
    5234                 : 
    5235             594 :         while (stmt->type != STMT_LABEL || stmt->label != label)
    5236             414 :             stmt = stmt->down;
    5237              90 :         noteType = SRC_BREAK2LABEL;
    5238                 :     } else {
    5239           52920 :         labelIndex = INVALID_ATOMID;
    5240          181383 :         while (!STMT_IS_LOOP(stmt) && stmt->type != STMT_SWITCH)
    5241           75543 :             stmt = stmt->down;
    5242           52920 :         noteType = (stmt->type == STMT_SWITCH) ? SRC_SWITCHBREAK : SRC_BREAK;
    5243                 :     }
    5244                 : 
    5245           53010 :     return EmitGoto(cx, bce, stmt, &stmt->breaks, labelIndex, noteType) >= 0;
    5246                 : }
    5247                 : 
    5248                 : static bool
    5249           38621 : EmitContinue(JSContext *cx, BytecodeEmitter *bce, PropertyName *label)
    5250                 : {
    5251           38621 :     StmtInfo *stmt = bce->topStmt;
    5252                 :     SrcNoteType noteType;
    5253                 :     jsatomid labelIndex;
    5254           38621 :     if (label) {
    5255              46 :         if (!bce->makeAtomIndex(label, &labelIndex))
    5256               0 :             return false;
    5257                 : 
    5258                 :         /* Find the loop statement enclosed by the matching label. */
    5259              46 :         StmtInfo *loop = NULL;
    5260             301 :         while (stmt->type != STMT_LABEL || stmt->label != label) {
    5261             209 :             if (STMT_IS_LOOP(stmt))
    5262              77 :                 loop = stmt;
    5263             209 :             stmt = stmt->down;
    5264                 :         }
    5265              46 :         stmt = loop;
    5266              46 :         noteType = SRC_CONT2LABEL;
    5267                 :     } else {
    5268           38575 :         labelIndex = INVALID_ATOMID;
    5269          236227 :         while (!STMT_IS_LOOP(stmt))
    5270          159077 :             stmt = stmt->down;
    5271           38575 :         noteType = SRC_CONTINUE;
    5272                 :     }
    5273                 : 
    5274           38621 :     return EmitGoto(cx, bce, stmt, &stmt->continues, labelIndex, noteType) >= 0;
    5275                 : }
    5276                 : 
    5277                 : static bool
    5278          660086 : EmitReturn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5279                 : {
    5280                 :     /* Push a return value */
    5281          660086 :     if (ParseNode *pn2 = pn->pn_kid) {
    5282          548038 :         if (!EmitTree(cx, bce, pn2))
    5283               0 :             return false;
    5284                 :     } else {
    5285                 :         /* No explicit return value provided */
    5286          112048 :         if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    5287               0 :             return false;
    5288                 :     }
    5289                 : 
    5290                 :     /*
    5291                 :      * EmitNonLocalJumpFixup may add fixup bytecode to close open try
    5292                 :      * blocks having finally clauses and to exit intermingled let blocks.
    5293                 :      * We can't simply transfer control flow to our caller in that case,
    5294                 :      * because we must gosub to those finally clauses from inner to outer,
    5295                 :      * with the correct stack pointer (i.e., after popping any with,
    5296                 :      * for/in, etc., slots nested inside the finally's try).
    5297                 :      *
    5298                 :      * In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an
    5299                 :      * extra JSOP_RETRVAL after the fixups.
    5300                 :      */
    5301          660086 :     ptrdiff_t top = bce->offset();
    5302                 : 
    5303          660086 :     if (Emit1(cx, bce, JSOP_RETURN) < 0)
    5304               0 :         return false;
    5305          660086 :     if (!EmitNonLocalJumpFixup(cx, bce, NULL))
    5306               0 :         return false;
    5307          660086 :     if (top + JSOP_RETURN_LENGTH != bce->offset()) {
    5308           73810 :         bce->base()[top] = JSOP_SETRVAL;
    5309           73810 :         if (Emit1(cx, bce, JSOP_RETRVAL) < 0)
    5310               0 :             return false;
    5311                 :     }
    5312                 : 
    5313          660086 :     return true;
    5314                 : }
    5315                 : 
    5316                 : static bool
    5317         2400798 : EmitStatementList(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    5318                 : {
    5319         2400798 :     JS_ASSERT(pn->isArity(PN_LIST));
    5320                 : 
    5321         2400798 :     ptrdiff_t noteIndex = -1;
    5322         2400798 :     ptrdiff_t tmp = bce->offset();
    5323         2400798 :     if (pn->pn_xflags & PNX_NEEDBRACES) {
    5324             102 :         noteIndex = NewSrcNote2(cx, bce, SRC_BRACE, 0);
    5325             102 :         if (noteIndex < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
    5326               0 :             return false;
    5327                 :     }
    5328                 : 
    5329                 :     StmtInfo stmtInfo;
    5330         2400798 :     PushStatement(bce, &stmtInfo, STMT_BLOCK, top);
    5331                 : 
    5332         2400798 :     ParseNode *pnchild = pn->pn_head;
    5333         2400798 :     if (pn->pn_xflags & PNX_FUNCDEFS) {
    5334                 :         /*
    5335                 :          * This block contains top-level function definitions. To ensure
    5336                 :          * that we emit the bytecode defining them before the rest of code
    5337                 :          * in the block we use a separate pass over functions. During the
    5338                 :          * main pass later the emitter will add JSOP_NOP with source notes
    5339                 :          * for the function to preserve the original functions position
    5340                 :          * when decompiling.
    5341                 :          *
    5342                 :          * Currently this is used only for functions, as compile-as-we go
    5343                 :          * mode for scripts does not allow separate emitter passes.
    5344                 :          */
    5345           27995 :         JS_ASSERT(bce->inFunction());
    5346           27995 :         if (pn->pn_xflags & PNX_DESTRUCT) {
    5347                 :             /*
    5348                 :              * Assign the destructuring arguments before defining any
    5349                 :              * functions, see bug 419662.
    5350                 :              */
    5351               4 :             JS_ASSERT(pnchild->isKind(PNK_SEMI));
    5352               4 :             JS_ASSERT(pnchild->pn_kid->isKind(PNK_VAR) || pnchild->pn_kid->isKind(PNK_CONST));
    5353               4 :             if (!EmitTree(cx, bce, pnchild))
    5354               0 :                 return false;
    5355               4 :             pnchild = pnchild->pn_next;
    5356                 :         }
    5357                 : 
    5358          308437 :         for (ParseNode *pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
    5359          280442 :             if (pn2->isKind(PNK_FUNCTION)) {
    5360           40990 :                 if (pn2->isOp(JSOP_NOP)) {
    5361           40990 :                     if (!EmitTree(cx, bce, pn2))
    5362               0 :                         return false;
    5363                 :                 } else {
    5364                 :                     /*
    5365                 :                      * JSOP_DEFFUN in a top-level block with function
    5366                 :                      * definitions appears, for example, when "if (true)"
    5367                 :                      * is optimized away from "if (true) function x() {}".
    5368                 :                      * See bug 428424.
    5369                 :                      */
    5370               0 :                     JS_ASSERT(pn2->isOp(JSOP_DEFFUN));
    5371                 :                 }
    5372                 :             }
    5373                 :         }
    5374                 :     }
    5375                 : 
    5376        11230146 :     for (ParseNode *pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
    5377         8829348 :         if (!EmitTree(cx, bce, pn2))
    5378               0 :             return false;
    5379                 :     }
    5380                 : 
    5381         2400798 :     if (noteIndex >= 0 && !SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, bce->offset() - tmp))
    5382               0 :         return false;
    5383                 : 
    5384         2400798 :     return PopStatementBCE(cx, bce);
    5385                 : }
    5386                 : 
    5387                 : static bool
    5388         6474702 : EmitStatement(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5389                 : {
    5390         6474702 :     JS_ASSERT(pn->isKind(PNK_SEMI));
    5391                 : 
    5392         6474702 :     ParseNode *pn2 = pn->pn_kid;
    5393         6474702 :     if (!pn2)
    5394            4830 :         return true;
    5395                 : 
    5396                 :     /*
    5397                 :      * Top-level or called-from-a-native JS_Execute/EvaluateScript,
    5398                 :      * debugger, and eval frames may need the value of the ultimate
    5399                 :      * expression statement as the script's result, despite the fact
    5400                 :      * that it appears useless to the compiler.
    5401                 :      *
    5402                 :      * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
    5403                 :      * calling JS_Compile* to suppress JSOP_POPV.
    5404                 :      */
    5405                 :     bool wantval;
    5406         6469872 :     JSBool useful = wantval = !(bce->flags & (TCF_IN_FUNCTION | TCF_NO_SCRIPT_RVAL));
    5407                 : 
    5408                 :     /* Don't eliminate expressions with side effects. */
    5409         6469872 :     if (!useful) {
    5410         5774353 :         if (!CheckSideEffects(cx, bce, pn2, &useful))
    5411               0 :             return false;
    5412                 : 
    5413                 :         /*
    5414                 :          * Don't eliminate apparently useless expressions if they are
    5415                 :          * labeled expression statements.  The tc->topStmt->update test
    5416                 :          * catches the case where we are nesting in EmitTree for a labeled
    5417                 :          * compound statement.
    5418                 :          */
    5419         5774380 :         if (bce->topStmt &&
    5420                 :             bce->topStmt->type == STMT_LABEL &&
    5421              27 :             bce->topStmt->update >= bce->offset())
    5422                 :         {
    5423              27 :             useful = true;
    5424                 :         }
    5425                 :     }
    5426                 : 
    5427         6469872 :     if (useful) {
    5428         6466410 :         JSOp op = wantval ? JSOP_POPV : JSOP_POP;
    5429         6466410 :         JS_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
    5430                 : #if JS_HAS_DESTRUCTURING
    5431        14531945 :         if (!wantval &&
    5432         5770891 :             pn2->isKind(PNK_ASSIGN) &&
    5433         2294644 :             !MaybeEmitGroupAssignment(cx, bce, op, pn2, &op))
    5434                 :         {
    5435               0 :             return false;
    5436                 :         }
    5437                 : #endif
    5438         6466410 :         if (op != JSOP_NOP) {
    5439         6466089 :             if (!EmitTree(cx, bce, pn2))
    5440               0 :                 return false;
    5441         6466089 :             if (Emit1(cx, bce, op) < 0)
    5442               0 :                 return false;
    5443                 :         }
    5444            3462 :     } else if (!pn->isDirectivePrologueMember()) {
    5445                 :         /* Don't complain about directive prologue members; just don't emit their code. */
    5446             704 :         bce->current->currentLine = pn2->pn_pos.begin.lineno;
    5447             704 :         if (!ReportCompileErrorNumber(cx, bce->tokenStream(), pn2,
    5448             704 :                                       JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_USELESS_EXPR))
    5449                 :         {
    5450               0 :             return false;
    5451                 :         }
    5452                 :     }
    5453                 : 
    5454         6469872 :     return true;
    5455                 : }
    5456                 : 
    5457                 : static bool
    5458           37494 : EmitDelete(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5459                 : {
    5460                 :     /*
    5461                 :      * Under ECMA 3, deleting a non-reference returns true -- but alas we
    5462                 :      * must evaluate the operand if it appears it might have side effects.
    5463                 :      */
    5464           37494 :     ParseNode *pn2 = pn->pn_kid;
    5465           37494 :     switch (pn2->getKind()) {
    5466                 :       case PNK_NAME:
    5467                 :       {
    5468             491 :         if (!BindNameToSlot(cx, bce, pn2))
    5469               0 :             return false;
    5470             491 :         JSOp op = pn2->getOp();
    5471             491 :         if (op == JSOP_FALSE) {
    5472              18 :             if (Emit1(cx, bce, op) < 0)
    5473               0 :                 return false;
    5474                 :         } else {
    5475             473 :             if (!EmitAtomOp(cx, pn2, op, bce))
    5476               0 :                 return false;
    5477                 :         }
    5478             491 :         break;
    5479                 :       }
    5480                 :       case PNK_DOT:
    5481           22915 :         if (!EmitPropOp(cx, pn2, JSOP_DELPROP, bce, false))
    5482               0 :             return false;
    5483           22915 :         break;
    5484                 : #if JS_HAS_XML_SUPPORT
    5485                 :       case PNK_DBLDOT:
    5486               0 :         JS_ASSERT(!bce->inStrictMode());
    5487               0 :         if (!EmitElemOp(cx, pn2, JSOP_DELDESC, bce))
    5488               0 :             return false;
    5489               0 :         break;
    5490                 : #endif
    5491                 :       case PNK_LB:
    5492           14088 :         if (!EmitElemOp(cx, pn2, JSOP_DELELEM, bce))
    5493               0 :             return false;
    5494           14088 :         break;
    5495                 :       default:
    5496                 :       {
    5497                 :         /*
    5498                 :          * If useless, just emit JSOP_TRUE; otherwise convert delete foo()
    5499                 :          * to foo(), true (a comma expression, requiring SRC_PCDELTA).
    5500                 :          */
    5501               0 :         JSBool useful = false;
    5502               0 :         if (!CheckSideEffects(cx, bce, pn2, &useful))
    5503               0 :             return false;
    5504                 : 
    5505                 :         ptrdiff_t off, noteIndex;
    5506               0 :         if (useful) {
    5507               0 :             JS_ASSERT_IF(pn2->isKind(PNK_LP), !(pn2->pn_xflags & PNX_SETCALL));
    5508               0 :             if (!EmitTree(cx, bce, pn2))
    5509               0 :                 return false;
    5510               0 :             off = bce->offset();
    5511               0 :             noteIndex = NewSrcNote2(cx, bce, SRC_PCDELTA, 0);
    5512               0 :             if (noteIndex < 0 || Emit1(cx, bce, JSOP_POP) < 0)
    5513               0 :                 return false;
    5514                 :         } else {
    5515               0 :             off = noteIndex = -1;
    5516                 :         }
    5517                 : 
    5518               0 :         if (Emit1(cx, bce, JSOP_TRUE) < 0)
    5519               0 :             return false;
    5520               0 :         if (noteIndex >= 0) {
    5521               0 :             ptrdiff_t tmp = bce->offset();
    5522               0 :             if (!SetSrcNoteOffset(cx, bce, unsigned(noteIndex), 0, tmp - off))
    5523               0 :                 return false;
    5524                 :         }
    5525                 :       }
    5526                 :     }
    5527                 : 
    5528           37494 :     return true;
    5529                 : }
    5530                 : 
    5531                 : static bool
    5532         3331826 : EmitCallOrNew(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    5533                 : {
    5534         3331826 :     bool callop = pn->isKind(PNK_LP);
    5535                 : 
    5536                 :     /*
    5537                 :      * Emit callable invocation or operator new (constructor call) code.
    5538                 :      * First, emit code for the left operand to evaluate the callable or
    5539                 :      * constructable object expression.
    5540                 :      *
    5541                 :      * For operator new applied to other expressions than E4X ones, we emit
    5542                 :      * JSOP_GETPROP instead of JSOP_CALLPROP, etc. This is necessary to
    5543                 :      * interpose the lambda-initialized method read barrier -- see the code
    5544                 :      * in jsinterp.cpp for JSOP_LAMBDA followed by JSOP_{SET,INIT}PROP.
    5545                 :      *
    5546                 :      * Then (or in a call case that has no explicit reference-base
    5547                 :      * object) we emit JSOP_UNDEFINED to produce the undefined |this| 
    5548                 :      * value required for calls (which non-strict mode functions 
    5549                 :      * will box into the global object).
    5550                 :      */
    5551         3331826 :     ParseNode *pn2 = pn->pn_head;
    5552         3331826 :     switch (pn2->getKind()) {
    5553                 :       case PNK_NAME:
    5554         1003934 :         if (!EmitNameOp(cx, bce, pn2, callop))
    5555               0 :             return false;
    5556         1003934 :         break;
    5557                 :       case PNK_DOT:
    5558         2313918 :         if (!EmitPropOp(cx, pn2, pn2->getOp(), bce, callop))
    5559               0 :             return false;
    5560         2313918 :         break;
    5561                 :       case PNK_LB:
    5562            4740 :         JS_ASSERT(pn2->isOp(JSOP_GETELEM));
    5563            4740 :         if (!EmitElemOp(cx, pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM, bce))
    5564               0 :             return false;
    5565            4740 :         break;
    5566                 : #if JS_HAS_XML_SUPPORT
    5567                 :       case PNK_XMLUNARY:
    5568               9 :         JS_ASSERT(pn2->isOp(JSOP_XMLNAME));
    5569               9 :         if (!EmitXMLName(cx, pn2, JSOP_CALLXMLNAME, bce))
    5570               0 :             return false;
    5571               9 :         callop = true;          /* suppress JSOP_UNDEFINED after */
    5572               9 :         break;
    5573                 : #endif
    5574                 :       default:
    5575            9225 :         if (!EmitTree(cx, bce, pn2))
    5576               0 :             return false;
    5577            9225 :         callop = false;             /* trigger JSOP_UNDEFINED after */
    5578            9225 :         break;
    5579                 :     }
    5580         3331826 :     if (!callop && Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    5581               0 :         return false;
    5582                 : 
    5583                 :     /* Remember start of callable-object bytecode for decompilation hint. */
    5584         3331826 :     ptrdiff_t off = top;
    5585                 : 
    5586                 :     /*
    5587                 :      * Emit code for each argument in order, then emit the JSOP_*CALL or
    5588                 :      * JSOP_NEW bytecode with a two-byte immediate telling how many args
    5589                 :      * were pushed on the operand stack.
    5590                 :      */
    5591         3331826 :     unsigned oldflags = bce->flags;
    5592         3331826 :     bce->flags &= ~TCF_IN_FOR_INIT;
    5593         7695471 :     for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
    5594         4363645 :         if (!EmitTree(cx, bce, pn3))
    5595               0 :             return false;
    5596                 :     }
    5597         3331826 :     bce->flags |= oldflags & TCF_IN_FOR_INIT;
    5598         3331826 :     if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - off) < 0)
    5599               0 :         return false;
    5600                 : 
    5601         3331826 :     uint32_t argc = pn->pn_count - 1;
    5602         3331826 :     if (Emit3(cx, bce, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0)
    5603               0 :         return false;
    5604         3331826 :     CheckTypeSet(cx, bce, pn->getOp());
    5605         3331826 :     if (pn->isOp(JSOP_EVAL))
    5606            4789 :         EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
    5607         3331826 :     if (pn->pn_xflags & PNX_SETCALL) {
    5608              27 :         if (Emit1(cx, bce, JSOP_SETCALL) < 0)
    5609               0 :             return false;
    5610                 :     }
    5611         3331826 :     return true;
    5612                 : }
    5613                 : 
    5614                 : static bool
    5615          229653 : EmitLogical(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5616                 : {
    5617                 :     /*
    5618                 :      * JSOP_OR converts the operand on the stack to boolean, leaves the original
    5619                 :      * value on the stack and jumps if true; otherwise it falls into the next
    5620                 :      * bytecode, which pops the left operand and then evaluates the right operand.
    5621                 :      * The jump goes around the right operand evaluation.
    5622                 :      *
    5623                 :      * JSOP_AND converts the operand on the stack to boolean and jumps if false;
    5624                 :      * otherwise it falls into the right operand's bytecode.
    5625                 :      */
    5626                 : 
    5627          229653 :     if (pn->isArity(PN_BINARY)) {
    5628          197108 :         if (!EmitTree(cx, bce, pn->pn_left))
    5629               0 :             return false;
    5630          197108 :         ptrdiff_t top = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
    5631          197108 :         if (top < 0)
    5632               0 :             return false;
    5633          197108 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    5634               0 :             return false;
    5635          197108 :         if (!EmitTree(cx, bce, pn->pn_right))
    5636               0 :             return false;
    5637          197108 :         ptrdiff_t off = bce->offset();
    5638          197108 :         jsbytecode *pc = bce->code(top);
    5639          197108 :         SET_JUMP_OFFSET(pc, off - top);
    5640          197108 :         *pc = pn->getOp();
    5641          197108 :         return true;
    5642                 :     }
    5643                 : 
    5644           32545 :     JS_ASSERT(pn->isArity(PN_LIST));
    5645           32545 :     JS_ASSERT(pn->pn_head->pn_next->pn_next);
    5646                 : 
    5647                 :     /* Left-associative operator chain: avoid too much recursion. */
    5648           32545 :     ParseNode *pn2 = pn->pn_head;
    5649           32545 :     if (!EmitTree(cx, bce, pn2))
    5650               0 :         return false;
    5651           32545 :     ptrdiff_t top = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
    5652           32545 :     if (top < 0)
    5653               0 :         return false;
    5654           32545 :     if (Emit1(cx, bce, JSOP_POP) < 0)
    5655               0 :         return false;
    5656                 : 
    5657                 :     /* Emit nodes between the head and the tail. */
    5658           32545 :     ptrdiff_t jmp = top;
    5659          108234 :     while ((pn2 = pn2->pn_next)->pn_next) {
    5660           43144 :         if (!EmitTree(cx, bce, pn2))
    5661               0 :             return false;
    5662           43144 :         ptrdiff_t off = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
    5663           43144 :         if (off < 0)
    5664               0 :             return false;
    5665           43144 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    5666               0 :             return false;
    5667           43144 :         SET_JUMP_OFFSET(bce->code(jmp), off - jmp);
    5668           43144 :         jmp = off;
    5669                 :     }
    5670           32545 :     if (!EmitTree(cx, bce, pn2))
    5671               0 :         return false;
    5672                 : 
    5673           32545 :     pn2 = pn->pn_head;
    5674           32545 :     ptrdiff_t off = bce->offset();
    5675           75689 :     do {
    5676           75689 :         jsbytecode *pc = bce->code(top);
    5677           75689 :         ptrdiff_t tmp = GET_JUMP_OFFSET(pc);
    5678           75689 :         SET_JUMP_OFFSET(pc, off - top);
    5679           75689 :         *pc = pn->getOp();
    5680           75689 :         top += tmp;
    5681                 :     } while ((pn2 = pn2->pn_next)->pn_next);
    5682                 : 
    5683           32545 :     return true;
    5684                 : }
    5685                 : 
    5686                 : static bool
    5687         1737187 : EmitIncOrDec(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5688                 : {
    5689                 :     /* Emit lvalue-specialized code for ++/-- operators. */
    5690         1737187 :     ParseNode *pn2 = pn->pn_kid;
    5691         1737187 :     JS_ASSERT(!pn2->isKind(PNK_RP));
    5692         1737187 :     JSOp op = pn->getOp();
    5693         1737187 :     switch (pn2->getKind()) {
    5694                 :       case PNK_DOT:
    5695            4874 :         if (!EmitPropIncDec(cx, pn2, op, bce))
    5696               0 :             return false;
    5697            4874 :         break;
    5698                 :       case PNK_LB:
    5699         1638851 :         if (!EmitElemIncDec(cx, pn2, op, bce))
    5700               0 :             return false;
    5701         1638851 :         break;
    5702                 :       case PNK_LP:
    5703               9 :         if (!EmitTree(cx, bce, pn2))
    5704               0 :             return false;
    5705               9 :         if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pn2->pn_offset) < 0)
    5706               0 :             return false;
    5707               9 :         if (Emit1(cx, bce, op) < 0)
    5708               0 :             return false;
    5709                 :         /*
    5710                 :          * This is dead code for the decompiler, don't generate
    5711                 :          * a decomposed version of the opcode. We do need to balance
    5712                 :          * the stacks in the decomposed version.
    5713                 :          */
    5714               9 :         JS_ASSERT(js_CodeSpec[op].format & JOF_DECOMPOSE);
    5715               9 :         JS_ASSERT(js_CodeSpec[op].format & JOF_ELEM);
    5716               9 :         if (Emit1(cx, bce, (JSOp)1) < 0)
    5717               0 :             return false;
    5718               9 :         if (Emit1(cx, bce, JSOP_POP) < 0)
    5719               0 :             return false;
    5720               9 :         break;
    5721                 : #if JS_HAS_XML_SUPPORT
    5722                 :       case PNK_XMLUNARY:
    5723               9 :         JS_ASSERT(!bce->inStrictMode());
    5724               9 :         JS_ASSERT(pn2->isOp(JSOP_SETXMLNAME));
    5725               9 :         if (!EmitTree(cx, bce, pn2->pn_kid))
    5726               0 :             return false;
    5727               9 :         if (Emit1(cx, bce, JSOP_BINDXMLNAME) < 0)
    5728               0 :             return false;
    5729               9 :         if (!EmitElemIncDec(cx, NULL, op, bce))
    5730               0 :             return false;
    5731               9 :         break;
    5732                 : #endif
    5733                 :       default:
    5734           93444 :         JS_ASSERT(pn2->isKind(PNK_NAME));
    5735           93444 :         pn2->setOp(op);
    5736           93444 :         if (!BindNameToSlot(cx, bce, pn2))
    5737               0 :             return false;
    5738           93444 :         op = pn2->getOp();
    5739           93444 :         if (op == JSOP_CALLEE) {
    5740               0 :             if (Emit1(cx, bce, op) < 0)
    5741               0 :                 return false;
    5742           93444 :         } else if (!pn2->pn_cookie.isFree()) {
    5743           70680 :             jsatomid atomIndex = pn2->pn_cookie.asInteger();
    5744           70680 :             EMIT_UINT16_IMM_OP(op, atomIndex);
    5745                 :         } else {
    5746           22764 :             JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
    5747           22764 :             if (js_CodeSpec[op].format & (JOF_INC | JOF_DEC)) {
    5748           22755 :                 if (!EmitNameIncDec(cx, pn2, op, bce))
    5749               0 :                     return false;
    5750                 :             } else {
    5751               9 :                 if (!EmitAtomOp(cx, pn2, op, bce))
    5752               0 :                     return false;
    5753                 :             }
    5754           22764 :             break;
    5755                 :         }
    5756           70680 :         if (pn2->isConst()) {
    5757               0 :             if (Emit1(cx, bce, JSOP_POS) < 0)
    5758               0 :                 return false;
    5759               0 :             op = pn->getOp();
    5760               0 :             if (!(js_CodeSpec[op].format & JOF_POST)) {
    5761               0 :                 if (Emit1(cx, bce, JSOP_ONE) < 0)
    5762               0 :                     return false;
    5763               0 :                 op = (js_CodeSpec[op].format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
    5764               0 :                 if (Emit1(cx, bce, op) < 0)
    5765               0 :                     return false;
    5766                 :             }
    5767                 :         }
    5768                 :     }
    5769         1737187 :     return true;
    5770                 : }
    5771                 : 
    5772                 : /*
    5773                 :  * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr12127. See
    5774                 :  * the comment on EmitSwitch.
    5775                 :  */
    5776                 : MOZ_NEVER_INLINE static bool
    5777             193 : EmitLabel(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5778                 : {
    5779                 :     /*
    5780                 :      * Emit a JSOP_LABEL instruction. The argument is the offset to the statement
    5781                 :      * following the labeled statement. This op has either a SRC_LABEL or
    5782                 :      * SRC_LABELBRACE source note for the decompiler.
    5783                 :      */
    5784             193 :     JSAtom *atom = pn->pn_atom;
    5785                 : 
    5786                 :     jsatomid index;
    5787             193 :     if (!bce->makeAtomIndex(atom, &index))
    5788               0 :         return false;
    5789                 : 
    5790             193 :     ParseNode *pn2 = pn->expr();
    5791             193 :     SrcNoteType noteType = (pn2->isKind(PNK_STATEMENTLIST) ||
    5792             193 :                             (pn2->isKind(PNK_LEXICALSCOPE) &&
    5793               0 :                              pn2->expr()->isKind(PNK_STATEMENTLIST)))
    5794                 :                            ? SRC_LABELBRACE
    5795             386 :                            : SRC_LABEL;
    5796             193 :     ptrdiff_t noteIndex = NewSrcNote2(cx, bce, noteType, ptrdiff_t(index));
    5797             193 :     if (noteIndex < 0)
    5798               0 :         return false;
    5799                 : 
    5800             193 :     ptrdiff_t top = EmitJump(cx, bce, JSOP_LABEL, 0);
    5801             193 :     if (top < 0)
    5802               0 :         return false;
    5803                 : 
    5804                 :     /* Emit code for the labeled statement. */
    5805                 :     StmtInfo stmtInfo;
    5806             193 :     PushStatement(bce, &stmtInfo, STMT_LABEL, bce->offset());
    5807             193 :     stmtInfo.label = atom;
    5808             193 :     if (!EmitTree(cx, bce, pn2))
    5809               0 :         return false;
    5810             193 :     if (!PopStatementBCE(cx, bce))
    5811               0 :         return false;
    5812                 : 
    5813                 :     /* Patch the JSOP_LABEL offset. */
    5814             193 :     SetJumpOffsetAt(bce, top);
    5815                 : 
    5816                 :     /* If the statement was compound, emit a note for the end brace. */
    5817             193 :     if (noteType == SRC_LABELBRACE) {
    5818               0 :         if (NewSrcNote(cx, bce, SRC_ENDBRACE) < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
    5819               0 :             return false;
    5820                 :     }
    5821                 : 
    5822             193 :     return true;
    5823                 : }
    5824                 : 
    5825                 : static bool
    5826             934 : EmitSyntheticStatements(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
    5827                 : {
    5828             934 :     JS_ASSERT(pn->isArity(PN_LIST));
    5829                 :     StmtInfo stmtInfo;
    5830             934 :     PushStatement(bce, &stmtInfo, STMT_SEQ, top);
    5831            2802 :     for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    5832            1868 :         if (!EmitTree(cx, bce, pn2))
    5833               0 :             return false;
    5834                 :     }
    5835             934 :     return PopStatementBCE(cx, bce);
    5836                 : }
    5837                 : 
    5838                 : static bool
    5839           68371 : EmitConditionalExpression(JSContext *cx, BytecodeEmitter *bce, ConditionalExpression &conditional)
    5840                 : {
    5841                 :     /* Emit the condition, then branch if false to the else part. */
    5842           68371 :     if (!EmitTree(cx, bce, &conditional.condition()))
    5843               0 :         return false;
    5844           68371 :     ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_COND);
    5845           68371 :     if (noteIndex < 0)
    5846               0 :         return false;
    5847           68371 :     ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFEQ, 0);
    5848           68371 :     if (beq < 0 || !EmitTree(cx, bce, &conditional.thenExpression()))
    5849               0 :         return false;
    5850                 : 
    5851                 :     /* Jump around else, fixup the branch, emit else, fixup jump. */
    5852           68371 :     ptrdiff_t jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
    5853           68371 :     if (jmp < 0)
    5854               0 :         return false;
    5855           68371 :     SetJumpOffsetAt(bce, beq);
    5856                 : 
    5857                 :     /*
    5858                 :      * Because each branch pushes a single value, but our stack budgeting
    5859                 :      * analysis ignores branches, we now have to adjust bce->stackDepth to
    5860                 :      * ignore the value pushed by the first branch.  Execution will follow
    5861                 :      * only one path, so we must decrement bce->stackDepth.
    5862                 :      *
    5863                 :      * Failing to do this will foil code, such as let expression and block
    5864                 :      * code generation, which must use the stack depth to compute local
    5865                 :      * stack indexes correctly.
    5866                 :      */
    5867           68371 :     JS_ASSERT(bce->stackDepth > 0);
    5868           68371 :     bce->stackDepth--;
    5869           68371 :     if (!EmitTree(cx, bce, &conditional.elseExpression()))
    5870               0 :         return false;
    5871           68371 :     SetJumpOffsetAt(bce, jmp);
    5872           68371 :     return SetSrcNoteOffset(cx, bce, noteIndex, 0, jmp - beq);
    5873                 : }
    5874                 : 
    5875                 : static bool
    5876          216320 : EmitObject(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5877                 : {
    5878                 : #if JS_HAS_DESTRUCTURING_SHORTHAND
    5879          216320 :     if (pn->pn_xflags & PNX_DESTRUCT) {
    5880                 :         ReportCompileErrorNumber(cx, bce->tokenStream(), pn, JSREPORT_ERROR,
    5881               0 :                                  JSMSG_BAD_OBJECT_INIT);
    5882               0 :         return false;
    5883                 :     }
    5884                 : #endif
    5885                 : 
    5886          216320 :     if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && bce->checkSingletonContext())
    5887            1842 :         return EmitSingletonInitialiser(cx, bce, pn);
    5888                 : 
    5889                 :     /*
    5890                 :      * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
    5891                 :      * a new object and in source order evaluating each property value and
    5892                 :      * adding the property to the object, without invoking latent setters.
    5893                 :      * We use the JSOP_NEWINIT and JSOP_INITELEM/JSOP_INITPROP bytecodes to
    5894                 :      * ignore setters and to avoid dup'ing and popping the object as each
    5895                 :      * property is added, as JSOP_SETELEM/JSOP_SETPROP would do.
    5896                 :      */
    5897          214478 :     ptrdiff_t offset = bce->next() - bce->base();
    5898          214478 :     if (!EmitNewInit(cx, bce, JSProto_Object, pn))
    5899               0 :         return false;
    5900                 : 
    5901                 :     /*
    5902                 :      * Try to construct the shape of the object as we go, so we can emit a
    5903                 :      * JSOP_NEWOBJECT with the final shape instead.
    5904                 :      */
    5905          214478 :     JSObject *obj = NULL;
    5906          214478 :     if (bce->compileAndGo()) {
    5907            9811 :         gc::AllocKind kind = GuessObjectGCKind(pn->pn_count);
    5908            9811 :         obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
    5909            9811 :         if (!obj)
    5910               0 :             return false;
    5911                 :     }
    5912                 : 
    5913          214478 :     unsigned methodInits = 0, slowMethodInits = 0;
    5914         1082713 :     for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    5915                 :         /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
    5916          868235 :         ParseNode *pn3 = pn2->pn_left;
    5917          868235 :         if (pn3->isKind(PNK_NUMBER)) {
    5918            4205 :             if (!EmitNumberOp(cx, pn3->pn_dval, bce))
    5919               0 :                 return false;
    5920                 :         }
    5921                 : 
    5922                 :         /* Emit code for the property initializer. */
    5923          868235 :         if (!EmitTree(cx, bce, pn2->pn_right))
    5924               0 :             return false;
    5925                 : 
    5926          868235 :         JSOp op = pn2->getOp();
    5927          868235 :         if (op == JSOP_GETTER || op == JSOP_SETTER) {
    5928           67597 :             obj = NULL;
    5929           67597 :             if (Emit1(cx, bce, op) < 0)
    5930               0 :                 return false;
    5931                 :         }
    5932                 : 
    5933                 :         /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */
    5934          868235 :         if (pn3->isKind(PNK_NUMBER)) {
    5935            4205 :             obj = NULL;
    5936            4205 :             if (NewSrcNote(cx, bce, SRC_INITPROP) < 0)
    5937               0 :                 return false;
    5938            4205 :             if (Emit1(cx, bce, JSOP_INITELEM) < 0)
    5939               0 :                 return false;
    5940                 :         } else {
    5941          864030 :             JS_ASSERT(pn3->isKind(PNK_NAME) || pn3->isKind(PNK_STRING));
    5942                 :             jsatomid index;
    5943          864030 :             if (!bce->makeAtomIndex(pn3->pn_atom, &index))
    5944               0 :                 return false;
    5945                 : 
    5946                 :             /*
    5947                 :              * Disable NEWOBJECT on initializers that set __proto__, which has
    5948                 :              * a non-standard setter on objects.
    5949                 :              */
    5950          864030 :             if (pn3->pn_atom == cx->runtime->atomState.protoAtom)
    5951            9780 :                 obj = NULL;
    5952          864030 :             op = JSOP_INITPROP;
    5953                 : 
    5954          864030 :             if (obj) {
    5955           10518 :                 JS_ASSERT(!obj->inDictionaryMode());
    5956           21036 :                 if (!DefineNativeProperty(cx, obj, ATOM_TO_JSID(pn3->pn_atom),
    5957                 :                                           UndefinedValue(), NULL, NULL,
    5958           21036 :                                           JSPROP_ENUMERATE, 0, 0))
    5959                 :                 {
    5960               0 :                     return false;
    5961                 :                 }
    5962           10518 :                 if (obj->inDictionaryMode())
    5963               0 :                     obj = NULL;
    5964                 :             }
    5965                 : 
    5966          864030 :             if (!EmitIndex32(cx, op, index, bce))
    5967               0 :                 return false;
    5968                 :         }
    5969                 :     }
    5970                 : 
    5971          214478 :     if (Emit1(cx, bce, JSOP_ENDINIT) < 0)
    5972               0 :         return false;
    5973                 : 
    5974          214478 :     if (obj) {
    5975                 :         /*
    5976                 :          * The object survived and has a predictable shape: update the original
    5977                 :          * bytecode.
    5978                 :          */
    5979            9143 :         ObjectBox *objbox = bce->parser->newObjectBox(obj);
    5980            9143 :         if (!objbox)
    5981               0 :             return false;
    5982            9143 :         unsigned index = bce->objectList.index(objbox);
    5983                 :         MOZ_STATIC_ASSERT(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
    5984                 :                           "newinit and newobject must have equal length to edit in-place");
    5985            9143 :         EMIT_UINT32_IN_PLACE(offset, JSOP_NEWOBJECT, uint32_t(index));
    5986                 :     }
    5987                 : 
    5988          214478 :     return true;
    5989                 : }
    5990                 : 
    5991                 : static bool
    5992          224358 : EmitArray(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    5993                 : {
    5994                 :     /*
    5995                 :      * Emit code for [a, b, c] that is equivalent to constructing a new
    5996                 :      * array and in source order evaluating each element value and adding
    5997                 :      * it to the array, without invoking latent setters.  We use the
    5998                 :      * JSOP_NEWINIT and JSOP_INITELEM bytecodes to ignore setters and to
    5999                 :      * avoid dup'ing and popping the array as each element is added, as
    6000                 :      * JSOP_SETELEM/JSOP_SETPROP would do.
    6001                 :      */
    6002                 : 
    6003                 : #if JS_HAS_GENERATORS
    6004          224358 :     if (pn->isKind(PNK_ARRAYCOMP)) {
    6005           12678 :         if (!EmitNewInit(cx, bce, JSProto_Array, pn))
    6006               0 :             return false;
    6007                 : 
    6008                 :         /*
    6009                 :          * Pass the new array's stack index to the PNK_ARRAYPUSH case via
    6010                 :          * bce->arrayCompDepth, then simply traverse the PNK_FOR node and
    6011                 :          * its kids under pn2 to generate this comprehension.
    6012                 :          */
    6013           12678 :         JS_ASSERT(bce->stackDepth > 0);
    6014           12678 :         unsigned saveDepth = bce->arrayCompDepth;
    6015           12678 :         bce->arrayCompDepth = (uint32_t) (bce->stackDepth - 1);
    6016           12678 :         if (!EmitTree(cx, bce, pn->pn_head))
    6017               0 :             return false;
    6018           12678 :         bce->arrayCompDepth = saveDepth;
    6019                 : 
    6020                 :         /* Emit the usual op needed for decompilation. */
    6021           12678 :         return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
    6022                 :     }
    6023                 : #endif /* JS_HAS_GENERATORS */
    6024                 : 
    6025          211680 :     if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && bce->checkSingletonContext())
    6026            5434 :         return EmitSingletonInitialiser(cx, bce, pn);
    6027                 : 
    6028          206246 :     ptrdiff_t off = EmitN(cx, bce, JSOP_NEWARRAY, 3);
    6029          206246 :     if (off < 0)
    6030               0 :         return false;
    6031          206246 :     CheckTypeSet(cx, bce, JSOP_NEWARRAY);
    6032          206246 :     jsbytecode *pc = bce->code(off);
    6033          206246 :     SET_UINT24(pc, pn->pn_count);
    6034                 : 
    6035          206246 :     ParseNode *pn2 = pn->pn_head;
    6036                 :     jsatomid atomIndex;
    6037         5494817 :     for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
    6038         5288571 :         if (!EmitNumberOp(cx, atomIndex, bce))
    6039               0 :             return false;
    6040         5288571 :         if (pn2->isKind(PNK_COMMA) && pn2->isArity(PN_NULLARY)) {
    6041            4899 :             if (Emit1(cx, bce, JSOP_HOLE) < 0)
    6042               0 :                 return false;
    6043                 :         } else {
    6044         5283672 :             if (!EmitTree(cx, bce, pn2))
    6045               0 :                 return false;
    6046                 :         }
    6047         5288571 :         if (Emit1(cx, bce, JSOP_INITELEM) < 0)
    6048               0 :             return false;
    6049                 :     }
    6050          206246 :     JS_ASSERT(atomIndex == pn->pn_count);
    6051                 : 
    6052          206246 :     if (pn->pn_xflags & PNX_ENDCOMMA) {
    6053                 :         /* Emit a source note so we know to decompile an extra comma. */
    6054            2337 :         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
    6055               0 :             return false;
    6056                 :     }
    6057                 : 
    6058                 :     /* Emit an op to finish the array and aid in decompilation. */
    6059          206246 :     return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
    6060                 : }
    6061                 : 
    6062                 : static bool
    6063          531783 : EmitUnary(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    6064                 : {
    6065                 :     /* Unary op, including unary +/-. */
    6066          531783 :     JSOp op = pn->getOp();
    6067          531783 :     ParseNode *pn2 = pn->pn_kid;
    6068                 : 
    6069          531783 :     JS_ASSERT(op != JSOP_XMLNAME);
    6070          531783 :     if (op == JSOP_TYPEOF && !pn2->isKind(PNK_NAME))
    6071               0 :         op = JSOP_TYPEOFEXPR;
    6072                 : 
    6073          531783 :     unsigned oldflags = bce->flags;
    6074          531783 :     bce->flags &= ~TCF_IN_FOR_INIT;
    6075          531783 :     if (!EmitTree(cx, bce, pn2))
    6076               0 :         return false;
    6077                 : 
    6078          531783 :     bce->flags |= oldflags & TCF_IN_FOR_INIT;
    6079          531783 :     return Emit1(cx, bce, op) >= 0;
    6080                 : }
    6081                 : 
    6082                 : JSBool
    6083        59282303 : frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
    6084                 : {
    6085        59282303 :     JS_CHECK_RECURSION(cx, return JS_FALSE);
    6086                 : 
    6087       118564606 :     EmitLevelManager elm(bce);
    6088                 : 
    6089        59282303 :     JSBool ok = true;
    6090        59282303 :     ptrdiff_t top = bce->offset();
    6091        59282303 :     pn->pn_offset = top;
    6092                 : 
    6093                 :     /* Emit notes to tell the current bytecode's source line number. */
    6094        59282303 :     UPDATE_LINE_NUMBER_NOTES(cx, bce, pn->pn_pos.begin.lineno);
    6095                 : 
    6096        59282303 :     switch (pn->getKind()) {
    6097                 :       case PNK_FUNCTION:
    6098         1019370 :         ok = EmitFunc(cx, bce, pn);
    6099         1019370 :         break;
    6100                 : 
    6101                 :       case PNK_ARGSBODY:
    6102                 :       {
    6103          646026 :         ParseNode *pnlast = pn->last();
    6104         1852199 :         for (ParseNode *pn2 = pn->pn_head; pn2 != pnlast; pn2 = pn2->pn_next) {
    6105         1206173 :             if (!pn2->isDefn())
    6106              18 :                 continue;
    6107         1206155 :             if (!BindNameToSlot(cx, bce, pn2))
    6108               0 :                 return JS_FALSE;
    6109         1206155 :             if (JOF_OPTYPE(pn2->getOp()) == JOF_QARG && bce->shouldNoteClosedName(pn2)) {
    6110          113998 :                 if (!bce->closedArgs.append(pn2->pn_cookie.slot()))
    6111               0 :                     return JS_FALSE;
    6112                 :             }
    6113                 :         }
    6114          646026 :         ok = EmitTree(cx, bce, pnlast);
    6115          646026 :         break;
    6116                 :       }
    6117                 : 
    6118                 :       case PNK_UPVARS:
    6119          811155 :         JS_ASSERT(pn->pn_names->count() != 0);
    6120          811155 :         bce->roLexdeps = pn->pn_names;
    6121          811155 :         ok = EmitTree(cx, bce, pn->pn_tree);
    6122          811155 :         bce->roLexdeps.clearMap();
    6123          811155 :         pn->pn_names.releaseMap(cx);
    6124          811155 :         break;
    6125                 : 
    6126                 :       case PNK_IF:
    6127          929543 :         ok = EmitIf(cx, bce, pn);
    6128          929543 :         break;
    6129                 : 
    6130                 :       case PNK_SWITCH:
    6131           17231 :         ok = EmitSwitch(cx, bce, pn);
    6132           17231 :         break;
    6133                 : 
    6134                 :       case PNK_WHILE:
    6135           51638 :         ok = EmitWhile(cx, bce, pn, top);
    6136           51638 :         break;
    6137                 : 
    6138                 :       case PNK_DOWHILE:
    6139             383 :         ok = EmitDo(cx, bce, pn);
    6140             383 :         break;
    6141                 : 
    6142                 :       case PNK_FOR:
    6143          122103 :         ok = EmitFor(cx, bce, pn, top);
    6144          122103 :         break;
    6145                 : 
    6146                 :       case PNK_BREAK:
    6147           53010 :         ok = EmitBreak(cx, bce, pn->asBreakStatement().label());
    6148           53010 :         break;
    6149                 : 
    6150                 :       case PNK_CONTINUE:
    6151           38621 :         ok = EmitContinue(cx, bce, pn->asContinueStatement().label());
    6152           38621 :         break;
    6153                 : 
    6154                 :       case PNK_WITH:
    6155             630 :         ok = EmitWith(cx, bce, pn);
    6156             630 :         break;
    6157                 : 
    6158                 :       case PNK_TRY:
    6159          241021 :         if (!EmitTry(cx, bce, pn))
    6160               0 :             return false;
    6161          241021 :         break;
    6162                 : 
    6163                 :       case PNK_CATCH:
    6164          225154 :         if (!EmitCatch(cx, bce, pn))
    6165               0 :             return false;
    6166          225154 :         break;
    6167                 : 
    6168                 :       case PNK_VAR:
    6169                 :       case PNK_CONST:
    6170         1024826 :         if (!EmitVariables(cx, bce, pn, InitializeVars))
    6171               0 :             return JS_FALSE;
    6172         1024826 :         break;
    6173                 : 
    6174                 :       case PNK_RETURN:
    6175          660086 :         ok = EmitReturn(cx, bce, pn);
    6176          660086 :         break;
    6177                 : 
    6178                 : #if JS_HAS_GENERATORS
    6179                 :       case PNK_YIELD:
    6180            4374 :         JS_ASSERT(bce->inFunction());
    6181            4374 :         if (pn->pn_kid) {
    6182            3593 :             if (!EmitTree(cx, bce, pn->pn_kid))
    6183               0 :                 return JS_FALSE;
    6184                 :         } else {
    6185             781 :             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
    6186               0 :                 return JS_FALSE;
    6187                 :         }
    6188            4374 :         if (pn->pn_hidden && NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
    6189               0 :             return JS_FALSE;
    6190            4374 :         if (Emit1(cx, bce, JSOP_YIELD) < 0)
    6191               0 :             return JS_FALSE;
    6192            4374 :         break;
    6193                 : #endif
    6194                 : 
    6195                 : #if JS_HAS_XML_SUPPORT
    6196                 :       case PNK_XMLCURLYEXPR:
    6197               0 :         JS_ASSERT(pn->isArity(PN_UNARY));
    6198               0 :         if (!EmitTree(cx, bce, pn->pn_kid))
    6199               0 :             return JS_FALSE;
    6200               0 :         if (Emit1(cx, bce, pn->getOp()) < 0)
    6201               0 :             return JS_FALSE;
    6202               0 :         break;
    6203                 : #endif
    6204                 : 
    6205                 :       case PNK_STATEMENTLIST:
    6206         2400798 :         ok = EmitStatementList(cx, bce, pn, top);
    6207         2400798 :         break;
    6208                 : 
    6209                 :       case PNK_SEQ:
    6210             934 :         ok = EmitSyntheticStatements(cx, bce, pn, top);
    6211             934 :         break;
    6212                 : 
    6213                 :       case PNK_SEMI:
    6214         6474702 :         ok = EmitStatement(cx, bce, pn);
    6215         6474702 :         break;
    6216                 : 
    6217                 :       case PNK_COLON:
    6218             193 :         ok = EmitLabel(cx, bce, pn);
    6219             193 :         break;
    6220                 : 
    6221                 :       case PNK_COMMA:
    6222                 :       {
    6223                 :         /*
    6224                 :          * Emit SRC_PCDELTA notes on each JSOP_POP between comma operands.
    6225                 :          * These notes help the decompiler bracket the bytecodes generated
    6226                 :          * from each sub-expression that follows a comma.
    6227                 :          */
    6228            2098 :         ptrdiff_t off = -1, noteIndex = -1;
    6229            4707 :         for (ParseNode *pn2 = pn->pn_head; ; pn2 = pn2->pn_next) {
    6230            4707 :             if (!EmitTree(cx, bce, pn2))
    6231               0 :                 return JS_FALSE;
    6232            4707 :             ptrdiff_t tmp = bce->offset();
    6233            4707 :             if (noteIndex >= 0) {
    6234            2609 :                 if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 0, tmp-off))
    6235               0 :                     return JS_FALSE;
    6236                 :             }
    6237            4707 :             if (!pn2->pn_next)
    6238                 :                 break;
    6239            2609 :             off = tmp;
    6240            2609 :             noteIndex = NewSrcNote2(cx, bce, SRC_PCDELTA, 0);
    6241            5218 :             if (noteIndex < 0 ||
    6242            2609 :                 Emit1(cx, bce, JSOP_POP) < 0) {
    6243               0 :                 return JS_FALSE;
    6244                 :             }
    6245                 :         }
    6246            2098 :         break;
    6247                 :       }
    6248                 : 
    6249                 :       case PNK_ASSIGN:
    6250                 :       case PNK_ADDASSIGN:
    6251                 :       case PNK_SUBASSIGN:
    6252                 :       case PNK_BITORASSIGN:
    6253                 :       case PNK_BITXORASSIGN:
    6254                 :       case PNK_BITANDASSIGN:
    6255                 :       case PNK_LSHASSIGN:
    6256                 :       case PNK_RSHASSIGN:
    6257                 :       case PNK_URSHASSIGN:
    6258                 :       case PNK_MULASSIGN:
    6259                 :       case PNK_DIVASSIGN:
    6260                 :       case PNK_MODASSIGN:
    6261         3018658 :         if (!EmitAssignment(cx, bce, pn->pn_left, pn->getOp(), pn->pn_right))
    6262               0 :             return false;
    6263         3018658 :         break;
    6264                 : 
    6265                 :       case PNK_CONDITIONAL:
    6266           68371 :         ok = EmitConditionalExpression(cx, bce, pn->asConditionalExpression());
    6267           68371 :         break;
    6268                 : 
    6269                 :       case PNK_OR:
    6270                 :       case PNK_AND:
    6271          229653 :         ok = EmitLogical(cx, bce, pn);
    6272          229653 :         break;
    6273                 : 
    6274                 :       case PNK_ADD:
    6275                 :       case PNK_SUB:
    6276                 :       case PNK_BITOR:
    6277                 :       case PNK_BITXOR:
    6278                 :       case PNK_BITAND:
    6279                 :       case PNK_STRICTEQ:
    6280                 :       case PNK_EQ:
    6281                 :       case PNK_STRICTNE:
    6282                 :       case PNK_NE:
    6283                 :       case PNK_LT:
    6284                 :       case PNK_LE:
    6285                 :       case PNK_GT:
    6286                 :       case PNK_GE:
    6287                 :       case PNK_IN:
    6288                 :       case PNK_INSTANCEOF:
    6289                 :       case PNK_LSH:
    6290                 :       case PNK_RSH:
    6291                 :       case PNK_URSH:
    6292                 :       case PNK_STAR:
    6293                 :       case PNK_DIV:
    6294                 :       case PNK_MOD:
    6295         1123155 :         if (pn->isArity(PN_LIST)) {
    6296                 :             /* Left-associative operator chain: avoid too much recursion. */
    6297          166353 :             ParseNode *pn2 = pn->pn_head;
    6298          166353 :             if (!EmitTree(cx, bce, pn2))
    6299               0 :                 return JS_FALSE;
    6300          166353 :             JSOp op = pn->getOp();
    6301          166353 :             while ((pn2 = pn2->pn_next) != NULL) {
    6302         2046292 :                 if (!EmitTree(cx, bce, pn2))
    6303               0 :                     return JS_FALSE;
    6304         2046292 :                 if (Emit1(cx, bce, op) < 0)
    6305               0 :                     return JS_FALSE;
    6306                 :             }
    6307                 :         } else {
    6308                 : #if JS_HAS_XML_SUPPORT
    6309                 :             unsigned oldflags;
    6310                 : 
    6311                 :       case PNK_DBLCOLON:
    6312          956874 :             JS_ASSERT(pn->getOp() != JSOP_XMLNAME);
    6313          956874 :             if (pn->isArity(PN_NAME)) {
    6314              72 :                 if (!EmitTree(cx, bce, pn->expr()))
    6315               0 :                     return JS_FALSE;
    6316              72 :                 if (!EmitAtomOp(cx, pn, pn->getOp(), bce))
    6317               0 :                     return JS_FALSE;
    6318              72 :                 break;
    6319                 :             }
    6320                 : 
    6321                 :             /*
    6322                 :              * Binary :: has a right operand that brackets arbitrary code,
    6323                 :              * possibly including a let (a = b) ... expression.  We must clear
    6324                 :              * TCF_IN_FOR_INIT to avoid mis-compiling such beasts.
    6325                 :              */
    6326          956802 :             oldflags = bce->flags;
    6327          956802 :             bce->flags &= ~TCF_IN_FOR_INIT;
    6328                 : #endif
    6329                 : 
    6330                 :             /* Binary operators that evaluate both operands unconditionally. */
    6331          956802 :             if (!EmitTree(cx, bce, pn->pn_left))
    6332               0 :                 return JS_FALSE;
    6333          956802 :             if (!EmitTree(cx, bce, pn->pn_right))
    6334               0 :                 return JS_FALSE;
    6335                 : #if JS_HAS_XML_SUPPORT
    6336          956802 :             bce->flags |= oldflags & TCF_IN_FOR_INIT;
    6337                 : #endif
    6338          956802 :             if (Emit1(cx, bce, pn->getOp()) < 0)
    6339               0 :                 return JS_FALSE;
    6340                 :         }
    6341         1123155 :         break;
    6342                 : 
    6343                 : #if JS_HAS_XML_SUPPORT
    6344                 :       case PNK_XMLUNARY:
    6345              54 :         if (pn->getOp() == JSOP_XMLNAME) {
    6346              54 :             if (!EmitXMLName(cx, pn, JSOP_XMLNAME, bce))
    6347               0 :                 return false;
    6348                 :         } else {
    6349               0 :             JSOp op = pn->getOp();
    6350               0 :             JS_ASSERT(op == JSOP_BINDXMLNAME || op == JSOP_SETXMLNAME);
    6351               0 :             unsigned oldflags = bce->flags;
    6352               0 :             bce->flags &= ~TCF_IN_FOR_INIT;
    6353               0 :             if (!EmitTree(cx, bce, pn->pn_kid))
    6354               0 :                 return false;
    6355               0 :             bce->flags |= oldflags & TCF_IN_FOR_INIT;
    6356               0 :             if (Emit1(cx, bce, op) < 0)
    6357               0 :                 return false;
    6358                 :         }
    6359              54 :         break;
    6360                 : #endif
    6361                 : 
    6362                 :       case PNK_THROW:
    6363                 : #if JS_HAS_XML_SUPPORT
    6364                 :       case PNK_AT:
    6365                 :       case PNK_DEFXMLNS:
    6366          123773 :         JS_ASSERT(pn->isArity(PN_UNARY));
    6367                 :         /* FALL THROUGH */
    6368                 : #endif
    6369                 :       case PNK_TYPEOF:
    6370                 :       case PNK_VOID:
    6371                 :       case PNK_NOT:
    6372                 :       case PNK_BITNOT:
    6373                 :       case PNK_POS:
    6374                 :       case PNK_NEG:
    6375          531783 :         ok = EmitUnary(cx, bce, pn);
    6376          531783 :         break;
    6377                 : 
    6378                 :       case PNK_PREINCREMENT:
    6379                 :       case PNK_PREDECREMENT:
    6380                 :       case PNK_POSTINCREMENT:
    6381                 :       case PNK_POSTDECREMENT:
    6382         1737187 :         ok = EmitIncOrDec(cx, bce, pn);
    6383         1737187 :         break;
    6384                 : 
    6385                 :       case PNK_DELETE:
    6386           37494 :         ok = EmitDelete(cx, bce, pn);
    6387           37494 :         break;
    6388                 : 
    6389                 : #if JS_HAS_XML_SUPPORT
    6390                 :       case PNK_FILTER:
    6391                 :       {
    6392              63 :         JS_ASSERT(!bce->inStrictMode());
    6393                 : 
    6394              63 :         if (!EmitTree(cx, bce, pn->pn_left))
    6395               0 :             return JS_FALSE;
    6396              63 :         ptrdiff_t jmp = EmitJump(cx, bce, JSOP_FILTER, 0);
    6397              63 :         if (jmp < 0)
    6398               0 :             return JS_FALSE;
    6399              63 :         top = EmitLoopHead(cx, bce, pn->pn_right);
    6400              63 :         if (top < 0)
    6401               0 :             return JS_FALSE;
    6402              63 :         if (!EmitTree(cx, bce, pn->pn_right))
    6403               0 :             return JS_FALSE;
    6404              63 :         SetJumpOffsetAt(bce, jmp);
    6405              63 :         if (!EmitLoopEntry(cx, bce, NULL))
    6406               0 :             return false;
    6407              63 :         if (EmitJump(cx, bce, JSOP_ENDFILTER, top - bce->offset()) < 0)
    6408               0 :             return JS_FALSE;
    6409              63 :         break;
    6410                 :       }
    6411                 : #endif
    6412                 : 
    6413                 :       case PNK_DOT:
    6414                 :         /*
    6415                 :          * Pop a stack operand, convert it to object, get a property named by
    6416                 :          * this bytecode's immediate-indexed atom operand, and push its value
    6417                 :          * (not a reference to it).
    6418                 :          */
    6419         5841557 :         ok = EmitPropOp(cx, pn, pn->getOp(), bce, JS_FALSE);
    6420         5841557 :         break;
    6421                 : 
    6422                 : #if JS_HAS_XML_SUPPORT
    6423                 :       case PNK_DBLDOT:
    6424               9 :         JS_ASSERT(!bce->inStrictMode());
    6425                 :         /* FALL THROUGH */
    6426                 : #endif
    6427                 :       case PNK_LB:
    6428                 :         /*
    6429                 :          * Pop two operands, convert the left one to object and the right one
    6430                 :          * to property name (atom or tagged int), get the named property, and
    6431                 :          * push its value.  Set the "obj" register to the result of ToObject
    6432                 :          * on the left operand.
    6433                 :          */
    6434          272637 :         ok = EmitElemOp(cx, pn, pn->getOp(), bce);
    6435          272637 :         break;
    6436                 : 
    6437                 :       case PNK_NEW:
    6438                 :       case PNK_LP:
    6439         3331826 :         ok = EmitCallOrNew(cx, bce, pn, top);
    6440         3331826 :         break;
    6441                 : 
    6442                 :       case PNK_LEXICALSCOPE:
    6443          366540 :         ok = EmitLexicalScope(cx, bce, pn);
    6444          366540 :         break;
    6445                 : 
    6446                 : #if JS_HAS_BLOCK_SCOPE
    6447                 :       case PNK_LET:
    6448          250177 :         ok = pn->isArity(PN_BINARY)
    6449           45212 :              ? EmitLet(cx, bce, pn)
    6450          295389 :              : EmitVariables(cx, bce, pn, InitializeVars);
    6451          250177 :         break;
    6452                 : #endif /* JS_HAS_BLOCK_SCOPE */
    6453                 : #if JS_HAS_GENERATORS
    6454                 :       case PNK_ARRAYPUSH: {
    6455                 :         int slot;
    6456                 : 
    6457                 :         /*
    6458                 :          * The array object's stack index is in bce->arrayCompDepth. See below
    6459                 :          * under the array initialiser code generator for array comprehension
    6460                 :          * special casing.
    6461                 :          */
    6462           12678 :         if (!EmitTree(cx, bce, pn->pn_kid))
    6463               0 :             return JS_FALSE;
    6464           12678 :         slot = AdjustBlockSlot(cx, bce, bce->arrayCompDepth);
    6465           12678 :         if (slot < 0)
    6466               0 :             return JS_FALSE;
    6467           12678 :         EMIT_UINT16_IMM_OP(pn->getOp(), slot);
    6468           12678 :         break;
    6469                 :       }
    6470                 : #endif
    6471                 : 
    6472                 :       case PNK_RB:
    6473                 : #if JS_HAS_GENERATORS
    6474                 :       case PNK_ARRAYCOMP:
    6475                 : #endif
    6476          224358 :         ok = EmitArray(cx, bce, pn);
    6477          224358 :         break;
    6478                 : 
    6479                 :       case PNK_RC:
    6480          216320 :         ok = EmitObject(cx, bce, pn);
    6481          216320 :         break;
    6482                 : 
    6483                 :       case PNK_NAME:
    6484                 :         /*
    6485                 :          * Cope with a left-over function definition that was replaced by a use
    6486                 :          * of a later function definition of the same name. See FunctionDef and
    6487                 :          * MakeDefIntoUse in Parser.cpp.
    6488                 :          */
    6489        12079812 :         if (pn->isOp(JSOP_NOP))
    6490               0 :             break;
    6491        12079812 :         if (!EmitNameOp(cx, bce, pn, JS_FALSE))
    6492               0 :             return JS_FALSE;
    6493        12079812 :         break;
    6494                 : 
    6495                 : #if JS_HAS_XML_SUPPORT
    6496                 :       case PNK_XMLATTR:
    6497                 :       case PNK_XMLSPACE:
    6498                 :       case PNK_XMLTEXT:
    6499                 :       case PNK_XMLCDATA:
    6500                 :       case PNK_XMLCOMMENT:
    6501             335 :         JS_ASSERT(!bce->inStrictMode());
    6502                 :         /* FALL THROUGH */
    6503                 : #endif
    6504                 :       case PNK_STRING:
    6505         6904205 :         ok = EmitAtomOp(cx, pn, pn->getOp(), bce);
    6506         6904205 :         break;
    6507                 : 
    6508                 :       case PNK_NUMBER:
    6509         5885932 :         ok = EmitNumberOp(cx, pn->pn_dval, bce);
    6510         5885932 :         break;
    6511                 : 
    6512                 :       case PNK_REGEXP:
    6513           34050 :         JS_ASSERT(pn->isOp(JSOP_REGEXP));
    6514           34050 :         ok = EmitRegExp(cx, bce->regexpList.index(pn->pn_objbox), bce);
    6515           34050 :         break;
    6516                 : 
    6517                 : #if JS_HAS_XML_SUPPORT
    6518                 :       case PNK_ANYNAME:
    6519                 : #endif
    6520                 :       case PNK_TRUE:
    6521                 :       case PNK_FALSE:
    6522                 :       case PNK_THIS:
    6523                 :       case PNK_NULL:
    6524         2387048 :         if (Emit1(cx, bce, pn->getOp()) < 0)
    6525               0 :             return JS_FALSE;
    6526         2387048 :         break;
    6527                 : 
    6528                 :       case PNK_DEBUGGER:
    6529            4397 :         if (Emit1(cx, bce, JSOP_DEBUGGER) < 0)
    6530               0 :             return JS_FALSE;
    6531            4397 :         break;
    6532                 : 
    6533                 : #if JS_HAS_XML_SUPPORT
    6534                 :       case PNK_XMLELEM:
    6535                 :       case PNK_XMLLIST:
    6536             308 :         JS_ASSERT(!bce->inStrictMode());
    6537             308 :         JS_ASSERT(pn->isKind(PNK_XMLLIST) || pn->pn_count != 0);
    6538                 : 
    6539             308 :         switch (pn->pn_head ? pn->pn_head->getKind() : PNK_XMLLIST) {
    6540                 :           case PNK_XMLETAGO:
    6541               0 :             JS_ASSERT(0);
    6542                 :             /* FALL THROUGH */
    6543                 :           case PNK_XMLPTAGC:
    6544                 :           case PNK_XMLSTAGO:
    6545               9 :             break;
    6546                 :           default:
    6547             299 :             if (Emit1(cx, bce, JSOP_STARTXML) < 0)
    6548               0 :                 return JS_FALSE;
    6549                 :         }
    6550                 : 
    6551             634 :         for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    6552             326 :             if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
    6553               0 :                 return JS_FALSE;
    6554             326 :             if (!EmitTree(cx, bce, pn2))
    6555               0 :                 return JS_FALSE;
    6556             326 :             if (pn2 != pn->pn_head && Emit1(cx, bce, JSOP_ADD) < 0)
    6557               0 :                 return JS_FALSE;
    6558                 :         }
    6559                 : 
    6560             308 :         if (pn->pn_xflags & PNX_XMLROOT) {
    6561             308 :             if (pn->pn_count == 0) {
    6562               0 :                 JS_ASSERT(pn->isKind(PNK_XMLLIST));
    6563               0 :                 JSAtom *atom = cx->runtime->atomState.emptyAtom;
    6564                 :                 jsatomid index;
    6565               0 :                 if (!bce->makeAtomIndex(atom, &index))
    6566               0 :                     return JS_FALSE;
    6567               0 :                 if (!EmitIndex32(cx, JSOP_STRING, index, bce))
    6568               0 :                     return false;
    6569                 :             }
    6570             308 :             if (Emit1(cx, bce, pn->getOp()) < 0)
    6571               0 :                 return JS_FALSE;
    6572                 :         }
    6573                 : #ifdef DEBUG
    6574                 :         else
    6575               0 :             JS_ASSERT(pn->pn_count != 0);
    6576                 : #endif
    6577             308 :         break;
    6578                 : 
    6579                 :       case PNK_XMLPTAGC:
    6580                 :       case PNK_XMLSTAGO:
    6581                 :       case PNK_XMLETAGO:
    6582              36 :         if (!EmitXMLTag(cx, bce, pn))
    6583               0 :             return false;
    6584              36 :         break;
    6585                 : 
    6586                 :       case PNK_XMLNAME:
    6587              36 :         JS_ASSERT(!bce->inStrictMode());
    6588                 : 
    6589              36 :         if (pn->isArity(PN_LIST)) {
    6590               0 :             JS_ASSERT(pn->pn_count != 0);
    6591               0 :             for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
    6592               0 :                 if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
    6593               0 :                     return JS_FALSE;
    6594               0 :                 if (!EmitTree(cx, bce, pn2))
    6595               0 :                     return JS_FALSE;
    6596               0 :                 if (pn2 != pn->pn_head && Emit1(cx, bce, JSOP_ADD) < 0)
    6597               0 :                     return JS_FALSE;
    6598                 :             }
    6599                 :         } else {
    6600              36 :             JS_ASSERT(pn->isArity(PN_NULLARY));
    6601              36 :             ok = pn->isOp(JSOP_OBJECT)
    6602               0 :                  ? EmitObjectOp(cx, pn->pn_objbox, pn->getOp(), bce)
    6603              36 :                  : EmitAtomOp(cx, pn, pn->getOp(), bce);
    6604                 :         }
    6605              36 :         break;
    6606                 : 
    6607                 :       case PNK_XMLPI:
    6608               0 :         if (!EmitXMLProcessingInstruction(cx, bce, pn->asXMLProcessingInstruction()))
    6609               0 :             return false;
    6610               0 :         break;
    6611                 : #endif /* JS_HAS_XML_SUPPORT */
    6612                 : 
    6613                 :       default:
    6614               0 :         JS_ASSERT(0);
    6615                 :     }
    6616                 : 
    6617                 :     /* bce->emitLevel == 1 means we're last on the stack, so finish up. */
    6618        59282303 :     if (ok && bce->emitLevel == 1) {
    6619         1879816 :         if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.end.lineno))
    6620               0 :             return JS_FALSE;
    6621                 :     }
    6622                 : 
    6623        59282303 :     return ok;
    6624                 : }
    6625                 : 
    6626                 : static int
    6627        69519530 : AllocSrcNote(JSContext *cx, BytecodeEmitter *bce)
    6628                 : {
    6629        69519530 :     jssrcnote *notes = bce->notes();
    6630                 :     jssrcnote *newnotes;
    6631        69519530 :     unsigned index = bce->noteCount();
    6632        69519530 :     unsigned max = bce->noteLimit();
    6633                 : 
    6634        69519530 :     if (index == max) {
    6635                 :         size_t newlength;
    6636         1046757 :         if (!notes) {
    6637         1036649 :             JS_ASSERT(!index && !max);
    6638         1036649 :             newlength = SRCNOTE_CHUNK_LENGTH;
    6639         1036649 :             newnotes = (jssrcnote *) cx->malloc_(SRCNOTE_SIZE(newlength));
    6640                 :         } else {
    6641           10108 :             JS_ASSERT(index <= max);
    6642           10108 :             newlength = max * 2;
    6643           10108 :             newnotes = (jssrcnote *) cx->realloc_(notes, SRCNOTE_SIZE(newlength));
    6644                 :         }
    6645         1046757 :         if (!newnotes) {
    6646               0 :             js_ReportOutOfMemory(cx);
    6647               0 :             return -1;
    6648                 :         }
    6649         1046757 :         bce->current->notes = newnotes;
    6650         1046757 :         bce->current->noteLimit = newlength;
    6651                 :     }
    6652                 : 
    6653        69519530 :     bce->current->noteCount = index + 1;
    6654        69519530 :     return (int)index;
    6655                 : }
    6656                 : 
    6657                 : int
    6658        58132804 : frontend::NewSrcNote(JSContext *cx, BytecodeEmitter *bce, SrcNoteType type)
    6659                 : {
    6660                 :     int index, n;
    6661                 :     jssrcnote *sn;
    6662                 :     ptrdiff_t offset, delta, xdelta;
    6663                 : 
    6664                 :     /*
    6665                 :      * Claim a note slot in bce->notes() by growing it if necessary and then
    6666                 :      * incrementing bce->noteCount().
    6667                 :      */
    6668        58132804 :     index = AllocSrcNote(cx, bce);
    6669        58132804 :     if (index < 0)
    6670               0 :         return -1;
    6671        58132804 :     sn = &bce->notes()[index];
    6672                 : 
    6673                 :     /*
    6674                 :      * Compute delta from the last annotated bytecode's offset.  If it's too
    6675                 :      * big to fit in sn, allocate one or more xdelta notes and reset sn.
    6676                 :      */
    6677        58132804 :     offset = bce->offset();
    6678        58132804 :     delta = offset - bce->lastNoteOffset();
    6679        58132804 :     bce->current->lastNoteOffset = offset;
    6680        58132804 :     if (delta >= SN_DELTA_LIMIT) {
    6681        11386726 :         do {
    6682        11386726 :             xdelta = JS_MIN(delta, SN_XDELTA_MASK);
    6683        11386726 :             SN_MAKE_XDELTA(sn, xdelta);
    6684        11386726 :             delta -= xdelta;
    6685        11386726 :             index = AllocSrcNote(cx, bce);
    6686        11386726 :             if (index < 0)
    6687               0 :                 return -1;
    6688        11386726 :             sn = &bce->notes()[index];
    6689                 :         } while (delta >= SN_DELTA_LIMIT);
    6690                 :     }
    6691                 : 
    6692                 :     /*
    6693                 :      * Initialize type and delta, then allocate the minimum number of notes
    6694                 :      * needed for type's arity.  Usually, we won't need more, but if an offset
    6695                 :      * does take two bytes, SetSrcNoteOffset will grow bce->notes().
    6696                 :      */
    6697        58132804 :     SN_MAKE_NOTE(sn, type, delta);
    6698        80147428 :     for (n = (int)js_SrcNoteSpec[type].arity; n > 0; n--) {
    6699        22014624 :         if (NewSrcNote(cx, bce, SRC_NULL) < 0)
    6700               0 :             return -1;
    6701                 :     }
    6702        58132804 :     return index;
    6703                 : }
    6704                 : 
    6705                 : int
    6706        21096554 : frontend::NewSrcNote2(JSContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset)
    6707                 : {
    6708                 :     int index;
    6709                 : 
    6710        21096554 :     index = NewSrcNote(cx, bce, type);
    6711        21096554 :     if (index >= 0) {
    6712        21096554 :         if (!SetSrcNoteOffset(cx, bce, index, 0, offset))
    6713               0 :             return -1;
    6714                 :     }
    6715        21096554 :     return index;
    6716                 : }
    6717                 : 
    6718                 : int
    6719           17231 : frontend::NewSrcNote3(JSContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset1,
    6720                 :             ptrdiff_t offset2)
    6721                 : {
    6722                 :     int index;
    6723                 : 
    6724           17231 :     index = NewSrcNote(cx, bce, type);
    6725           17231 :     if (index >= 0) {
    6726           17231 :         if (!SetSrcNoteOffset(cx, bce, index, 0, offset1))
    6727               0 :             return -1;
    6728           17231 :         if (!SetSrcNoteOffset(cx, bce, index, 1, offset2))
    6729               0 :             return -1;
    6730                 :     }
    6731           17231 :     return index;
    6732                 : }
    6733                 : 
    6734                 : static JSBool
    6735              35 : GrowSrcNotes(JSContext *cx, BytecodeEmitter *bce)
    6736                 : {
    6737              35 :     size_t newlength = bce->noteLimit() * 2;
    6738              35 :     jssrcnote *newnotes = (jssrcnote *) cx->realloc_(bce->notes(), newlength);
    6739              35 :     if (!newnotes) {
    6740               0 :         js_ReportOutOfMemory(cx);
    6741               0 :         return JS_FALSE;
    6742                 :     }
    6743              35 :     bce->current->notes = newnotes;
    6744              35 :     bce->current->noteLimit = newlength;
    6745              35 :     return JS_TRUE;
    6746                 : }
    6747                 : 
    6748                 : jssrcnote *
    6749           61243 : frontend::AddToSrcNoteDelta(JSContext *cx, BytecodeEmitter *bce, jssrcnote *sn, ptrdiff_t delta)
    6750                 : {
    6751                 :     ptrdiff_t base, limit, newdelta, diff;
    6752                 :     int index;
    6753                 : 
    6754                 :     /*
    6755                 :      * Called only from OptimizeSpanDeps and FinishTakingSrcNotes to add to
    6756                 :      * main script note deltas, and only by a small positive amount.
    6757                 :      */
    6758           61243 :     JS_ASSERT(bce->current == &bce->main);
    6759           61243 :     JS_ASSERT((unsigned) delta < (unsigned) SN_XDELTA_LIMIT);
    6760                 : 
    6761           61243 :     base = SN_DELTA(sn);
    6762           61243 :     limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
    6763           61243 :     newdelta = base + delta;
    6764           61243 :     if (newdelta < limit) {
    6765           34086 :         SN_SET_DELTA(sn, newdelta);
    6766                 :     } else {
    6767           27157 :         index = sn - bce->main.notes;
    6768           27157 :         if (bce->main.noteCount == bce->main.noteLimit) {
    6769               0 :             if (!GrowSrcNotes(cx, bce))
    6770               0 :                 return NULL;
    6771               0 :             sn = bce->main.notes + index;
    6772                 :         }
    6773           27157 :         diff = bce->main.noteCount - index;
    6774           27157 :         bce->main.noteCount++;
    6775           27157 :         memmove(sn + 1, sn, SRCNOTE_SIZE(diff));
    6776           27157 :         SN_MAKE_XDELTA(sn, delta);
    6777           27157 :         sn++;
    6778                 :     }
    6779           61243 :     return sn;
    6780                 : }
    6781                 : 
    6782                 : static JSBool
    6783        22046442 : SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, unsigned index, unsigned which, ptrdiff_t offset)
    6784                 : {
    6785                 :     jssrcnote *sn;
    6786                 :     ptrdiff_t diff;
    6787                 : 
    6788        22046442 :     if (size_t(offset) > SN_MAX_OFFSET) {
    6789               0 :         ReportStatementTooLarge(cx, bce);
    6790               0 :         return JS_FALSE;
    6791                 :     }
    6792                 : 
    6793                 :     /* Find the offset numbered which (i.e., skip exactly which offsets). */
    6794        22046442 :     sn = &bce->notes()[index];
    6795        22046442 :     JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
    6796        22046442 :     JS_ASSERT((int) which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
    6797        22347540 :     for (sn++; which; sn++, which--) {
    6798          301098 :         if (*sn & SN_3BYTE_OFFSET_FLAG)
    6799           51713 :             sn += 2;
    6800                 :     }
    6801                 : 
    6802                 :     /*
    6803                 :      * See if the new offset requires three bytes either by being too big or if
    6804                 :      * the offset has already been inflated (in which case, we need to stay big
    6805                 :      * to not break the srcnote encoding if this isn't the last srcnote).
    6806                 :      */
    6807        22046442 :     if (offset > (ptrdiff_t)SN_3BYTE_OFFSET_MASK || (*sn & SN_3BYTE_OFFSET_FLAG)) {
    6808                 :         /* Maybe this offset was already set to a three-byte value. */
    6809         1664556 :         if (!(*sn & SN_3BYTE_OFFSET_FLAG)) {
    6810                 :             /* Losing, need to insert another two bytes for this offset. */
    6811         1660398 :             index = sn - bce->notes();
    6812                 : 
    6813                 :             /*
    6814                 :              * Test to see if the source note array must grow to accommodate
    6815                 :              * either the first or second byte of additional storage required
    6816                 :              * by this 3-byte offset.
    6817                 :              */
    6818         1660398 :             if (bce->noteCount() + 1 >= bce->noteLimit()) {
    6819              35 :                 if (!GrowSrcNotes(cx, bce))
    6820               0 :                     return JS_FALSE;
    6821              35 :                 sn = bce->notes() + index;
    6822                 :             }
    6823         1660398 :             bce->current->noteCount += 2;
    6824                 : 
    6825         1660398 :             diff = bce->noteCount() - (index + 3);
    6826         1660398 :             JS_ASSERT(diff >= 0);
    6827         1660398 :             if (diff > 0)
    6828          190470 :                 memmove(sn + 3, sn + 1, SRCNOTE_SIZE(diff));
    6829                 :         }
    6830         1664556 :         *sn++ = (jssrcnote)(SN_3BYTE_OFFSET_FLAG | (offset >> 16));
    6831         1664556 :         *sn++ = (jssrcnote)(offset >> 8);
    6832                 :     }
    6833        22046442 :     *sn = (jssrcnote)offset;
    6834        22046442 :     return JS_TRUE;
    6835                 : }
    6836                 : 
    6837                 : #ifdef DEBUG_notme
    6838                 : #define DEBUG_srcnotesize
    6839                 : #endif
    6840                 : 
    6841                 : #ifdef DEBUG_srcnotesize
    6842                 : #define NBINS 10
    6843                 : static uint32_t hist[NBINS];
    6844                 : 
    6845                 : static void
    6846                 : DumpSrcNoteSizeHist()
    6847                 : {
    6848                 :     static FILE *fp;
    6849                 :     int i, n;
    6850                 : 
    6851                 :     if (!fp) {
    6852                 :         fp = fopen("/tmp/srcnotes.hist", "w");
    6853                 :         if (!fp)
    6854                 :             return;
    6855                 :         setvbuf(fp, NULL, _IONBF, 0);
    6856                 :     }
    6857                 :     fprintf(fp, "SrcNote size histogram:\n");
    6858                 :     for (i = 0; i < NBINS; i++) {
    6859                 :         fprintf(fp, "%4u %4u ", JS_BIT(i), hist[i]);
    6860                 :         for (n = (int) JS_HOWMANY(hist[i], 10); n > 0; --n)
    6861                 :             fputc('*', fp);
    6862                 :         fputc('\n', fp);
    6863                 :     }
    6864                 :     fputc('\n', fp);
    6865                 : }
    6866                 : #endif
    6867                 : 
    6868                 : /*
    6869                 :  * Fill in the storage at notes with prolog and main srcnotes; the space at
    6870                 :  * notes was allocated using the BytecodeEmitter::countFinalSourceNotes()
    6871                 :  * method from BytecodeEmitter.h. SO DON'T CHANGE THIS FUNCTION WITHOUT AT
    6872                 :  * LEAST CHECKING WHETHER BytecodeEmitter::countFinalSourceNotes() NEEDS
    6873                 :  * CORRESPONDING CHANGES!
    6874                 :  */
    6875                 : JSBool
    6876         1109121 : frontend::FinishTakingSrcNotes(JSContext *cx, BytecodeEmitter *bce, jssrcnote *notes)
    6877                 : {
    6878                 :     unsigned prologCount, mainCount, totalCount;
    6879                 :     ptrdiff_t offset, delta;
    6880                 :     jssrcnote *sn;
    6881                 : 
    6882         1109121 :     JS_ASSERT(bce->current == &bce->main);
    6883                 : 
    6884         1109121 :     prologCount = bce->prolog.noteCount;
    6885         1109121 :     if (prologCount && bce->prolog.currentLine != bce->firstLine) {
    6886           17407 :         bce->switchToProlog();
    6887           17407 :         if (NewSrcNote2(cx, bce, SRC_SETLINE, (ptrdiff_t)bce->firstLine) < 0)
    6888               0 :             return false;
    6889           17407 :         prologCount = bce->prolog.noteCount;
    6890           17407 :         bce->switchToMain();
    6891                 :     } else {
    6892                 :         /*
    6893                 :          * Either no prolog srcnotes, or no line number change over prolog.
    6894                 :          * We don't need a SRC_SETLINE, but we may need to adjust the offset
    6895                 :          * of the first main note, by adding to its delta and possibly even
    6896                 :          * prepending SRC_XDELTA notes to it to account for prolog bytecodes
    6897                 :          * that came at and after the last annotated bytecode.
    6898                 :          */
    6899         1091714 :         offset = bce->prologOffset() - bce->prolog.lastNoteOffset;
    6900         1091714 :         JS_ASSERT(offset >= 0);
    6901         1091714 :         if (offset > 0 && bce->main.noteCount != 0) {
    6902                 :             /* NB: Use as much of the first main note's delta as we can. */
    6903           34086 :             sn = bce->main.notes;
    6904                 :             delta = SN_IS_XDELTA(sn)
    6905                 :                     ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK)
    6906           34086 :                     : SN_DELTA_MASK - (*sn & SN_DELTA_MASK);
    6907           34086 :             if (offset < delta)
    6908            6911 :                 delta = offset;
    6909           27157 :             for (;;) {
    6910           61243 :                 if (!AddToSrcNoteDelta(cx, bce, sn, delta))
    6911               0 :                     return false;
    6912           61243 :                 offset -= delta;
    6913           61243 :                 if (offset == 0)
    6914                 :                     break;
    6915           27157 :                 delta = JS_MIN(offset, SN_XDELTA_MASK);
    6916           27157 :                 sn = bce->main.notes;
    6917                 :             }
    6918                 :         }
    6919                 :     }
    6920                 : 
    6921         1109121 :     mainCount = bce->main.noteCount;
    6922         1109121 :     totalCount = prologCount + mainCount;
    6923         1109121 :     if (prologCount)
    6924           17407 :         PodCopy(notes, bce->prolog.notes, prologCount);
    6925         1109121 :     PodCopy(notes + prologCount, bce->main.notes, mainCount);
    6926         1109121 :     SN_MAKE_TERMINATOR(&notes[totalCount]);
    6927                 : 
    6928         1109121 :     return true;
    6929                 : }
    6930                 : 
    6931                 : static JSBool
    6932          301592 : NewTryNote(JSContext *cx, BytecodeEmitter *bce, JSTryNoteKind kind, unsigned stackDepth, size_t start,
    6933                 :            size_t end)
    6934                 : {
    6935          301592 :     JS_ASSERT((unsigned)(uint16_t)stackDepth == stackDepth);
    6936          301592 :     JS_ASSERT(start <= end);
    6937                 :     JS_ASSERT((size_t)(uint32_t)start == start);
    6938                 :     JS_ASSERT((size_t)(uint32_t)end == end);
    6939                 : 
    6940          301592 :     TryNode *tryNode = cx->tempLifoAlloc().new_<TryNode>();
    6941          301592 :     if (!tryNode) {
    6942               0 :         js_ReportOutOfMemory(cx);
    6943               0 :         return JS_FALSE;
    6944                 :     }
    6945                 : 
    6946          301592 :     tryNode->note.kind = kind;
    6947          301592 :     tryNode->note.stackDepth = (uint16_t)stackDepth;
    6948          301592 :     tryNode->note.start = (uint32_t)start;
    6949          301592 :     tryNode->note.length = (uint32_t)(end - start);
    6950          301592 :     tryNode->prev = bce->lastTryNode;
    6951          301592 :     bce->lastTryNode = tryNode;
    6952          301592 :     bce->ntrynotes++;
    6953          301592 :     return JS_TRUE;
    6954                 : }
    6955                 : 
    6956                 : void
    6957          141944 : frontend::FinishTakingTryNotes(BytecodeEmitter *bce, JSTryNoteArray *array)
    6958                 : {
    6959                 :     TryNode *tryNode;
    6960                 :     JSTryNote *tn;
    6961                 : 
    6962          141944 :     JS_ASSERT(array->length > 0 && array->length == bce->ntrynotes);
    6963          141944 :     tn = array->vector + array->length;
    6964          141944 :     tryNode = bce->lastTryNode;
    6965          301583 :     do {
    6966          301583 :         *--tn = tryNode->note;
    6967                 :     } while ((tryNode = tryNode->prev) != NULL);
    6968          141944 :     JS_ASSERT(tn == array->vector);
    6969          141944 : }
    6970                 : 
    6971                 : /*
    6972                 :  * Find the index of the given object for code generator.
    6973                 :  *
    6974                 :  * Since the emitter refers to each parsed object only once, for the index we
    6975                 :  * use the number of already indexes objects. We also add the object to a list
    6976                 :  * to convert the list to a fixed-size array when we complete code generation,
    6977                 :  * see js::CGObjectList::finish below.
    6978                 :  *
    6979                 :  * Most of the objects go to BytecodeEmitter::objectList but for regexp we use
    6980                 :  * a separated BytecodeEmitter::regexpList. In this way the emitted index can
    6981                 :  * be directly used to store and fetch a reference to a cloned RegExp object
    6982                 :  * that shares the same JSRegExp private data created for the object literal in
    6983                 :  * objbox. We need a cloned object to hold lastIndex and other direct
    6984                 :  * properties that should not be shared among threads sharing a precompiled
    6985                 :  * function or script.
    6986                 :  *
    6987                 :  * If the code being compiled is function code, allocate a reserved slot in
    6988                 :  * the cloned function object that shares its precompiled script with other
    6989                 :  * cloned function objects and with the compiler-created clone-parent. There
    6990                 :  * are nregexps = script->regexps()->length such reserved slots in each
    6991                 :  * function object cloned from fun->object. NB: during compilation, a funobj
    6992                 :  * slots element must never be allocated, because JSObject::allocSlot could
    6993                 :  * hand out one of the slots that should be given to a regexp clone.
    6994                 :  *
    6995                 :  * If the code being compiled is global code, the cloned regexp are stored in
    6996                 :  * fp->vars slot and to protect regexp slots from GC we set fp->nvars to
    6997                 :  * nregexps.
    6998                 :  *
    6999                 :  * The slots initially contain undefined or null. We populate them lazily when
    7000                 :  * JSOP_REGEXP is executed for the first time.
    7001                 :  *
    7002                 :  * Why clone regexp objects?  ECMA specifies that when a regular expression
    7003                 :  * literal is scanned, a RegExp object is created.  In the spec, compilation
    7004                 :  * and execution happen indivisibly, but in this implementation and many of
    7005                 :  * its embeddings, code is precompiled early and re-executed in multiple
    7006                 :  * threads, or using multiple global objects, or both, for efficiency.
    7007                 :  *
    7008                 :  * In such cases, naively following ECMA leads to wrongful sharing of RegExp
    7009                 :  * objects, which makes for collisions on the lastIndex property (especially
    7010                 :  * for global regexps) and on any ad-hoc properties.  Also, __proto__ refers to
    7011                 :  * the pre-compilation prototype, a pigeon-hole problem for instanceof tests.
    7012                 :  */
    7013                 : unsigned
    7014         1475466 : CGObjectList::index(ObjectBox *objbox)
    7015                 : {
    7016         1475466 :     JS_ASSERT(!objbox->emitLink);
    7017         1475466 :     objbox->emitLink = lastbox;
    7018         1475466 :     lastbox = objbox;
    7019         1475466 :     return length++;
    7020                 : }
    7021                 : 
    7022                 : void
    7023          402694 : CGObjectList::finish(JSObjectArray *array)
    7024                 : {
    7025          402694 :     JS_ASSERT(length <= INDEX_LIMIT);
    7026          402694 :     JS_ASSERT(length == array->length);
    7027                 : 
    7028          402694 :     js::HeapPtrObject *cursor = array->vector + array->length;
    7029          402694 :     ObjectBox *objbox = lastbox;
    7030         1496534 :     do {
    7031         1496534 :         --cursor;
    7032         1496534 :         JS_ASSERT(!*cursor);
    7033         1496534 :         *cursor = objbox->object;
    7034                 :     } while ((objbox = objbox->emitLink) != NULL);
    7035          402694 :     JS_ASSERT(cursor == array->vector);
    7036          402694 : }
    7037                 : 
    7038                 : void
    7039           12798 : GCConstList::finish(JSConstArray *array)
    7040                 : {
    7041           12798 :     JS_ASSERT(array->length == list.length());
    7042           12798 :     Value *src = list.begin(), *srcend = list.end();
    7043           12798 :     HeapValue *dst = array->vector;
    7044           68100 :     for (; src != srcend; ++src, ++dst)
    7045           55302 :         *dst = *src;
    7046           12798 : }
    7047                 : 
    7048                 : /*
    7049                 :  * We should try to get rid of offsetBias (always 0 or 1, where 1 is
    7050                 :  * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL.
    7051                 :  */
    7052                 : JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
    7053                 :     {"null",            0},
    7054                 :     {"if",              0},
    7055                 :     {"if-else",         2},
    7056                 :     {"for",             3},
    7057                 :     {"while",           1},
    7058                 :     {"continue",        0},
    7059                 :     {"decl",            1},
    7060                 :     {"pcdelta",         1},
    7061                 :     {"assignop",        0},
    7062                 :     {"cond",            1},
    7063                 :     {"brace",           1},
    7064                 :     {"hidden",          0},
    7065                 :     {"pcbase",          1},
    7066                 :     {"label",           1},
    7067                 :     {"labelbrace",      1},
    7068                 :     {"endbrace",        0},
    7069                 :     {"break2label",     1},
    7070                 :     {"cont2label",      1},
    7071                 :     {"switch",          2},
    7072                 :     {"funcdef",         1},
    7073                 :     {"catch",           1},
    7074                 :     {"unused",         -1},
    7075                 :     {"newline",         0},
    7076                 :     {"setline",         1},
    7077                 :     {"xdelta",          0},
    7078                 : };
    7079                 : 
    7080                 : JS_FRIEND_API(unsigned)
    7081       138829626 : js_SrcNoteLength(jssrcnote *sn)
    7082                 : {
    7083                 :     unsigned arity;
    7084                 :     jssrcnote *base;
    7085                 : 
    7086       138829626 :     arity = (int)js_SrcNoteSpec[SN_TYPE(sn)].arity;
    7087       281625785 :     for (base = sn++; arity; sn++, arity--) {
    7088       142796159 :         if (*sn & SN_3BYTE_OFFSET_FLAG)
    7089         6319703 :             sn += 2;
    7090                 :     }
    7091       138829626 :     return sn - base;
    7092                 : }
    7093                 : 
    7094                 : JS_FRIEND_API(ptrdiff_t)
    7095         4777950 : js_GetSrcNoteOffset(jssrcnote *sn, unsigned which)
    7096                 : {
    7097                 :     /* Find the offset numbered which (i.e., skip exactly which offsets). */
    7098         4777950 :     JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
    7099         4777950 :     JS_ASSERT((int) which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
    7100         4782153 :     for (sn++; which; sn++, which--) {
    7101            4203 :         if (*sn & SN_3BYTE_OFFSET_FLAG)
    7102               9 :             sn += 2;
    7103                 :     }
    7104         4777950 :     if (*sn & SN_3BYTE_OFFSET_FLAG) {
    7105         1757284 :         return (ptrdiff_t)(((uint32_t)(sn[0] & SN_3BYTE_OFFSET_MASK) << 16)
    7106         1757284 :                            | (sn[1] << 8)
    7107         3514568 :                            | sn[2]);
    7108                 :     }
    7109         3020666 :     return (ptrdiff_t)*sn;
    7110                 : }

Generated by: LCOV version 1.7