LCOV - app.info - js/src/frontend/BytecodeEmitter.cpp

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

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

Generated by: LCOV version 1.7