Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsemit.cpp
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 #include "jstypes.h"
50 #include "jsstdint.h"
51 #include "jsarena.h"
52 #include "jsutil.h"
53 #include "jsbit.h"
54 #include "jsprf.h"
55 #include "jsapi.h"
56 #include "jsatom.h"
57 #include "jsbool.h"
58 #include "jscntxt.h"
59 #include "jsversion.h"
60 #include "jsemit.h"
61 #include "jsfun.h"
62 #include "jsnum.h"
63 #include "jsopcode.h"
64 #include "jsparse.h"
65 #include "jsregexp.h"
66 #include "jsscan.h"
67 #include "jsscope.h"
68 #include "jsscript.h"
69 #include "jsautooplen.h"        // generated headers last
70 #include "jsstaticcheck.h"
71
72 #include "jsatominlines.h"
73 #include "jsobjinlines.h"
74 #include "jsscopeinlines.h"
75 #include "jsscriptinlines.h"
76
77 /* Allocation chunk counts, must be powers of two in general. */
78 #define BYTECODE_CHUNK  256     /* code allocation increment */
79 #define SRCNOTE_CHUNK   64      /* initial srcnote allocation increment */
80 #define TRYNOTE_CHUNK   64      /* trynote allocation increment */
81
82 /* Macros to compute byte sizes from typed element counts. */
83 #define BYTECODE_SIZE(n)        ((n) * sizeof(jsbytecode))
84 #define SRCNOTE_SIZE(n)         ((n) * sizeof(jssrcnote))
85 #define TRYNOTE_SIZE(n)         ((n) * sizeof(JSTryNote))
86
87 using namespace js;
88 using namespace js::gc;
89
90 static JSBool
91 NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind,
92            uintN stackDepth, size_t start, size_t end);
93
94 static JSBool
95 EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg);
96
97 static JSBool
98 EmitLeaveBlock(JSContext *cx, JSCodeGenerator *cg, JSOp op, JSObjectBox *box);
99
100 void
101 JSTreeContext::trace(JSTracer *trc)
102 {
103     bindings.trace(trc);
104 }
105
106 JSCodeGenerator::JSCodeGenerator(Parser *parser,
107                                  JSArenaPool *cpool, JSArenaPool *npool,
108                                  uintN lineno)
109   : JSTreeContext(parser),
110     codePool(cpool), notePool(npool),
111     codeMark(JS_ARENA_MARK(cpool)), noteMark(JS_ARENA_MARK(npool)),
112     stackDepth(0), maxStackDepth(0),
113     ntrynotes(0), lastTryNode(NULL),
114     spanDeps(NULL), jumpTargets(NULL), jtFreeList(NULL),
115     numSpanDeps(0), numJumpTargets(0), spanDepTodo(0),
116     arrayCompDepth(0),
117     emitLevel(0),
118     constMap(parser->context),
119     constList(parser->context),
120     globalUses(ContextAllocPolicy(parser->context)),
121     closedArgs(ContextAllocPolicy(parser->context)),
122     closedVars(ContextAllocPolicy(parser->context)),
123     traceIndex(0)
124 {
125     flags = TCF_COMPILING;
126     memset(&prolog, 0, sizeof prolog);
127     memset(&main, 0, sizeof main);
128     current = &main;
129     firstLine = prolog.currentLine = main.currentLine = lineno;
130     prolog.noteMask = main.noteMask = SRCNOTE_CHUNK - 1;
131     memset(&upvarMap, 0, sizeof upvarMap);
132 }
133
134 bool JSCodeGenerator::init()
135 {
136     return constMap.init();
137 }
138
139 JSCodeGenerator::~JSCodeGenerator()
140 {
141     JS_ARENA_RELEASE(codePool, codeMark);
142     JS_ARENA_RELEASE(notePool, noteMark);
143
144     /* NB: non-null only after OOM. */
145     if (spanDeps)
146         parser->context->free(spanDeps);
147
148     if (upvarMap.vector)
149         parser->context->free(upvarMap.vector);
150 }
151
152 static ptrdiff_t
153 EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta)
154 {
155     jsbytecode *base, *limit, *next;
156     ptrdiff_t offset, length;
157     size_t incr, size;
158
159     base = CG_BASE(cg);
160     next = CG_NEXT(cg);
161     limit = CG_LIMIT(cg);
162     offset = next - base;
163     if (next + delta > limit) {
164         length = offset + delta;
165         length = (length <= BYTECODE_CHUNK)
166                  ? BYTECODE_CHUNK
167                  : JS_BIT(JS_CeilingLog2(length));
168         incr = BYTECODE_SIZE(length);
169         if (!base) {
170             JS_ARENA_ALLOCATE_CAST(base, jsbytecode *, cg->codePool, incr);
171         } else {
172             size = BYTECODE_SIZE(limit - base);
173             incr -= size;
174             JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);
175         }
176         if (!base) {
177             js_ReportOutOfScriptQuota(cx);
178             return -1;
179         }
180         CG_BASE(cg) = base;
181         CG_LIMIT(cg) = base + length;
182         CG_NEXT(cg) = base + offset;
183     }
184     return offset;
185 }
186
187 static void
188 UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target)
189 {
190     jsbytecode *pc;
191     JSOp op;
192     const JSCodeSpec *cs;
193     uintN extra, depth, nuses;
194     intN ndefs;
195
196     pc = CG_CODE(cg, target);
197     op = (JSOp) *pc;
198     cs = &js_CodeSpec[op];
199 #ifdef JS_TRACER
200     extern uint8 js_opcode2extra[];
201     extra = js_opcode2extra[op];
202 #else
203     extra = 0;
204 #endif
205     if ((cs->format & JOF_TMPSLOT_MASK) || extra) {
206         depth = (uintN) cg->stackDepth +
207                 ((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT) +
208                 extra;
209         /* :TODO: hack - remove later. */
210         switch (op) {
211           case JSOP_PROPINC:
212           case JSOP_PROPDEC:
213             depth += 1;
214             break;
215           case JSOP_NAMEINC:
216           case JSOP_NAMEDEC:
217           case JSOP_INCNAME:
218           case JSOP_DECNAME:
219           case JSOP_GNAMEINC:
220           case JSOP_GNAMEDEC:
221           case JSOP_INCGNAME:
222           case JSOP_DECGNAME:
223             depth += 2;
224             break;
225           default:
226             break;
227         }
228         if (depth > cg->maxStackDepth)
229             cg->maxStackDepth = depth;
230     }
231
232     nuses = js_GetStackUses(cs, op, pc);
233     cg->stackDepth -= nuses;
234     JS_ASSERT(cg->stackDepth >= 0);
235     if (cg->stackDepth < 0) {
236         char numBuf[12];
237         TokenStream *ts;
238
239         JS_snprintf(numBuf, sizeof numBuf, "%d", target);
240         ts = &cg->parser->tokenStream;
241         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING,
242                                      js_GetErrorMessage, NULL,
243                                      JSMSG_STACK_UNDERFLOW,
244                                      ts->getFilename() ? ts->getFilename() : "stdin",
245                                      numBuf);
246     }
247     ndefs = cs->ndefs;
248     if (ndefs < 0) {
249         JSObject *blockObj;
250
251         /* We just executed IndexParsedObject */
252         JS_ASSERT(op == JSOP_ENTERBLOCK);
253         JS_ASSERT(nuses == 0);
254         blockObj = cg->objectList.lastbox->object;
255         JS_ASSERT(blockObj->isStaticBlock());
256         JS_ASSERT(blockObj->getSlot(JSSLOT_BLOCK_DEPTH).isUndefined());
257
258         OBJ_SET_BLOCK_DEPTH(cx, blockObj, cg->stackDepth);
259         ndefs = OBJ_BLOCK_COUNT(cx, blockObj);
260     }
261     cg->stackDepth += ndefs;
262     if ((uintN)cg->stackDepth > cg->maxStackDepth)
263         cg->maxStackDepth = cg->stackDepth;
264 }
265
266 ptrdiff_t
267 js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op)
268 {
269     ptrdiff_t offset = EmitCheck(cx, cg, op, 1);
270
271     if (offset >= 0) {
272         *CG_NEXT(cg)++ = (jsbytecode)op;
273         UpdateDepth(cx, cg, offset);
274     }
275     return offset;
276 }
277
278 ptrdiff_t
279 js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1)
280 {
281     ptrdiff_t offset = EmitCheck(cx, cg, op, 2);
282
283     if (offset >= 0) {
284         jsbytecode *next = CG_NEXT(cg);
285         next[0] = (jsbytecode)op;
286         next[1] = op1;
287         CG_NEXT(cg) = next + 2;
288         UpdateDepth(cx, cg, offset);
289     }
290     return offset;
291 }
292
293 ptrdiff_t
294 js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1,
295          jsbytecode op2)
296 {
297     ptrdiff_t offset = EmitCheck(cx, cg, op, 3);
298
299     if (offset >= 0) {
300         jsbytecode *next = CG_NEXT(cg);
301         next[0] = (jsbytecode)op;
302         next[1] = op1;
303         next[2] = op2;
304         CG_NEXT(cg) = next + 3;
305         UpdateDepth(cx, cg, offset);
306     }
307     return offset;
308 }
309
310 ptrdiff_t
311 js_Emit5(JSContext *cx, JSCodeGenerator *cg, JSOp op, uint16 op1, uint16 op2)
312 {
313     ptrdiff_t offset = EmitCheck(cx, cg, op, 5);
314
315     if (offset >= 0) {
316         jsbytecode *next = CG_NEXT(cg);
317         next[0] = (jsbytecode)op;
318         next[1] = UINT16_HI(op1);
319         next[2] = UINT16_LO(op1);
320         next[3] = UINT16_HI(op2);
321         next[4] = UINT16_LO(op2);
322         CG_NEXT(cg) = next + 5;
323         UpdateDepth(cx, cg, offset);
324     }
325     return offset;
326 }
327
328 ptrdiff_t
329 js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra)
330 {
331     ptrdiff_t length = 1 + (ptrdiff_t)extra;
332     ptrdiff_t offset = EmitCheck(cx, cg, op, length);
333
334     if (offset >= 0) {
335         jsbytecode *next = CG_NEXT(cg);
336         *next = (jsbytecode)op;
337         memset(next + 1, 0, BYTECODE_SIZE(extra));
338         CG_NEXT(cg) = next + length;
339
340         /*
341          * Don't UpdateDepth if op's use-count comes from the immediate
342          * operand yet to be stored in the extra bytes after op.
343          */
344         if (js_CodeSpec[op].nuses >= 0)
345             UpdateDepth(cx, cg, offset);
346     }
347     return offset;
348 }
349
350 /* XXX too many "... statement" L10N gaffes below -- fix via js.msg! */
351 const char js_with_statement_str[] = "with statement";
352 const char js_finally_block_str[]  = "finally block";
353 const char js_script_str[]         = "script";
354
355 static const char *statementName[] = {
356     "label statement",       /* LABEL */
357     "if statement",          /* IF */
358     "else statement",        /* ELSE */
359     "destructuring body",    /* BODY */
360     "switch statement",      /* SWITCH */
361     "block",                 /* BLOCK */
362     js_with_statement_str,   /* WITH */
363     "catch block",           /* CATCH */
364     "try block",             /* TRY */
365     js_finally_block_str,    /* FINALLY */
366     js_finally_block_str,    /* SUBROUTINE */
367     "do loop",               /* DO_LOOP */
368     "for loop",              /* FOR_LOOP */
369     "for/in loop",           /* FOR_IN_LOOP */
370     "while loop",            /* WHILE_LOOP */
371 };
372
373 JS_STATIC_ASSERT(JS_ARRAY_LENGTH(statementName) == STMT_LIMIT);
374
375 static const char *
376 StatementName(JSCodeGenerator *cg)
377 {
378     if (!cg->topStmt)
379         return js_script_str;
380     return statementName[cg->topStmt->type];
381 }
382
383 static void
384 ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg)
385 {
386     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET,
387                          StatementName(cg));
388 }
389
390 /**
391   Span-dependent instructions in JS bytecode consist of the jump (JOF_JUMP)
392   and switch (JOF_LOOKUPSWITCH, JOF_TABLESWITCH) format opcodes, subdivided
393   into unconditional (gotos and gosubs), and conditional jumps or branches
394   (which pop a value, test it, and jump depending on its value).  Most jumps
395   have just one immediate operand, a signed offset from the jump opcode's pc
396   to the target bytecode.  The lookup and table switch opcodes may contain
397   many jump offsets.
398
399   Mozilla bug #80981 (http://bugzilla.mozilla.org/show_bug.cgi?id=80981) was
400   fixed by adding extended "X" counterparts to the opcodes/formats (NB: X is
401   suffixed to prefer JSOP_ORX thereby avoiding a JSOP_XOR name collision for
402   the extended form of the JSOP_OR branch opcode).  The unextended or short
403   formats have 16-bit signed immediate offset operands, the extended or long
404   formats have 32-bit signed immediates.  The span-dependency problem consists
405   of selecting as few long instructions as possible, or about as few -- since
406   jumps can span other jumps, extending one jump may cause another to need to
407   be extended.
408
409   Most JS scripts are short, so need no extended jumps.  We optimize for this
410   case by generating short jumps until we know a long jump is needed.  After
411   that point, we keep generating short jumps, but each jump's 16-bit immediate
412   offset operand is actually an unsigned index into cg->spanDeps, an array of
413   JSSpanDep structs.  Each struct tells the top offset in the script of the
414   opcode, the "before" offset of the jump (which will be the same as top for
415   simplex jumps, but which will index further into the bytecode array for a
416   non-initial jump offset in a lookup or table switch), the after "offset"
417   adjusted during span-dependent instruction selection (initially the same
418   value as the "before" offset), and the jump target (more below).
419
420   Since we generate cg->spanDeps lazily, from within js_SetJumpOffset, we must
421   ensure that all bytecode generated so far can be inspected to discover where
422   the jump offset immediate operands lie within CG_CODE(cg).  But the bonus is
423   that we generate span-dependency records sorted by their offsets, so we can
424   binary-search when trying to find a JSSpanDep for a given bytecode offset,
425   or the nearest JSSpanDep at or above a given pc.
426
427   To avoid limiting scripts to 64K jumps, if the cg->spanDeps index overflows
428   65534, we store SPANDEP_INDEX_HUGE in the jump's immediate operand.  This
429   tells us that we need to binary-search for the cg->spanDeps entry by the
430   jump opcode's bytecode offset (sd->before).
431
432   Jump targets need to be maintained in a data structure that lets us look
433   up an already-known target by its address (jumps may have a common target),
434   and that also lets us update the addresses (script-relative, a.k.a. absolute
435   offsets) of targets that come after a jump target (for when a jump below
436   that target needs to be extended).  We use an AVL tree, implemented using
437   recursion, but with some tricky optimizations to its height-balancing code
438   (see http://www.cmcrossroads.com/bradapp/ftp/src/libs/C++/AvlTrees.html).
439
440   A final wrinkle: backpatch chains are linked by jump-to-jump offsets with
441   positive sign, even though they link "backward" (i.e., toward lower bytecode
442   address).  We don't want to waste space and search time in the AVL tree for
443   such temporary backpatch deltas, so we use a single-bit wildcard scheme to
444   tag true JSJumpTarget pointers and encode untagged, signed (positive) deltas
445   in JSSpanDep.target pointers, depending on whether the JSSpanDep has a known
446   target, or is still awaiting backpatching.
447
448   Note that backpatch chains would present a problem for BuildSpanDepTable,
449   which inspects bytecode to build cg->spanDeps on demand, when the first
450   short jump offset overflows.  To solve this temporary problem, we emit a
451   proxy bytecode (JSOP_BACKPATCH; JSOP_BACKPATCH_POP for branch ops) whose
452   nuses/ndefs counts help keep the stack balanced, but whose opcode format
453   distinguishes its backpatch delta immediate operand from a normal jump
454   offset.
455  */
456 static int
457 BalanceJumpTargets(JSJumpTarget **jtp)
458 {
459     JSJumpTarget *jt, *jt2, *root;
460     int dir, otherDir, heightChanged;
461     JSBool doubleRotate;
462
463     jt = *jtp;
464     JS_ASSERT(jt->balance != 0);
465
466     if (jt->balance < -1) {
467         dir = JT_RIGHT;
468         doubleRotate = (jt->kids[JT_LEFT]->balance > 0);
469     } else if (jt->balance > 1) {
470         dir = JT_LEFT;
471         doubleRotate = (jt->kids[JT_RIGHT]->balance < 0);
472     } else {
473         return 0;
474     }
475
476     otherDir = JT_OTHER_DIR(dir);
477     if (doubleRotate) {
478         jt2 = jt->kids[otherDir];
479         *jtp = root = jt2->kids[dir];
480
481         jt->kids[otherDir] = root->kids[dir];
482         root->kids[dir] = jt;
483
484         jt2->kids[dir] = root->kids[otherDir];
485         root->kids[otherDir] = jt2;
486
487         heightChanged = 1;
488         root->kids[JT_LEFT]->balance = -JS_MAX(root->balance, 0);
489         root->kids[JT_RIGHT]->balance = -JS_MIN(root->balance, 0);
490         root->balance = 0;
491     } else {
492         *jtp = root = jt->kids[otherDir];
493         jt->kids[otherDir] = root->kids[dir];
494         root->kids[dir] = jt;
495
496         heightChanged = (root->balance != 0);
497         jt->balance = -((dir == JT_LEFT) ? --root->balance : ++root->balance);
498     }
499
500     return heightChanged;
501 }
502
503 typedef struct AddJumpTargetArgs {
504     JSContext           *cx;
505     JSCodeGenerator     *cg;
506     ptrdiff_t           offset;
507     JSJumpTarget        *node;
508 } AddJumpTargetArgs;
509
510 static int
511 AddJumpTarget(AddJumpTargetArgs *args, JSJumpTarget **jtp)
512 {
513     JSJumpTarget *jt;
514     int balanceDelta;
515
516     jt = *jtp;
517     if (!jt) {
518         JSCodeGenerator *cg = args->cg;
519
520         jt = cg->jtFreeList;
521         if (jt) {
522             cg->jtFreeList = jt->kids[JT_LEFT];
523         } else {
524             JS_ARENA_ALLOCATE_CAST(jt, JSJumpTarget *, &args->cx->tempPool,
525                                    sizeof *jt);
526             if (!jt) {
527                 js_ReportOutOfScriptQuota(args->cx);
528                 return 0;
529             }
530         }
531         jt->offset = args->offset;
532         jt->balance = 0;
533         jt->kids[JT_LEFT] = jt->kids[JT_RIGHT] = NULL;
534         cg->numJumpTargets++;
535         args->node = jt;
536         *jtp = jt;
537         return 1;
538     }
539
540     if (jt->offset == args->offset) {
541         args->node = jt;
542         return 0;
543     }
544
545     if (args->offset < jt->offset)
546         balanceDelta = -AddJumpTarget(args, &jt->kids[JT_LEFT]);
547     else
548         balanceDelta = AddJumpTarget(args, &jt->kids[JT_RIGHT]);
549     if (!args->node)
550         return 0;
551
552     jt->balance += balanceDelta;
553     return (balanceDelta && jt->balance)
554            ? 1 - BalanceJumpTargets(jtp)
555            : 0;
556 }
557
558 #ifdef DEBUG_brendan
559 static int AVLCheck(JSJumpTarget *jt)
560 {
561     int lh, rh;
562
563     if (!jt) return 0;
564     JS_ASSERT(-1 <= jt->balance && jt->balance <= 1);
565     lh = AVLCheck(jt->kids[JT_LEFT]);
566     rh = AVLCheck(jt->kids[JT_RIGHT]);
567     JS_ASSERT(jt->balance == rh - lh);
568     return 1 + JS_MAX(lh, rh);
569 }
570 #endif
571
572 static JSBool
573 SetSpanDepTarget(JSContext *cx, JSCodeGenerator *cg, JSSpanDep *sd,
574                  ptrdiff_t off)
575 {
576     AddJumpTargetArgs args;
577
578     if (off < JUMPX_OFFSET_MIN || JUMPX_OFFSET_MAX < off) {
579         ReportStatementTooLarge(cx, cg);
580         return JS_FALSE;
581     }
582
583     args.cx = cx;
584     args.cg = cg;
585     args.offset = sd->top + off;
586     args.node = NULL;
587     AddJumpTarget(&args, &cg->jumpTargets);
588     if (!args.node)
589         return JS_FALSE;
590
591 #ifdef DEBUG_brendan
592     AVLCheck(cg->jumpTargets);
593 #endif
594
595     SD_SET_TARGET(sd, args.node);
596     return JS_TRUE;
597 }
598
599 #define SPANDEPS_MIN            256
600 #define SPANDEPS_SIZE(n)        ((n) * sizeof(JSSpanDep))
601 #define SPANDEPS_SIZE_MIN       SPANDEPS_SIZE(SPANDEPS_MIN)
602
603 static JSBool
604 AddSpanDep(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, jsbytecode *pc2,
605            ptrdiff_t off)
606 {
607     uintN index;
608     JSSpanDep *sdbase, *sd;
609     size_t size;
610
611     index = cg->numSpanDeps;
612     if (index + 1 == 0) {
613         ReportStatementTooLarge(cx, cg);
614         return JS_FALSE;
615     }
616
617     if ((index & (index - 1)) == 0 &&
618         (!(sdbase = cg->spanDeps) || index >= SPANDEPS_MIN)) {
619         size = sdbase ? SPANDEPS_SIZE(index) : SPANDEPS_SIZE_MIN / 2;
620         sdbase = (JSSpanDep *) cx->realloc(sdbase, size + size);
621         if (!sdbase)
622             return JS_FALSE;
623         cg->spanDeps = sdbase;
624     }
625
626     cg->numSpanDeps = index + 1;
627     sd = cg->spanDeps + index;
628     sd->top = pc - CG_BASE(cg);
629     sd->offset = sd->before = pc2 - CG_BASE(cg);
630
631     if (js_CodeSpec[*pc].format & JOF_BACKPATCH) {
632         /* Jump offset will be backpatched if off is a non-zero "bpdelta". */
633         if (off != 0) {
634             JS_ASSERT(off >= 1 + JUMP_OFFSET_LEN);
635             if (off > BPDELTA_MAX) {
636                 ReportStatementTooLarge(cx, cg);
637                 return JS_FALSE;
638             }
639         }
640         SD_SET_BPDELTA(sd, off);
641     } else if (off == 0) {
642         /* Jump offset will be patched directly, without backpatch chaining. */
643         SD_SET_TARGET(sd, 0);
644     } else {
645         /* The jump offset in off is non-zero, therefore it's already known. */
646         if (!SetSpanDepTarget(cx, cg, sd, off))
647             return JS_FALSE;
648     }
649
650     if (index > SPANDEP_INDEX_MAX)
651         index = SPANDEP_INDEX_HUGE;
652     SET_SPANDEP_INDEX(pc2, index);
653     return JS_TRUE;
654 }
655
656 static jsbytecode *
657 AddSwitchSpanDeps(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc)
658 {
659     JSOp op;
660     jsbytecode *pc2;
661     ptrdiff_t off;
662     jsint low, high;
663     uintN njumps, indexlen;
664
665     op = (JSOp) *pc;
666     JS_ASSERT(op == JSOP_TABLESWITCH || op == JSOP_LOOKUPSWITCH);
667     pc2 = pc;
668     off = GET_JUMP_OFFSET(pc2);
669     if (!AddSpanDep(cx, cg, pc, pc2, off))
670         return NULL;
671     pc2 += JUMP_OFFSET_LEN;
672     if (op == JSOP_TABLESWITCH) {
673         low = GET_JUMP_OFFSET(pc2);
674         pc2 += JUMP_OFFSET_LEN;
675         high = GET_JUMP_OFFSET(pc2);
676         pc2 += JUMP_OFFSET_LEN;
677         njumps = (uintN) (high - low + 1);
678         indexlen = 0;
679     } else {
680         njumps = GET_UINT16(pc2);
681         pc2 += UINT16_LEN;
682         indexlen = INDEX_LEN;
683     }
684     while (njumps) {
685         --njumps;
686         pc2 += indexlen;
687         off = GET_JUMP_OFFSET(pc2);
688         if (!AddSpanDep(cx, cg, pc, pc2, off))
689             return NULL;
690         pc2 += JUMP_OFFSET_LEN;
691     }
692     return 1 + pc2;
693 }
694
695 static JSBool
696 BuildSpanDepTable(JSContext *cx, JSCodeGenerator *cg)
697 {
698     jsbytecode *pc, *end;
699     JSOp op;
700     const JSCodeSpec *cs;
701     ptrdiff_t off;
702
703     pc = CG_BASE(cg) + cg->spanDepTodo;
704     end = CG_NEXT(cg);
705     while (pc != end) {
706         JS_ASSERT(pc < end);
707         op = (JSOp)*pc;
708         cs = &js_CodeSpec[op];
709
710         switch (JOF_TYPE(cs->format)) {
711           case JOF_TABLESWITCH:
712           case JOF_LOOKUPSWITCH:
713             pc = AddSwitchSpanDeps(cx, cg, pc);
714             if (!pc)
715                 return JS_FALSE;
716             break;
717
718           case JOF_JUMP:
719             off = GET_JUMP_OFFSET(pc);
720             if (!AddSpanDep(cx, cg, pc, pc, off))
721                 return JS_FALSE;
722             /* FALL THROUGH */
723           default:
724             pc += cs->length;
725             break;
726         }
727     }
728
729     return JS_TRUE;
730 }
731
732 static JSSpanDep *
733 GetSpanDep(JSCodeGenerator *cg, jsbytecode *pc)
734 {
735     uintN index;
736     ptrdiff_t offset;
737     int lo, hi, mid;
738     JSSpanDep *sd;
739
740     index = GET_SPANDEP_INDEX(pc);
741     if (index != SPANDEP_INDEX_HUGE)
742         return cg->spanDeps + index;
743
744     offset = pc - CG_BASE(cg);
745     lo = 0;
746     hi = cg->numSpanDeps - 1;
747     while (lo <= hi) {
748         mid = (lo + hi) / 2;
749         sd = cg->spanDeps + mid;
750         if (sd->before == offset)
751             return sd;
752         if (sd->before < offset)
753             lo = mid + 1;
754         else
755             hi = mid - 1;
756     }
757
758     JS_ASSERT(0);
759     return NULL;
760 }
761
762 static JSBool
763 SetBackPatchDelta(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
764                   ptrdiff_t delta)
765 {
766     JSSpanDep *sd;
767
768     JS_ASSERT(delta >= 1 + JUMP_OFFSET_LEN);
769     if (!cg->spanDeps && delta < JUMP_OFFSET_MAX) {
770         SET_JUMP_OFFSET(pc, delta);
771         return JS_TRUE;
772     }
773
774     if (delta > BPDELTA_MAX) {
775         ReportStatementTooLarge(cx, cg);
776         return JS_FALSE;
777     }
778
779     if (!cg->spanDeps && !BuildSpanDepTable(cx, cg))
780         return JS_FALSE;
781
782     sd = GetSpanDep(cg, pc);
783     JS_ASSERT(SD_GET_BPDELTA(sd) == 0);
784     SD_SET_BPDELTA(sd, delta);
785     return JS_TRUE;
786 }
787
788 static void
789 UpdateJumpTargets(JSJumpTarget *jt, ptrdiff_t pivot, ptrdiff_t delta)
790 {
791     if (jt->offset > pivot) {
792         jt->offset += delta;
793         if (jt->kids[JT_LEFT])
794             UpdateJumpTargets(jt->kids[JT_LEFT], pivot, delta);
795     }
796     if (jt->kids[JT_RIGHT])
797         UpdateJumpTargets(jt->kids[JT_RIGHT], pivot, delta);
798 }
799
800 static JSSpanDep *
801 FindNearestSpanDep(JSCodeGenerator *cg, ptrdiff_t offset, int lo,
802                    JSSpanDep *guard)
803 {
804     int num, hi, mid;
805     JSSpanDep *sdbase, *sd;
806
807     num = cg->numSpanDeps;
808     JS_ASSERT(num > 0);
809     hi = num - 1;
810     sdbase = cg->spanDeps;
811     while (lo <= hi) {
812         mid = (lo + hi) / 2;
813         sd = sdbase + mid;
814         if (sd->before == offset)
815             return sd;
816         if (sd->before < offset)
817             lo = mid + 1;
818         else
819             hi = mid - 1;
820     }
821     if (lo == num)
822         return guard;
823     sd = sdbase + lo;
824     JS_ASSERT(sd->before >= offset && (lo == 0 || sd[-1].before < offset));
825     return sd;
826 }
827
828 static void
829 FreeJumpTargets(JSCodeGenerator *cg, JSJumpTarget *jt)
830 {
831     if (jt->kids[JT_LEFT])
832         FreeJumpTargets(cg, jt->kids[JT_LEFT]);
833     if (jt->kids[JT_RIGHT])
834         FreeJumpTargets(cg, jt->kids[JT_RIGHT]);
835     jt->kids[JT_LEFT] = cg->jtFreeList;
836     cg->jtFreeList = jt;
837 }
838
839 static JSBool
840 OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg)
841 {
842     jsbytecode *pc, *oldpc, *base, *limit, *next;
843     JSSpanDep *sd, *sd2, *sdbase, *sdlimit, *sdtop, guard;
844     ptrdiff_t offset, growth, delta, top, pivot, span, length, target;
845     JSBool done;
846     JSOp op;
847     uint32 type;
848     size_t size, incr;
849     jssrcnote *sn, *snlimit;
850     JSSrcNoteSpec *spec;
851     uintN i, n, noteIndex;
852     JSTryNode *tryNode;
853 #ifdef DEBUG_brendan
854     int passes = 0;
855 #endif
856
857     base = CG_BASE(cg);
858     sdbase = cg->spanDeps;
859     sdlimit = sdbase + cg->numSpanDeps;
860     offset = CG_OFFSET(cg);
861     growth = 0;
862
863     do {
864         done = JS_TRUE;
865         delta = 0;
866         top = pivot = -1;
867         sdtop = NULL;
868         pc = NULL;
869         op = JSOP_NOP;
870         type = 0;
871 #ifdef DEBUG_brendan
872         passes++;
873 #endif
874
875         for (sd = sdbase; sd < sdlimit; sd++) {
876             JS_ASSERT(JT_HAS_TAG(sd->target));
877             sd->offset += delta;
878
879             if (sd->top != top) {
880                 sdtop = sd;
881                 top = sd->top;
882                 JS_ASSERT(top == sd->before);
883                 pivot = sd->offset;
884                 pc = base + top;
885                 op = (JSOp) *pc;
886                 type = JOF_OPTYPE(op);
887                 if (JOF_TYPE_IS_EXTENDED_JUMP(type)) {
888                     /*
889                      * We already extended all the jump offset operands for
890                      * the opcode at sd->top.  Jumps and branches have only
891                      * one jump offset operand, but switches have many, all
892                      * of which are adjacent in cg->spanDeps.
893                      */
894                     continue;
895                 }
896
897                 JS_ASSERT(type == JOF_JUMP ||
898                           type == JOF_TABLESWITCH ||
899                           type == JOF_LOOKUPSWITCH);
900             }
901
902             if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) {
903                 span = SD_SPAN(sd, pivot);
904                 if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) {
905                     ptrdiff_t deltaFromTop = 0;
906
907                     done = JS_FALSE;
908
909                     switch (op) {
910                       case JSOP_GOTO:         op = JSOP_GOTOX; break;
911                       case JSOP_IFEQ:         op = JSOP_IFEQX; break;
912                       case JSOP_IFNE:         op = JSOP_IFNEX; break;
913                       case JSOP_OR:           op = JSOP_ORX; break;
914                       case JSOP_AND:          op = JSOP_ANDX; break;
915                       case JSOP_GOSUB:        op = JSOP_GOSUBX; break;
916                       case JSOP_CASE:         op = JSOP_CASEX; break;
917                       case JSOP_DEFAULT:      op = JSOP_DEFAULTX; break;
918                       case JSOP_TABLESWITCH:  op = JSOP_TABLESWITCHX; break;
919                       case JSOP_LOOKUPSWITCH: op = JSOP_LOOKUPSWITCHX; break;
920                       default:
921                         ReportStatementTooLarge(cx, cg);
922                         return JS_FALSE;
923                     }
924                     *pc = (jsbytecode) op;
925
926                     for (sd2 = sdtop; sd2 < sdlimit && sd2->top == top; sd2++) {
927                         if (sd2 <= sd) {
928                             /*
929                              * sd2->offset already includes delta as it stood
930                              * before we entered this loop, but it must also
931                              * include the delta relative to top due to all the
932                              * extended jump offset immediates for the opcode
933                              * starting at top, which we extend in this loop.
934                              *
935                              * If there is only one extended jump offset, then
936                              * sd2->offset won't change and this for loop will
937                              * iterate once only.
938                              */
939                             sd2->offset += deltaFromTop;
940                             deltaFromTop += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN;
941                         } else {
942                             /*
943                              * sd2 comes after sd, and won't be revisited by
944                              * the outer for loop, so we have to increase its
945                              * offset by delta, not merely by deltaFromTop.
946                              */
947                             sd2->offset += delta;
948                         }
949
950                         delta += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN;
951                         UpdateJumpTargets(cg->jumpTargets, sd2->offset,
952                                           JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN);
953                     }
954                     sd = sd2 - 1;
955                 }
956             }
957         }
958
959         growth += delta;
960     } while (!done);
961
962     if (growth) {
963 #ifdef DEBUG_brendan
964         TokenStream *ts = &cg->parser->tokenStream;
965
966         printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n",
967                ts->filename ? ts->filename : "stdin", cg->firstLine,
968                growth / (JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN), cg->numSpanDeps,
969                passes, offset + growth, offset, growth);
970 #endif
971
972         /*
973          * Ensure that we have room for the extended jumps, but don't round up
974          * to a power of two -- we're done generating code, so we cut to fit.
975          */
976         limit = CG_LIMIT(cg);
977         length = offset + growth;
978         next = base + length;
979         if (next > limit) {
980             JS_ASSERT(length > BYTECODE_CHUNK);
981             size = BYTECODE_SIZE(limit - base);
982             incr = BYTECODE_SIZE(length) - size;
983             JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);
984             if (!base) {
985                 js_ReportOutOfScriptQuota(cx);
986                 return JS_FALSE;
987             }
988             CG_BASE(cg) = base;
989             CG_LIMIT(cg) = next = base + length;
990         }
991         CG_NEXT(cg) = next;
992
993         /*
994          * Set up a fake span dependency record to guard the end of the code
995          * being generated.  This guard record is returned as a fencepost by
996          * FindNearestSpanDep if there is no real spandep at or above a given
997          * unextended code offset.
998          */
999         guard.top = -1;
1000         guard.offset = offset + growth;
1001         guard.before = offset;
1002         guard.target = NULL;
1003     }
1004
1005     /*
1006      * Now work backwards through the span dependencies, copying chunks of
1007      * bytecode between each extended jump toward the end of the grown code
1008      * space, and restoring immediate offset operands for all jump bytecodes.
1009      * The first chunk of bytecodes, starting at base and ending at the first
1010      * extended jump offset (NB: this chunk includes the operation bytecode
1011      * just before that immediate jump offset), doesn't need to be copied.
1012      */
1013     JS_ASSERT(sd == sdlimit);
1014     top = -1;
1015     while (--sd >= sdbase) {
1016         if (sd->top != top) {
1017             top = sd->top;
1018             op = (JSOp) base[top];
1019             type = JOF_OPTYPE(op);
1020
1021             for (sd2 = sd - 1; sd2 >= sdbase && sd2->top == top; sd2--)
1022                 continue;
1023             sd2++;
1024             pivot = sd2->offset;
1025             JS_ASSERT(top == sd2->before);
1026         }
1027
1028         oldpc = base + sd->before;
1029         span = SD_SPAN(sd, pivot);
1030
1031         /*
1032          * If this jump didn't need to be extended, restore its span immediate
1033          * offset operand now, overwriting the index of sd within cg->spanDeps
1034          * that was stored temporarily after *pc when BuildSpanDepTable ran.
1035          *
1036          * Note that span might fit in 16 bits even for an extended jump op,
1037          * if the op has multiple span operands, not all of which overflowed
1038          * (e.g. JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH where some cases are in
1039          * range for a short jump, but others are not).
1040          */
1041         if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) {
1042             JS_ASSERT(JUMP_OFFSET_MIN <= span && span <= JUMP_OFFSET_MAX);
1043             SET_JUMP_OFFSET(oldpc, span);
1044             continue;
1045         }
1046
1047         /*
1048          * Set up parameters needed to copy the next run of bytecode starting
1049          * at offset (which is a cursor into the unextended, original bytecode
1050          * vector), down to sd->before (a cursor of the same scale as offset,
1051          * it's the index of the original jump pc).  Reuse delta to count the
1052          * nominal number of bytes to copy.
1053          */
1054         pc = base + sd->offset;
1055         delta = offset - sd->before;
1056         JS_ASSERT(delta >= 1 + JUMP_OFFSET_LEN);
1057
1058         /*
1059          * Don't bother copying the jump offset we're about to reset, but do
1060          * copy the bytecode at oldpc (which comes just before its immediate
1061          * jump offset operand), on the next iteration through the loop, by
1062          * including it in offset's new value.
1063          */
1064         offset = sd->before + 1;
1065         size = BYTECODE_SIZE(delta - (1 + JUMP_OFFSET_LEN));
1066         if (size) {
1067             memmove(pc + 1 + JUMPX_OFFSET_LEN,
1068                     oldpc + 1 + JUMP_OFFSET_LEN,
1069                     size);
1070         }
1071
1072         SET_JUMPX_OFFSET(pc, span);
1073     }
1074
1075     if (growth) {
1076         /*
1077          * Fix source note deltas.  Don't hardwire the delta fixup adjustment,
1078          * even though currently it must be JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN
1079          * at each sd that moved.  The future may bring different offset sizes
1080          * for span-dependent instruction operands.  However, we fix only main
1081          * notes here, not prolog notes -- we know that prolog opcodes are not
1082          * span-dependent, and aren't likely ever to be.
1083          */
1084         offset = growth = 0;
1085         sd = sdbase;
1086         for (sn = cg->main.notes, snlimit = sn + cg->main.noteCount;
1087              sn < snlimit;
1088              sn = SN_NEXT(sn)) {
1089             /*
1090              * Recall that the offset of a given note includes its delta, and
1091              * tells the offset of the annotated bytecode from the main entry
1092              * point of the script.
1093              */
1094             offset += SN_DELTA(sn);
1095             while (sd < sdlimit && sd->before < offset) {
1096                 /*
1097                  * To compute the delta to add to sn, we need to look at the
1098                  * spandep after sd, whose offset - (before + growth) tells by
1099                  * how many bytes sd's instruction grew.
1100                  */
1101                 sd2 = sd + 1;
1102                 if (sd2 == sdlimit)
1103                     sd2 = &guard;
1104                 delta = sd2->offset - (sd2->before + growth);
1105                 if (delta > 0) {
1106                     JS_ASSERT(delta == JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN);
1107                     sn = js_AddToSrcNoteDelta(cx, cg, sn, delta);
1108                     if (!sn)
1109                         return JS_FALSE;
1110                     snlimit = cg->main.notes + cg->main.noteCount;
1111                     growth += delta;
1112                 }
1113                 sd++;
1114             }
1115
1116             /*
1117              * If sn has span-dependent offset operands, check whether each
1118              * covers further span-dependencies, and increase those operands
1119              * accordingly.  Some source notes measure offset not from the
1120              * annotated pc, but from that pc plus some small bias.  NB: we
1121              * assume that spec->offsetBias can't itself span span-dependent
1122              * instructions!
1123              */
1124             spec = &js_SrcNoteSpec[SN_TYPE(sn)];
1125             if (spec->isSpanDep) {
1126                 pivot = offset + spec->offsetBias;
1127                 n = spec->arity;
1128                 for (i = 0; i < n; i++) {
1129                     span = js_GetSrcNoteOffset(sn, i);
1130                     if (span == 0)
1131                         continue;
1132                     target = pivot + span * spec->isSpanDep;
1133                     sd2 = FindNearestSpanDep(cg, target,
1134                                              (target >= pivot)
1135                                              ? sd - sdbase
1136                                              : 0,
1137                                              &guard);
1138
1139                     /*
1140                      * Increase target by sd2's before-vs-after offset delta,
1141                      * which is absolute (i.e., relative to start of script,
1142                      * as is target).  Recompute the span by subtracting its
1143                      * adjusted pivot from target.
1144                      */
1145                     target += sd2->offset - sd2->before;
1146                     span = target - (pivot + growth);
1147                     span *= spec->isSpanDep;
1148                     noteIndex = sn - cg->main.notes;
1149                     if (!js_SetSrcNoteOffset(cx, cg, noteIndex, i, span))
1150                         return JS_FALSE;
1151                     sn = cg->main.notes + noteIndex;
1152                     snlimit = cg->main.notes + cg->main.noteCount;
1153                 }
1154             }
1155         }
1156         cg->main.lastNoteOffset += growth;
1157
1158         /*
1159          * Fix try/catch notes (O(numTryNotes * log2(numSpanDeps)), but it's
1160          * not clear how we can beat that).
1161          */
1162         for (tryNode = cg->lastTryNode; tryNode; tryNode = tryNode->prev) {
1163             /*
1164              * First, look for the nearest span dependency at/above tn->start.
1165              * There may not be any such spandep, in which case the guard will
1166              * be returned.
1167              */
1168             offset = tryNode->note.start;
1169             sd = FindNearestSpanDep(cg, offset, 0, &guard);
1170             delta = sd->offset - sd->before;
1171             tryNode->note.start = offset + delta;
1172
1173             /*
1174              * Next, find the nearest spandep at/above tn->start + tn->length.
1175              * Use its delta minus tn->start's delta to increase tn->length.
1176              */
1177             length = tryNode->note.length;
1178             sd2 = FindNearestSpanDep(cg, offset + length, sd - sdbase, &guard);
1179             if (sd2 != sd) {
1180                 tryNode->note.length =
1181                     length + sd2->offset - sd2->before - delta;
1182             }
1183         }
1184     }
1185
1186 #ifdef DEBUG_brendan
1187   {
1188     uintN bigspans = 0;
1189     top = -1;
1190     for (sd = sdbase; sd < sdlimit; sd++) {
1191         offset = sd->offset;
1192
1193         /* NB: sd->top cursors into the original, unextended bytecode vector. */
1194         if (sd->top != top) {
1195             JS_ASSERT(top == -1 ||
1196                       !JOF_TYPE_IS_EXTENDED_JUMP(type) ||
1197                       bigspans != 0);
1198             bigspans = 0;
1199             top = sd->top;
1200             JS_ASSERT(top == sd->before);
1201             op = (JSOp) base[offset];
1202             type = JOF_OPTYPE(op);
1203             JS_ASSERT(type == JOF_JUMP ||
1204                       type == JOF_JUMPX ||
1205                       type == JOF_TABLESWITCH ||
1206                       type == JOF_TABLESWITCHX ||
1207                       type == JOF_LOOKUPSWITCH ||
1208                       type == JOF_LOOKUPSWITCHX);
1209             pivot = offset;
1210         }
1211
1212         pc = base + offset;
1213         if (JOF_TYPE_IS_EXTENDED_JUMP(type)) {
1214             span = GET_JUMPX_OFFSET(pc);
1215             if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) {
1216                 bigspans++;
1217             } else {
1218                 JS_ASSERT(type == JOF_TABLESWITCHX ||
1219                           type == JOF_LOOKUPSWITCHX);
1220             }
1221         } else {
1222             span = GET_JUMP_OFFSET(pc);
1223         }
1224         JS_ASSERT(SD_SPAN(sd, pivot) == span);
1225     }
1226     JS_ASSERT(!JOF_TYPE_IS_EXTENDED_JUMP(type) || bigspans != 0);
1227   }
1228 #endif
1229
1230     /*
1231      * Reset so we optimize at most once -- cg may be used for further code
1232      * generation of successive, independent, top-level statements.  No jump
1233      * can span top-level statements, because JS lacks goto.
1234      */
1235     size = SPANDEPS_SIZE(JS_BIT(JS_CeilingLog2(cg->numSpanDeps)));
1236     cx->free(cg->spanDeps);
1237     cg->spanDeps = NULL;
1238     FreeJumpTargets(cg, cg->jumpTargets);
1239     cg->jumpTargets = NULL;
1240     cg->numSpanDeps = cg->numJumpTargets = 0;
1241     cg->spanDepTodo = CG_OFFSET(cg);
1242     return JS_TRUE;
1243 }
1244
1245 static ptrdiff_t
1246 EmitJump(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t off)
1247 {
1248     JSBool extend;
1249     ptrdiff_t jmp;
1250     jsbytecode *pc;
1251
1252     extend = off < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < off;
1253     if (extend && !cg->spanDeps && !BuildSpanDepTable(cx, cg))
1254         return -1;
1255
1256     jmp = js_Emit3(cx, cg, op, JUMP_OFFSET_HI(off), JUMP_OFFSET_LO(off));
1257     if (jmp >= 0 && (extend || cg->spanDeps)) {
1258         pc = CG_CODE(cg, jmp);
1259         if (!AddSpanDep(cx, cg, pc, pc, off))
1260             return -1;
1261     }
1262     return jmp;
1263 }
1264
1265 static ptrdiff_t
1266 GetJumpOffset(JSCodeGenerator *cg, jsbytecode *pc)
1267 {
1268     JSSpanDep *sd;
1269     JSJumpTarget *jt;
1270     ptrdiff_t top;
1271
1272     if (!cg->spanDeps)
1273         return GET_JUMP_OFFSET(pc);
1274
1275     sd = GetSpanDep(cg, pc);
1276     jt = sd->target;
1277     if (!JT_HAS_TAG(jt))
1278         return JT_TO_BPDELTA(jt);
1279
1280     top = sd->top;
1281     while (--sd >= cg->spanDeps && sd->top == top)
1282         continue;
1283     sd++;
1284     return JT_CLR_TAG(jt)->offset - sd->offset;
1285 }
1286
1287 JSBool
1288 js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
1289                  ptrdiff_t off)
1290 {
1291     if (!cg->spanDeps) {
1292         if (JUMP_OFFSET_MIN <= off && off <= JUMP_OFFSET_MAX) {
1293             SET_JUMP_OFFSET(pc, off);
1294             return JS_TRUE;
1295         }
1296
1297         if (!BuildSpanDepTable(cx, cg))
1298             return JS_FALSE;
1299     }
1300
1301     return SetSpanDepTarget(cx, cg, GetSpanDep(cg, pc), off);
1302 }
1303
1304 bool
1305 JSTreeContext::inStatement(JSStmtType type)
1306 {
1307     for (JSStmtInfo *stmt = topStmt; stmt; stmt = stmt->down) {
1308         if (stmt->type == type)
1309             return true;
1310     }
1311     return false;
1312 }
1313
1314 bool
1315 JSTreeContext::ensureSharpSlots()
1316 {
1317 #if JS_HAS_SHARP_VARS
1318     JS_STATIC_ASSERT(SHARP_NSLOTS == 2);
1319
1320     if (sharpSlotBase >= 0) {
1321         JS_ASSERT(flags & TCF_HAS_SHARPS);
1322         return true;
1323     }
1324
1325     JS_ASSERT(!(flags & TCF_HAS_SHARPS));
1326     if (inFunction()) {
1327         JSContext *cx = parser->context;
1328         JSAtom *sharpArrayAtom = js_Atomize(cx, "#array", 6, 0);
1329         JSAtom *sharpDepthAtom = js_Atomize(cx, "#depth", 6, 0);
1330         if (!sharpArrayAtom || !sharpDepthAtom)
1331             return false;
1332
1333         sharpSlotBase = bindings.countVars();
1334         if (!bindings.addVariable(cx, sharpArrayAtom))
1335             return false;
1336         if (!bindings.addVariable(cx, sharpDepthAtom))
1337             return false;
1338     } else {
1339         /*
1340          * Compiler::compileScript will rebase immediate operands indexing
1341          * the sharp slots to come at the end of the global script's |nfixed|
1342          * slots storage, after gvars and regexps.
1343          */
1344         sharpSlotBase = 0;
1345     }
1346     flags |= TCF_HAS_SHARPS;
1347 #endif
1348     return true;
1349 }
1350
1351 bool
1352 JSTreeContext::skipSpansGenerator(unsigned skip)
1353 {
1354     JSTreeContext *tc = this;
1355     for (unsigned i = 0; i < skip; ++i, tc = tc->parent) {
1356         if (!tc)
1357             return false;
1358         if (tc->flags & TCF_FUN_IS_GENERATOR)
1359             return true;
1360     }
1361     return false;
1362 }
1363
1364 void
1365 js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
1366                  ptrdiff_t top)
1367 {
1368     stmt->type = type;
1369     stmt->flags = 0;
1370     stmt->blockid = tc->blockid();
1371     SET_STATEMENT_TOP(stmt, top);
1372     stmt->label = NULL;
1373     JS_ASSERT(!stmt->blockBox);
1374     stmt->down = tc->topStmt;
1375     tc->topStmt = stmt;
1376     if (STMT_LINKS_SCOPE(stmt)) {
1377         stmt->downScope = tc->topScopeStmt;
1378         tc->topScopeStmt = stmt;
1379     } else {
1380         stmt->downScope = NULL;
1381     }
1382 }
1383
1384 void
1385 js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObjectBox *blockBox,
1386                   ptrdiff_t top)
1387 {
1388     js_PushStatement(tc, stmt, STMT_BLOCK, top);
1389     stmt->flags |= SIF_SCOPE;
1390     blockBox->parent = tc->blockChainBox;
1391     blockBox->object->setParent(tc->blockChain());
1392     stmt->downScope = tc->topScopeStmt;
1393     tc->topScopeStmt = stmt;
1394     tc->blockChainBox = blockBox;
1395     stmt->blockBox = blockBox;
1396 }
1397
1398 /*
1399  * Emit a backpatch op with offset pointing to the previous jump of this type,
1400  * so that we can walk back up the chain fixing up the op and jump offset.
1401  */
1402 static ptrdiff_t
1403 EmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp)
1404 {
1405     ptrdiff_t offset, delta;
1406
1407     offset = CG_OFFSET(cg);
1408     delta = offset - *lastp;
1409     *lastp = offset;
1410     JS_ASSERT(delta > 0);
1411     return EmitJump(cx, cg, op, delta);
1412 }
1413
1414 static ptrdiff_t
1415 EmitTraceOp(JSContext *cx, JSCodeGenerator *cg)
1416 {
1417     uint32 index = cg->traceIndex;
1418     if (index < UINT16_MAX)
1419         cg->traceIndex++;
1420     return js_Emit3(cx, cg, JSOP_TRACE, UINT16_HI(index), UINT16_LO(index));
1421 }
1422
1423 /*
1424  * Macro to emit a bytecode followed by a uint16 immediate operand stored in
1425  * big-endian order, used for arg and var numbers as well as for atomIndexes.
1426  * NB: We use cx and cg from our caller's lexical environment, and return
1427  * false on error.
1428  */
1429 #define EMIT_UINT16_IMM_OP(op, i)                                             \
1430     JS_BEGIN_MACRO                                                            \
1431         if (js_Emit3(cx, cg, op, UINT16_HI(i), UINT16_LO(i)) < 0)             \
1432             return JS_FALSE;                                                  \
1433     JS_END_MACRO
1434
1435 #define EMIT_UINT16PAIR_IMM_OP(op, i, j)                                      \
1436     JS_BEGIN_MACRO                                                            \
1437         ptrdiff_t off_ = js_EmitN(cx, cg, op, 2 * UINT16_LEN);                \
1438         if (off_ < 0)                                                         \
1439             return JS_FALSE;                                                  \
1440         jsbytecode *pc_ = CG_CODE(cg, off_);                                  \
1441         SET_UINT16(pc_, i);                                                   \
1442         pc_ += UINT16_LEN;                                                    \
1443         SET_UINT16(pc_, j);                                                   \
1444     JS_END_MACRO
1445
1446 #define EMIT_UINT16_IN_PLACE(offset, op, i)                                   \
1447     JS_BEGIN_MACRO                                                            \
1448         CG_CODE(cg, offset)[0] = op;                                          \
1449         CG_CODE(cg, offset)[1] = UINT16_HI(i);                                \
1450         CG_CODE(cg, offset)[2] = UINT16_LO(i);                                \
1451     JS_END_MACRO
1452
1453 static JSBool
1454 FlushPops(JSContext *cx, JSCodeGenerator *cg, intN *npops)
1455 {
1456     JS_ASSERT(*npops != 0);
1457     if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
1458         return JS_FALSE;
1459     EMIT_UINT16_IMM_OP(JSOP_POPN, *npops);
1460     *npops = 0;
1461     return JS_TRUE;
1462 }
1463
1464 /*
1465  * Emit additional bytecode(s) for non-local jumps.
1466  */
1467 static JSBool
1468 EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt)
1469 {
1470     intN depth, npops;
1471     JSStmtInfo *stmt;
1472
1473     /*
1474      * The non-local jump fixup we emit will unbalance cg->stackDepth, because
1475      * the fixup replicates balanced code such as JSOP_LEAVEWITH emitted at the
1476      * end of a with statement, so we save cg->stackDepth here and restore it
1477      * just before a successful return.
1478      */
1479     depth = cg->stackDepth;
1480     npops = 0;
1481
1482 #define FLUSH_POPS() if (npops && !FlushPops(cx, cg, &npops)) return JS_FALSE
1483
1484     for (stmt = cg->topStmt; stmt != toStmt; stmt = stmt->down) {
1485         switch (stmt->type) {
1486           case STMT_FINALLY:
1487             FLUSH_POPS();
1488             if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
1489                 return JS_FALSE;
1490             if (EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(*stmt)) < 0)
1491                 return JS_FALSE;
1492             break;
1493
1494           case STMT_WITH:
1495             /* There's a With object on the stack that we need to pop. */
1496             FLUSH_POPS();
1497             if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
1498                 return JS_FALSE;
1499             if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0)
1500                 return JS_FALSE;
1501             break;
1502
1503           case STMT_FOR_IN_LOOP:
1504             /*
1505              * The iterator and the object being iterated need to be popped.
1506              */
1507             FLUSH_POPS();
1508             if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
1509                 return JS_FALSE;
1510             if (js_Emit1(cx, cg, JSOP_ENDITER) < 0)
1511                 return JS_FALSE;
1512             break;
1513
1514           case STMT_SUBROUTINE:
1515             /*
1516              * There's a [exception or hole, retsub pc-index] pair on the
1517              * stack that we need to pop.
1518              */
1519             npops += 2;
1520             break;
1521
1522           default:;
1523         }
1524
1525         if (stmt->flags & SIF_SCOPE) {
1526             /* There is a Block object with locals on the stack to pop. */
1527             FLUSH_POPS();
1528             if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
1529                 return JS_FALSE;
1530             if (!EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, stmt->blockBox))
1531                 return JS_FALSE;
1532         }
1533     }
1534
1535     FLUSH_POPS();
1536     cg->stackDepth = depth;
1537     return JS_TRUE;
1538
1539 #undef FLUSH_POPS
1540 }
1541
1542 static JSBool
1543 EmitKnownBlockChain(JSContext *cx, JSCodeGenerator *cg, JSObjectBox *box)
1544 {
1545     if (box)
1546         return EmitIndexOp(cx, JSOP_BLOCKCHAIN, box->index, cg);
1547     return js_Emit1(cx, cg, JSOP_NULLBLOCKCHAIN) >= 0;
1548 }
1549
1550 static JSBool
1551 EmitBlockChain(JSContext *cx, JSCodeGenerator *cg)
1552 {
1553     return EmitKnownBlockChain(cx, cg, cg->blockChainBox);
1554 }
1555
1556 static ptrdiff_t
1557 EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
1558          ptrdiff_t *lastp, JSAtomListElement *label, JSSrcNoteType noteType)
1559 {
1560     intN index;
1561
1562     if (!EmitNonLocalJumpFixup(cx, cg, toStmt))
1563         return -1;
1564
1565     if (label)
1566         index = js_NewSrcNote2(cx, cg, noteType, (ptrdiff_t) ALE_INDEX(label));
1567     else if (noteType != SRC_NULL)
1568         index = js_NewSrcNote(cx, cg, noteType);
1569     else
1570         index = 0;
1571     if (index < 0)
1572         return -1;
1573
1574     ptrdiff_t result = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, lastp);
1575     if (result < 0)
1576         return result;
1577
1578     if (!EmitBlockChain(cx, cg))
1579         return -1;
1580
1581     return result;
1582 }
1583
1584 static JSBool
1585 BackPatch(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t last,
1586           jsbytecode *target, jsbytecode op)
1587 {
1588     jsbytecode *pc, *stop;
1589     ptrdiff_t delta, span;
1590
1591     pc = CG_CODE(cg, last);
1592     stop = CG_CODE(cg, -1);
1593     while (pc != stop) {
1594         delta = GetJumpOffset(cg, pc);
1595         span = target - pc;
1596         CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, span);
1597
1598         /*
1599          * Set *pc after jump offset in case bpdelta didn't overflow, but span
1600          * does (if so, CHECK_AND_SET_JUMP_OFFSET might call BuildSpanDepTable
1601          * and need to see the JSOP_BACKPATCH* op at *pc).
1602          */
1603         *pc = op;
1604         pc -= delta;
1605     }
1606     return JS_TRUE;
1607 }
1608
1609 void
1610 js_PopStatement(JSTreeContext *tc)
1611 {
1612     JSStmtInfo *stmt;
1613
1614     stmt = tc->topStmt;
1615     tc->topStmt = stmt->down;
1616     if (STMT_LINKS_SCOPE(stmt)) {
1617         tc->topScopeStmt = stmt->downScope;
1618         if (stmt->flags & SIF_SCOPE) {
1619             tc->blockChainBox = stmt->blockBox->parent;
1620             JS_SCOPE_DEPTH_METERING(--tc->scopeDepth);
1621         }
1622     }
1623 }
1624
1625 JSBool
1626 js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg)
1627 {
1628     JSStmtInfo *stmt;
1629
1630     stmt = cg->topStmt;
1631     if (!STMT_IS_TRYING(stmt) &&
1632         (!BackPatch(cx, cg, stmt->breaks, CG_NEXT(cg), JSOP_GOTO) ||
1633          !BackPatch(cx, cg, stmt->continues, CG_CODE(cg, stmt->update),
1634                     JSOP_GOTO))) {
1635         return JS_FALSE;
1636     }
1637     js_PopStatement(cg);
1638     return JS_TRUE;
1639 }
1640
1641 JSBool
1642 js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
1643                              JSParseNode *pn)
1644 {
1645     /* XXX just do numbers for now */
1646     if (pn->pn_type == TOK_NUMBER) {
1647         if (!cg->constMap.put(atom, NumberValue(pn->pn_dval)))
1648             return JS_FALSE;
1649     }
1650     return JS_TRUE;
1651 }
1652
1653 JSStmtInfo *
1654 js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt)
1655 {
1656     if (!stmt)
1657         stmt = tc->topScopeStmt;
1658     for (; stmt; stmt = stmt->downScope) {
1659         if (stmt->type == STMT_WITH)
1660             break;
1661
1662         /* Skip "maybe scope" statements that don't contain let bindings. */
1663         if (!(stmt->flags & SIF_SCOPE))
1664             continue;
1665
1666         JSObject *obj = stmt->blockBox->object;
1667         JS_ASSERT(obj->isStaticBlock());
1668
1669         const Shape *shape = obj->nativeLookup(ATOM_TO_JSID(atom));
1670         if (shape) {
1671             JS_ASSERT(shape->hasShortID());
1672
1673             if (slotp) {
1674                 JS_ASSERT(obj->getSlot(JSSLOT_BLOCK_DEPTH).isInt32());
1675                 *slotp = obj->getSlot(JSSLOT_BLOCK_DEPTH).toInt32() + shape->shortid;
1676             }
1677             return stmt;
1678         }
1679     }
1680
1681     if (slotp)
1682         *slotp = -1;
1683     return stmt;
1684 }
1685
1686 /*
1687  * The function sets vp to NO_CONSTANT when the atom does not corresponds to a
1688  * name defining a constant.
1689  */
1690 static JSBool
1691 LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
1692                           Value *constp)
1693 {
1694     JSStmtInfo *stmt;
1695     JSObject *obj;
1696
1697     /*
1698      * Chase down the cg stack, but only until we reach the outermost cg.
1699      * This enables propagating consts from top-level into switch cases in a
1700      * function compiled along with the top-level script.
1701      */
1702     constp->setMagic(JS_NO_CONSTANT);
1703     do {
1704         if (cg->inFunction() || cg->compileAndGo()) {
1705             /* XXX this will need revising if 'const' becomes block-scoped. */
1706             stmt = js_LexicalLookup(cg, atom, NULL);
1707             if (stmt)
1708                 return JS_TRUE;
1709
1710             if (JSCodeGenerator::ConstMap::Ptr p = cg->constMap.lookup(atom)) {
1711                 JS_ASSERT(!p->value.isMagic(JS_NO_CONSTANT));
1712                 *constp = p->value;
1713                 return JS_TRUE;
1714             }
1715
1716             /*
1717              * Try looking in the variable object for a direct property that
1718              * is readonly and permanent.  We know such a property can't be
1719              * shadowed by another property on obj's prototype chain, or a
1720              * with object or catch variable; nor can prop's value be changed,
1721              * nor can prop be deleted.
1722              */
1723             if (cg->inFunction()) {
1724                 if (cg->bindings.hasBinding(cx, atom))
1725                     break;
1726             } else {
1727                 JS_ASSERT(cg->compileAndGo());
1728                 obj = cg->scopeChain();
1729
1730                 const Shape *shape = obj->nativeLookup(ATOM_TO_JSID(atom));
1731                 if (shape) {
1732                     /*
1733                      * We're compiling code that will be executed immediately,
1734                      * not re-executed against a different scope chain and/or
1735                      * variable object.  Therefore we can get constant values
1736                      * from our variable object here.
1737                      */
1738                     if (!shape->writable() && !shape->configurable() &&
1739                         shape->hasDefaultGetter() && obj->containsSlot(shape->slot)) {
1740                         *constp = obj->getSlot(shape->slot);
1741                     }
1742                 }
1743
1744                 if (shape)
1745                     break;
1746             }
1747         }
1748     } while (cg->parent && (cg = cg->parent->asCodeGenerator()));
1749     return JS_TRUE;
1750 }
1751
1752 static inline bool
1753 FitsWithoutBigIndex(uintN index)
1754 {
1755     return index < JS_BIT(16);
1756 }
1757
1758 /*
1759  * Return JSOP_NOP to indicate that index fits 2 bytes and no index segment
1760  * reset instruction is necessary, JSOP_FALSE to indicate an error or either
1761  * JSOP_RESETBASE0 or JSOP_RESETBASE1 to indicate the reset bytecode to issue
1762  * after the main bytecode sequence.
1763  */
1764 static JSOp
1765 EmitBigIndexPrefix(JSContext *cx, JSCodeGenerator *cg, uintN index)
1766 {
1767     uintN indexBase;
1768
1769     /*
1770      * We have max 3 bytes for indexes and check for INDEX_LIMIT overflow only
1771      * for big indexes.
1772      */
1773     JS_STATIC_ASSERT(INDEX_LIMIT <= JS_BIT(24));
1774     JS_STATIC_ASSERT(INDEX_LIMIT >=
1775                      (JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 2) << 16);
1776
1777     if (FitsWithoutBigIndex(index))
1778         return JSOP_NOP;
1779     indexBase = index >> 16;
1780     if (indexBase <= JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 1) {
1781         if (js_Emit1(cx, cg, (JSOp)(JSOP_INDEXBASE1 + indexBase - 1)) < 0)
1782             return JSOP_FALSE;
1783         return JSOP_RESETBASE0;
1784     }
1785
1786     if (index >= INDEX_LIMIT) {
1787         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1788                              JSMSG_TOO_MANY_LITERALS);
1789         return JSOP_FALSE;
1790     }
1791
1792     if (js_Emit2(cx, cg, JSOP_INDEXBASE, (JSOp)indexBase) < 0)
1793         return JSOP_FALSE;
1794     return JSOP_RESETBASE;
1795 }
1796
1797 /*
1798  * Emit a bytecode and its 2-byte constant index immediate operand. If the
1799  * index requires more than 2 bytes, emit a prefix op whose 8-bit immediate
1800  * operand effectively extends the 16-bit immediate of the prefixed opcode,
1801  * by changing index "segment" (see jsinterp.c). We optimize segments 1-3
1802  * with single-byte JSOP_INDEXBASE[123] codes.
1803  *
1804  * Such prefixing currently requires a suffix to restore the "zero segment"
1805  * register setting, but this could be optimized further.
1806  */
1807 static JSBool
1808 EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg)
1809 {
1810     JSOp bigSuffix;
1811
1812     bigSuffix = EmitBigIndexPrefix(cx, cg, index);
1813     if (bigSuffix == JSOP_FALSE)
1814         return JS_FALSE;
1815     EMIT_UINT16_IMM_OP(op, index);
1816     return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0;
1817 }
1818
1819 /*
1820  * Slight sugar for EmitIndexOp, again accessing cx and cg from the macro
1821  * caller's lexical environment, and embedding a false return on error.
1822  */
1823 #define EMIT_INDEX_OP(op, index)                                              \
1824     JS_BEGIN_MACRO                                                            \
1825         if (!EmitIndexOp(cx, op, index, cg))                                  \
1826             return JS_FALSE;                                                  \
1827     JS_END_MACRO
1828
1829 static JSBool
1830 EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
1831 {
1832     JSAtomListElement *ale;
1833
1834     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
1835     if (op == JSOP_GETPROP &&
1836         pn->pn_atom == cx->runtime->atomState.lengthAtom) {
1837         return js_Emit1(cx, cg, JSOP_LENGTH) >= 0;
1838     }
1839     ale = cg->atomList.add(cg->parser, pn->pn_atom);
1840     if (!ale)
1841         return JS_FALSE;
1842     return EmitIndexOp(cx, op, ALE_INDEX(ale), cg);
1843 }
1844
1845 static JSBool
1846 EmitObjectOp(JSContext *cx, JSObjectBox *objbox, JSOp op,
1847              JSCodeGenerator *cg)
1848 {
1849     JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
1850     return EmitIndexOp(cx, op, cg->objectList.index(objbox), cg);
1851 }
1852
1853 /*
1854  * What good are ARGNO_LEN and SLOTNO_LEN, you ask?  The answer is that, apart
1855  * from EmitSlotIndexOp, they abstract out the detail that both are 2, and in
1856  * other parts of the code there's no necessary relationship between the two.
1857  * The abstraction cracks here in order to share EmitSlotIndexOp code among
1858  * the JSOP_DEFLOCALFUN and JSOP_GET{ARG,VAR,LOCAL}PROP cases.
1859  */
1860 JS_STATIC_ASSERT(ARGNO_LEN == 2);
1861 JS_STATIC_ASSERT(SLOTNO_LEN == 2);
1862
1863 static JSBool
1864 EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index,
1865                 JSCodeGenerator *cg)
1866 {
1867     JSOp bigSuffix;
1868     ptrdiff_t off;
1869     jsbytecode *pc;
1870
1871     JS_ASSERT(JOF_OPTYPE(op) == JOF_SLOTATOM ||
1872               JOF_OPTYPE(op) == JOF_SLOTOBJECT);
1873     bigSuffix = EmitBigIndexPrefix(cx, cg, index);
1874     if (bigSuffix == JSOP_FALSE)
1875         return JS_FALSE;
1876
1877     /* Emit [op, slot, index]. */
1878     off = js_EmitN(cx, cg, op, 2 + INDEX_LEN);
1879     if (off < 0)
1880         return JS_FALSE;
1881     pc = CG_CODE(cg, off);
1882     SET_UINT16(pc, slot);
1883     pc += 2;
1884     SET_INDEX(pc, index);
1885     return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0;
1886 }
1887
1888 bool
1889 JSCodeGenerator::shouldNoteClosedName(JSParseNode *pn)
1890 {
1891     return !callsEval() && pn->pn_defn && pn->isClosed();
1892 }
1893
1894 /*
1895  * Adjust the slot for a block local to account for the number of variables
1896  * that share the same index space with locals. Due to the incremental code
1897  * generation for top-level script, we do the adjustment via code patching in
1898  * Compiler::compileScript; see comments there.
1899  *
1900  * The function returns -1 on failures.
1901  */
1902 static jsint
1903 AdjustBlockSlot(JSContext *cx, JSCodeGenerator *cg, jsint slot)
1904 {
1905     JS_ASSERT((jsuint) slot < cg->maxStackDepth);
1906     if (cg->inFunction()) {
1907         slot += cg->bindings.countVars();
1908         if ((uintN) slot >= SLOTNO_LIMIT) {
1909             ReportCompileErrorNumber(cx, CG_TS(cg), NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_LOCALS);
1910             slot = -1;
1911         }
1912     }
1913     return slot;
1914 }
1915
1916 static bool
1917 EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
1918 {
1919     JS_ASSERT(PN_TYPE(pn) == TOK_LEXICALSCOPE);
1920     if (!EmitObjectOp(cx, pn->pn_objbox, JSOP_ENTERBLOCK, cg))
1921         return false;
1922
1923     JSObject *blockObj = pn->pn_objbox->object;
1924     jsint depth = AdjustBlockSlot(cx, cg, OBJ_BLOCK_DEPTH(cx, blockObj));
1925     if (depth < 0)
1926         return false;
1927
1928     uintN base = JSSLOT_FREE(&js_BlockClass);
1929     for (uintN slot = base, limit = base + OBJ_BLOCK_COUNT(cx, blockObj); slot < limit; slot++) {
1930         const Value &v = blockObj->getSlot(slot);
1931
1932         /* Beware the empty destructuring dummy. */
1933         if (v.isUndefined()) {
1934             JS_ASSERT(slot + 1 <= limit);
1935             continue;
1936         }
1937
1938         JSDefinition *dn = (JSDefinition *) v.toPrivate();
1939         JS_ASSERT(dn->pn_defn);
1940         JS_ASSERT(uintN(dn->frameSlot() + depth) < JS_BIT(16));
1941         dn->pn_cookie.set(dn->pn_cookie.level(), uint16(dn->frameSlot() + depth));
1942 #ifdef DEBUG
1943         for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
1944             JS_ASSERT(pnu->pn_lexdef == dn);
1945             JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
1946             JS_ASSERT(pnu->pn_cookie.isFree());
1947         }
1948 #endif
1949
1950         /*
1951          * If this variable is closed over, and |eval| is not present, then
1952          * then set a bit in dslots so the Method JIT can deoptimize this
1953          * slot.
1954          */
1955         bool isClosed = cg->shouldNoteClosedName(dn);
1956         blockObj->setSlot(slot, BooleanValue(isClosed));
1957     }
1958
1959     return true;
1960 }
1961
1962 static JSBool
1963 EmitLeaveBlock(JSContext *cx, JSCodeGenerator *cg, JSOp op,
1964                JSObjectBox *box)
1965 {
1966     JSOp bigSuffix;
1967     uintN count = OBJ_BLOCK_COUNT(cx, box->object);
1968     
1969     bigSuffix = EmitBigIndexPrefix(cx, cg, box->index);
1970     if (bigSuffix == JSOP_FALSE)
1971         return JS_FALSE;
1972     if (js_Emit5(cx, cg, op, count, box->index) < 0)
1973         return JS_FALSE;
1974     return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0;
1975 }
1976
1977 /*
1978  * Try to convert a *NAME op to a *GNAME op, which optimizes access to
1979  * undeclared globals. Return true if a conversion was made.
1980  *
1981  * This conversion is not made if we are in strict mode.  In eval code nested
1982  * within (strict mode) eval code, access to an undeclared "global" might
1983  * merely be to a binding local to that outer eval:
1984  *
1985  *   "use strict";
1986  *   var x = "global";
1987  *   eval('var x = "eval"; eval("x");'); // 'eval', not 'global'
1988  *
1989  * Outside eval code, access to an undeclared global is a strict mode error:
1990  *
1991  *   "use strict";
1992  *   function foo()
1993  *   {
1994  *     undeclared = 17; // throws ReferenceError
1995  *   }
1996  *   foo();
1997  */
1998 static bool
1999 TryConvertToGname(JSCodeGenerator *cg, JSParseNode *pn, JSOp *op)
2000 {
2001     if (cg->compileAndGo() && 
2002         cg->compiler()->globalScope->globalObj &&
2003         !cg->mightAliasLocals() &&
2004         !pn->isDeoptimized() &&
2005         !(cg->flags & TCF_STRICT_MODE_CODE)) { 
2006         switch (*op) {
2007           case JSOP_NAME:     *op = JSOP_GETGNAME; break;
2008           case JSOP_SETNAME:  *op = JSOP_SETGNAME; break;
2009           case JSOP_INCNAME:  *op = JSOP_INCGNAME; break;
2010           case JSOP_NAMEINC:  *op = JSOP_GNAMEINC; break;
2011           case JSOP_DECNAME:  *op = JSOP_DECGNAME; break;
2012           case JSOP_NAMEDEC:  *op = JSOP_GNAMEDEC; break;
2013           case JSOP_FORNAME:  *op = JSOP_FORGNAME; break;
2014           case JSOP_SETCONST:
2015           case JSOP_DELNAME:
2016             /* Not supported. */
2017             return false;
2018           default: JS_NOT_REACHED("gname");
2019         }
2020         return true;
2021     }
2022     return false;
2023 }
2024
2025 // Binds a global, given a |dn| that is known to have the PND_GVAR bit, and a pn
2026 // that is |dn| or whose definition is |dn|. |pn->pn_cookie| is an outparam
2027 // that will be free (meaning no binding), or a slot number.
2028 static bool
2029 BindKnownGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *dn, JSParseNode *pn, JSAtom *atom)
2030 {
2031     // Cookie is an outparam; make sure caller knew to clear it.
2032     JS_ASSERT(pn->pn_cookie.isFree());
2033
2034     if (cg->mightAliasLocals())
2035         return true;
2036
2037     GlobalScope *globalScope = cg->compiler()->globalScope;
2038
2039     uint32 index;
2040     if (dn->pn_cookie.isFree()) {
2041         // The definition wasn't bound, so find its atom's index in the
2042         // mapping of defined globals.
2043         JSAtomListElement *ale = globalScope->names.lookup(atom);
2044         index = ALE_INDEX(ale);
2045     } else {
2046         JSCodeGenerator *globalcg = globalScope->cg;
2047
2048         // If the definition is bound, and we're in the same cg, we can re-use
2049         // its cookie.
2050         if (globalcg == cg) {
2051             pn->pn_cookie = dn->pn_cookie;
2052             pn->pn_dflags |= PND_BOUND;
2053             return true;
2054         }
2055
2056         // Otherwise, find the atom's index by using the originating cg's
2057         // global use table.
2058         index = globalcg->globalUses[dn->pn_cookie.asInteger()].slot;
2059     }
2060
2061     if (!cg->addGlobalUse(atom, index, &pn->pn_cookie))
2062         return false;
2063
2064     if (!pn->pn_cookie.isFree())
2065         pn->pn_dflags |= PND_BOUND;
2066
2067     return true;
2068 }
2069
2070 // See BindKnownGlobal()'s comment.
2071 static bool
2072 BindGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSAtom *atom)
2073 {
2074     pn->pn_cookie.makeFree();
2075
2076     JSDefinition *dn;
2077     if (pn->pn_used) {
2078         dn = pn->pn_lexdef;
2079     } else {
2080         if (!pn->pn_defn)
2081             return true;
2082         dn = (JSDefinition *)pn;
2083     }
2084
2085     // Only optimize for defined globals.
2086     if (!dn->isGlobal())
2087         return true;
2088
2089     return BindKnownGlobal(cx, cg, dn, pn, atom);
2090 }
2091
2092 /*
2093  * BindNameToSlot attempts to optimize name gets and sets to stack slot loads
2094  * and stores, given the compile-time information in cg and a TOK_NAME node pn.
2095  * It returns false on error, true on success.
2096  *
2097  * The caller can inspect pn->pn_cookie for FREE_UPVAR_COOKIE to tell whether
2098  * optimization occurred, in which case BindNameToSlot also updated pn->pn_op.
2099  * If pn->pn_cookie is still FREE_UPVAR_COOKIE on return, pn->pn_op still may
2100  * have been optimized, e.g., from JSOP_NAME to JSOP_CALLEE.  Whether or not
2101  * pn->pn_op was modified, if this function finds an argument or local variable
2102  * name, PND_CONST will be set in pn_dflags for read-only properties after a
2103  * successful return.
2104  *
2105  * NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget
2106  * to update the TOK_FOR (for-in) and TOK_ASSIGN (op=, e.g. +=) special cases
2107  * in js_EmitTree.
2108  */
2109 static JSBool
2110 BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
2111 {
2112     JSDefinition *dn;
2113     JSOp op;
2114     JSAtom *atom;
2115     JSDefinition::Kind dn_kind;
2116     JSAtomListElement *ale;
2117     uintN index;
2118
2119     JS_ASSERT(pn->pn_type == TOK_NAME);
2120
2121     /* Idempotency tests come first, since we may be called more than once. */
2122     if (pn->pn_dflags & PND_BOUND)
2123         return JS_TRUE;
2124
2125     /* No cookie initialized for these two, they're pre-bound by definition. */
2126     JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE);
2127
2128     /*
2129      * The parser linked all uses (including forward references) to their
2130      * definitions, unless a with statement or direct eval intervened.
2131      */
2132     if (pn->pn_used) {
2133         JS_ASSERT(pn->pn_cookie.isFree());
2134         dn = pn->pn_lexdef;
2135         JS_ASSERT(dn->pn_defn);
2136         if (pn->isDeoptimized())
2137             return JS_TRUE;
2138         pn->pn_dflags |= (dn->pn_dflags & PND_CONST);
2139     } else {
2140         if (!pn->pn_defn)
2141             return JS_TRUE;
2142         dn = (JSDefinition *) pn;
2143     }
2144
2145     op = PN_OP(pn);
2146     if (op == JSOP_NOP)
2147         return JS_TRUE;
2148
2149     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
2150     atom = pn->pn_atom;
2151     UpvarCookie cookie = dn->pn_cookie;
2152     dn_kind = dn->kind();
2153
2154     /*
2155      * Turn attempts to mutate const-declared bindings into get ops (for
2156      * pre-increment and pre-decrement ops, our caller will have to emit
2157      * JSOP_POS, JSOP_ONE, and JSOP_ADD as well).
2158      *
2159      * Turn JSOP_DELNAME into JSOP_FALSE if dn is known, as all declared
2160      * bindings visible to the compiler are permanent in JS unless the
2161      * declaration originates at top level in eval code.
2162      */
2163     switch (op) {
2164       case JSOP_NAME:
2165       case JSOP_SETCONST:
2166         break;
2167       case JSOP_DELNAME:
2168         if (dn_kind != JSDefinition::UNKNOWN) {
2169             if (cg->parser->callerFrame && dn->isTopLevel())
2170                 JS_ASSERT(cg->compileAndGo());
2171             else
2172                 pn->pn_op = JSOP_FALSE;
2173             pn->pn_dflags |= PND_BOUND;
2174             return JS_TRUE;
2175         }
2176         break;
2177       default:
2178         if (pn->isConst())
2179             pn->pn_op = op = JSOP_NAME;
2180     }
2181
2182     if (dn->isGlobal()) {
2183         if (op == JSOP_NAME) {
2184             /*
2185              * If the definition is a defined global, not potentially aliased
2186              * by a local variable, and not mutating the variable, try and
2187              * optimize to a fast, unguarded global access.
2188              */
2189             if (!BindKnownGlobal(cx, cg, dn, pn, atom))
2190                 return JS_FALSE;
2191             if (!pn->pn_cookie.isFree()) {
2192                 pn->pn_op = JSOP_GETGLOBAL;
2193                 return JS_TRUE;
2194             }
2195         }
2196
2197         /*
2198          * The locally stored cookie here should really come from |pn|, not
2199          * |dn|. For example, we could have a SETGNAME op's lexdef be a
2200          * GETGLOBAL op, and their cookies have very different meanings. As
2201          * a workaround, just make the cookie free.
2202          */
2203         cookie.makeFree();
2204     }
2205
2206     if (cookie.isFree()) {
2207         JSStackFrame *caller = cg->parser->callerFrame;
2208         if (caller) {
2209             JS_ASSERT(cg->compileAndGo());
2210
2211             /*
2212              * Don't generate upvars on the left side of a for loop. See
2213              * bug 470758.
2214              */
2215             if (cg->flags & TCF_IN_FOR_INIT)
2216                 return JS_TRUE;
2217
2218             JS_ASSERT(caller->isScriptFrame());
2219
2220             /*
2221              * If this is an eval in the global scope, then unbound variables
2222              * must be globals, so try to use GNAME ops.
2223              */
2224             if (caller->isGlobalFrame() && TryConvertToGname(cg, pn, &op)) {
2225                 ale = cg->atomList.add(cg->parser, atom);
2226                 if (!ale)
2227                     return JS_FALSE;
2228
2229                 pn->pn_op = op;
2230                 pn->pn_dflags |= PND_BOUND;
2231                 return JS_TRUE;
2232             }
2233
2234             /*
2235              * Out of tricks, so we must rely on PICs to optimize named
2236              * accesses from direct eval called from function code.
2237              */
2238             return JS_TRUE;
2239         }
2240
2241         /* Optimize accesses to undeclared globals. */
2242         if (!cg->mightAliasLocals() && !TryConvertToGname(cg, pn, &op))
2243             return JS_TRUE;
2244
2245         ale = cg->atomList.add(cg->parser, atom);
2246         if (!ale)
2247             return JS_FALSE;
2248
2249         pn->pn_op = op;
2250         pn->pn_dflags |= PND_BOUND;
2251
2252         return JS_TRUE;
2253     }
2254
2255     uint16 level = cookie.level();
2256     JS_ASSERT(cg->staticLevel >= level);
2257
2258     const uintN skip = cg->staticLevel - level;
2259     if (skip != 0) {
2260         JS_ASSERT(cg->inFunction());
2261         JS_ASSERT_IF(cookie.slot() != UpvarCookie::CALLEE_SLOT, cg->lexdeps.lookup(atom));
2262         JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
2263         JS_ASSERT(cg->fun()->u.i.skipmin <= skip);
2264
2265         /*
2266          * If op is a mutating opcode, this upvar's lookup skips too many levels,
2267          * or the function is heavyweight, we fall back on JSOP_*NAME*.
2268          */
2269         if (op != JSOP_NAME)
2270             return JS_TRUE;
2271         if (level >= UpvarCookie::UPVAR_LEVEL_LIMIT)
2272             return JS_TRUE;
2273         if (cg->flags & TCF_FUN_HEAVYWEIGHT)
2274             return JS_TRUE;
2275
2276         if (!cg->fun()->isFlatClosure())
2277             return JS_TRUE;
2278
2279         ale = cg->upvarList.lookup(atom);
2280         if (ale) {
2281             index = ALE_INDEX(ale);
2282         } else {
2283             if (!cg->bindings.addUpvar(cx, atom))
2284                 return JS_FALSE;
2285
2286             ale = cg->upvarList.add(cg->parser, atom);
2287             if (!ale)
2288                 return JS_FALSE;
2289             index = ALE_INDEX(ale);
2290             JS_ASSERT(index == cg->upvarList.count - 1);
2291
2292             UpvarCookie *vector = cg->upvarMap.vector;
2293             uint32 length = cg->lexdeps.count;
2294             if (!vector || cg->upvarMap.length != length) {
2295                 vector = (UpvarCookie *) js_realloc(vector, length * sizeof *vector);
2296                 if (!vector) {
2297                     JS_ReportOutOfMemory(cx);
2298                     return JS_FALSE;
2299                 }
2300                 cg->upvarMap.vector = vector;
2301                 cg->upvarMap.length = length;
2302             }
2303
2304             uintN slot = cookie.slot();
2305             if (slot != UpvarCookie::CALLEE_SLOT && dn_kind != JSDefinition::ARG) {
2306                 JSTreeContext *tc = cg;
2307                 do {
2308                     tc = tc->parent;
2309                 } while (tc->staticLevel != level);
2310                 if (tc->inFunction())
2311                     slot += tc->fun()->nargs;
2312             }
2313
2314             JS_ASSERT(index < cg->upvarMap.length);
2315             vector[index].set(skip, slot);
2316         }
2317
2318         pn->pn_op = JSOP_GETFCSLOT;
2319         JS_ASSERT((index & JS_BITMASK(16)) == index);
2320         pn->pn_cookie.set(0, index);
2321         pn->pn_dflags |= PND_BOUND;
2322         return JS_TRUE;
2323     }
2324
2325     /*
2326      * We are compiling a function body and may be able to optimize name
2327      * to stack slot. Look for an argument or variable in the function and
2328      * rewrite pn_op and update pn accordingly.
2329      */
2330     switch (dn_kind) {
2331       case JSDefinition::UNKNOWN:
2332         return JS_TRUE;
2333
2334       case JSDefinition::LET:
2335         switch (op) {
2336           case JSOP_NAME:     op = JSOP_GETLOCAL; break;
2337           case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
2338           case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
2339           case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
2340           case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
2341           case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
2342           case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;
2343           default: JS_NOT_REACHED("let");
2344         }
2345         break;
2346
2347       case JSDefinition::ARG:
2348         switch (op) {
2349           case JSOP_NAME:     op = JSOP_GETARG; break;
2350           case JSOP_SETNAME:  op = JSOP_SETARG; break;
2351           case JSOP_INCNAME:  op = JSOP_INCARG; break;
2352           case JSOP_NAMEINC:  op = JSOP_ARGINC; break;
2353           case JSOP_DECNAME:  op = JSOP_DECARG; break;
2354           case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;
2355           case JSOP_FORNAME:  op = JSOP_FORARG; break;
2356           default: JS_NOT_REACHED("arg");
2357         }
2358         JS_ASSERT(!pn->isConst());
2359         break;
2360
2361       case JSDefinition::VAR:
2362         if (PN_OP(dn) == JSOP_CALLEE) {
2363             JS_ASSERT(op != JSOP_CALLEE);
2364             JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom);
2365
2366             /*
2367              * Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight to
2368              * address two cases: a new binding introduced by eval, and
2369              * assignment to the name in strict mode.
2370              *
2371              *   var fun = (function f(s) { eval(s); return f; });
2372              *   assertEq(fun("var f = 42"), 42);
2373              *
2374              * ECMAScript specifies that a function expression's name is bound
2375              * in a lexical environment distinct from that used to bind its
2376              * named parameters, the arguments object, and its variables.  The
2377              * new binding for "var f = 42" shadows the binding for the
2378              * function itself, so the name of the function will not refer to
2379              * the function.
2380              *
2381              *    (function f() { "use strict"; f = 12; })();
2382              *
2383              * Outside strict mode, assignment to a function expression's name
2384              * has no effect.  But in strict mode, this attempt to mutate an
2385              * immutable binding must throw a TypeError.  We implement this by
2386              * not optimizing such assignments and by marking such functions as
2387              * heavyweight, ensuring that the function name is represented in
2388              * the scope chain so that assignment will throw a TypeError.
2389              */
2390             JS_ASSERT(op != JSOP_DELNAME);
2391             if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) {
2392                 op = JSOP_CALLEE;
2393                 pn->pn_dflags |= PND_CONST;
2394             }
2395
2396             pn->pn_op = op;
2397             pn->pn_dflags |= PND_BOUND;
2398             return JS_TRUE;
2399         }
2400         /* FALL THROUGH */
2401
2402       default:
2403         JS_ASSERT_IF(dn_kind != JSDefinition::FUNCTION,
2404                      dn_kind == JSDefinition::VAR ||
2405                      dn_kind == JSDefinition::CONST);
2406         switch (op) {
2407           case JSOP_NAME:     op = JSOP_GETLOCAL; break;
2408           case JSOP_SETNAME:  op = JSOP_SETLOCAL; break;
2409           case JSOP_SETCONST: op = JSOP_SETLOCAL; break;
2410           case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
2411           case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
2412           case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
2413           case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
2414           case JSOP_FORNAME:  op = JSOP_FORLOCAL; break;
2415           default: JS_NOT_REACHED("local");
2416         }
2417         JS_ASSERT_IF(dn_kind == JSDefinition::CONST, pn->pn_dflags & PND_CONST);
2418         break;
2419     }
2420
2421     JS_ASSERT(op != PN_OP(pn));
2422     pn->pn_op = op;
2423     pn->pn_cookie.set(0, cookie.slot());
2424     pn->pn_dflags |= PND_BOUND;
2425     return JS_TRUE;
2426 }
2427
2428 bool
2429 JSCodeGenerator::addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie)
2430 {
2431     JSAtomListElement *ale = globalMap.lookup(atom);
2432     if (ale) {
2433         cookie->set(0, uint16(ALE_INDEX(ale)));
2434         return true;
2435     }
2436
2437     /* Don't bother encoding indexes >= uint16 */
2438     if (globalUses.length() >= UINT16_LIMIT) {
2439         cookie->makeFree();
2440         return true;
2441     }
2442
2443     /* Find or add an existing atom table entry. */
2444     ale = atomList.add(parser, atom);
2445     if (!ale)
2446         return false;
2447
2448     cookie->set(0, globalUses.length());
2449
2450     GlobalSlotArray::Entry entry = { ALE_INDEX(ale), slot };
2451     if (!globalUses.append(entry))
2452         return false;
2453
2454     ale = globalMap.add(parser, atom);
2455     if (!ale)
2456         return false;
2457
2458     ALE_SET_INDEX(ale, cookie->asInteger());
2459     return true;
2460 }
2461
2462 /*
2463  * If pn contains a useful expression, return true with *answer set to true.
2464  * If pn contains a useless expression, return true with *answer set to false.
2465  * Return false on error.
2466  *
2467  * The caller should initialize *answer to false and invoke this function on
2468  * an expression statement or similar subtree to decide whether the tree could
2469  * produce code that has any side effects.  For an expression statement, we
2470  * define useless code as code with no side effects, because the main effect,
2471  * the value left on the stack after the code executes, will be discarded by a
2472  * pop bytecode.
2473  */
2474 static JSBool
2475 CheckSideEffects(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
2476                  JSBool *answer)
2477 {
2478     JSBool ok;
2479     JSParseNode *pn2;
2480
2481     ok = JS_TRUE;
2482     if (!pn || *answer)
2483         return ok;
2484
2485     switch (pn->pn_arity) {
2486       case PN_FUNC:
2487         /*
2488          * A named function, contrary to ES3, is no longer useful, because we
2489          * bind its name lexically (using JSOP_CALLEE) instead of creating an
2490          * Object instance and binding a readonly, permanent property in it
2491          * (the object and binding can be detected and hijacked or captured).
2492          * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
2493          */
2494         *answer = JS_FALSE;
2495         break;
2496
2497       case PN_LIST:
2498         if (pn->pn_op == JSOP_NOP ||
2499             pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
2500             pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
2501             /*
2502              * Non-operators along with ||, &&, ===, and !== never invoke
2503              * toString or valueOf.
2504              */
2505             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
2506                 ok &= CheckSideEffects(cx, cg, pn2, answer);
2507         } else {
2508             /*
2509              * All invocation operations (construct: TOK_NEW, call: TOK_LP)
2510              * are presumed to be useful, because they may have side effects
2511              * even if their main effect (their return value) is discarded.
2512              *
2513              * TOK_LB binary trees of 3 or more nodes are flattened into lists
2514              * to avoid too much recursion.  All such lists must be presumed
2515              * to be useful because each index operation could invoke a getter
2516              * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,
2517              * does not apply here: arguments[i][j] might invoke a getter).
2518              *
2519              * Likewise, array and object initialisers may call prototype
2520              * setters (the __defineSetter__ built-in, and writable __proto__
2521              * on Array.prototype create this hazard). Initialiser list nodes
2522              * have JSOP_NEWINIT in their pn_op.
2523              */
2524             *answer = JS_TRUE;
2525         }
2526         break;
2527
2528       case PN_TERNARY:
2529         ok = CheckSideEffects(cx, cg, pn->pn_kid1, answer) &&
2530              CheckSideEffects(cx, cg, pn->pn_kid2, answer) &&
2531              CheckSideEffects(cx, cg, pn->pn_kid3, answer);
2532         break;
2533
2534       case PN_BINARY:
2535         if (pn->pn_type == TOK_ASSIGN) {
2536             /*
2537              * Assignment is presumed to be useful, even if the next operation
2538              * is another assignment overwriting this one's ostensible effect,
2539              * because the left operand may be a property with a setter that
2540              * has side effects.
2541              *
2542              * The only exception is assignment of a useless value to a const
2543              * declared in the function currently being compiled.
2544              */
2545             pn2 = pn->pn_left;
2546             if (pn2->pn_type != TOK_NAME) {
2547                 *answer = JS_TRUE;
2548             } else {
2549                 if (!BindNameToSlot(cx, cg, pn2))
2550                     return JS_FALSE;
2551                 if (!CheckSideEffects(cx, cg, pn->pn_right, answer))
2552                     return JS_FALSE;
2553                 if (!*answer && (pn->pn_op != JSOP_NOP || !pn2->isConst()))
2554                     *answer = JS_TRUE;
2555             }
2556         } else {
2557             if (pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
2558                 pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
2559                 /*
2560                  * ||, &&, ===, and !== do not convert their operands via
2561                  * toString or valueOf method calls.
2562                  */
2563                 ok = CheckSideEffects(cx, cg, pn->pn_left, answer) &&
2564                      CheckSideEffects(cx, cg, pn->pn_right, answer);
2565             } else {
2566                 /*
2567                  * We can't easily prove that neither operand ever denotes an
2568                  * object with a toString or valueOf method.
2569                  */
2570                 *answer = JS_TRUE;
2571             }
2572         }
2573         break;
2574
2575       case PN_UNARY:
2576         switch (pn->pn_type) {
2577           case TOK_DELETE:
2578             pn2 = pn->pn_kid;
2579             switch (pn2->pn_type) {
2580               case TOK_NAME:
2581                 if (!BindNameToSlot(cx, cg, pn2))
2582                     return JS_FALSE;
2583                 if (pn2->isConst()) {
2584                     *answer = JS_FALSE;
2585                     break;
2586                 }
2587                 /* FALL THROUGH */
2588               case TOK_DOT:
2589 #if JS_HAS_XML_SUPPORT
2590               case TOK_DBLDOT:
2591 #endif
2592               case TOK_LP:
2593               case TOK_LB:
2594                 /* All these delete addressing modes have effects too. */
2595                 *answer = JS_TRUE;
2596                 break;
2597               default:
2598                 ok = CheckSideEffects(cx, cg, pn2, answer);
2599                 break;
2600             }
2601             break;
2602
2603           case TOK_UNARYOP:
2604             if (pn->pn_op == JSOP_NOT) {
2605                 /* ! does not convert its operand via toString or valueOf. */
2606                 ok = CheckSideEffects(cx, cg, pn->pn_kid, answer);
2607                 break;
2608             }
2609             /* FALL THROUGH */
2610
2611           default:
2612             /*
2613              * All of TOK_INC, TOK_DEC, TOK_THROW, TOK_YIELD, and TOK_DEFSHARP
2614              * have direct effects. Of the remaining unary-arity node types,
2615              * we can't easily prove that the operand never denotes an object
2616              * with a toString or valueOf method.
2617              */
2618             *answer = JS_TRUE;
2619             break;
2620         }
2621         break;
2622
2623       case PN_NAME:
2624         /*
2625          * Take care to avoid trying to bind a label name (labels, both for
2626          * statements and property values in object initialisers, have pn_op
2627          * defaulted to JSOP_NOP).
2628          */
2629         if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) {
2630             if (!BindNameToSlot(cx, cg, pn))
2631                 return JS_FALSE;
2632             if (pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE &&
2633                 pn->pn_cookie.isFree()) {
2634                 /*
2635                  * Not an argument or local variable use, and not a use of a
2636                  * unshadowed named function expression's given name, so this
2637                  * expression could invoke a getter that has side effects.
2638                  */
2639                 *answer = JS_TRUE;
2640             }
2641         }
2642         pn2 = pn->maybeExpr();
2643         if (pn->pn_type == TOK_DOT) {
2644             if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2))
2645                 return JS_FALSE;
2646             if (!(pn2->pn_op == JSOP_ARGUMENTS &&
2647                   pn->pn_atom == cx->runtime->atomState.lengthAtom)) {
2648                 /*
2649                  * Any dotted property reference could call a getter, except
2650                  * for arguments.length where arguments is unambiguous.
2651                  */
2652                 *answer = JS_TRUE;
2653             }
2654         }
2655         ok = CheckSideEffects(cx, cg, pn2, answer);
2656         break;
2657
2658       case PN_NAMESET:
2659         ok = CheckSideEffects(cx, cg, pn->pn_tree, answer);
2660         break;
2661
2662       case PN_NULLARY:
2663         if (pn->pn_type == TOK_DEBUGGER)
2664             *answer = JS_TRUE;
2665         break;
2666     }
2667     return ok;
2668 }
2669
2670 static JSBool
2671 EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
2672            JSBool callContext)
2673 {
2674     JSOp op;
2675
2676     if (!BindNameToSlot(cx, cg, pn))
2677         return JS_FALSE;
2678     op = PN_OP(pn);
2679
2680     if (callContext) {
2681         switch (op) {
2682           case JSOP_NAME:
2683             op = JSOP_CALLNAME;
2684             break;
2685           case JSOP_GETGNAME:
2686             op = JSOP_CALLGNAME;
2687             break;
2688           case JSOP_GETGLOBAL:
2689             op = JSOP_CALLGLOBAL;
2690             break;
2691           case JSOP_GETARG:
2692             op = JSOP_CALLARG;
2693             break;
2694           case JSOP_GETLOCAL:
2695             op = JSOP_CALLLOCAL;
2696             break;
2697           case JSOP_GETFCSLOT:
2698             op = JSOP_CALLFCSLOT;
2699             break;
2700           default:
2701             JS_ASSERT(op == JSOP_ARGUMENTS || op == JSOP_CALLEE);
2702             break;
2703         }
2704     }
2705
2706     if (op == JSOP_ARGUMENTS || op == JSOP_CALLEE) {
2707         if (js_Emit1(cx, cg, op) < 0)
2708             return JS_FALSE;
2709         if (callContext && js_Emit1(cx, cg, JSOP_PUSH) < 0)
2710             return JS_FALSE;
2711     } else {
2712         if (!pn->pn_cookie.isFree()) {
2713             EMIT_UINT16_IMM_OP(op, pn->pn_cookie.asInteger());
2714         } else {
2715             if (!EmitAtomOp(cx, pn, op, cg))
2716                 return JS_FALSE;
2717         }
2718     }
2719
2720     return JS_TRUE;
2721 }
2722
2723 #if JS_HAS_XML_SUPPORT
2724 static JSBool
2725 EmitXMLName(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
2726 {
2727     JSParseNode *pn2;
2728     uintN oldflags;
2729
2730     JS_ASSERT(pn->pn_type == TOK_UNARYOP);
2731     JS_ASSERT(pn->pn_op == JSOP_XMLNAME);
2732     JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME);
2733
2734     pn2 = pn->pn_kid;
2735     oldflags = cg->flags;
2736     cg->flags &= ~TCF_IN_FOR_INIT;
2737     if (!js_EmitTree(cx, cg, pn2))
2738         return JS_FALSE;
2739     cg->flags |= oldflags & TCF_IN_FOR_INIT;
2740     if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
2741                        CG_OFFSET(cg) - pn2->pn_offset) < 0) {
2742         return JS_FALSE;
2743     }
2744
2745     return js_Emit1(cx, cg, op) >= 0;
2746 }
2747 #endif
2748
2749 static JSBool
2750 EmitSpecialPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
2751 {
2752     /*
2753      * Special case for obj.__proto__ to deoptimize away from fast paths in the
2754      * interpreter and trace recorder, which skip dense array instances by
2755      * going up to Array.prototype before looking up the property name.
2756      */
2757     JSAtomListElement *ale = cg->atomList.add(cg->parser, pn->pn_atom);
2758     if (!ale)
2759         return JS_FALSE;
2760     if (!EmitIndexOp(cx, JSOP_QNAMEPART, ALE_INDEX(ale), cg))
2761         return JS_FALSE;
2762     if (js_Emit1(cx, cg, op) < 0)
2763         return JS_FALSE;
2764     return JS_TRUE;
2765 }
2766
2767 static JSBool
2768 EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
2769            JSBool callContext)
2770 {
2771     JSParseNode *pn2, *pndot, *pnup, *pndown;
2772     ptrdiff_t top;
2773
2774     JS_ASSERT(pn->pn_arity == PN_NAME);
2775     pn2 = pn->maybeExpr();
2776
2777     /* Special case deoptimization for __proto__. */
2778     if ((op == JSOP_GETPROP || op == JSOP_CALLPROP) &&
2779         pn->pn_atom == cx->runtime->atomState.protoAtom) {
2780         if (pn2 && !js_EmitTree(cx, cg, pn2))
2781             return JS_FALSE;
2782         return EmitSpecialPropOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, cg);
2783     }
2784
2785     if (callContext) {
2786         JS_ASSERT(pn->pn_type == TOK_DOT);
2787         JS_ASSERT(op == JSOP_GETPROP);
2788         op = JSOP_CALLPROP;
2789     } else if (op == JSOP_GETPROP && pn->pn_type == TOK_DOT) {
2790         if (pn2->pn_op == JSOP_THIS) {
2791             if (pn->pn_atom != cx->runtime->atomState.lengthAtom) {
2792                 /* Fast path for gets of |this.foo|. */
2793                 return EmitAtomOp(cx, pn, JSOP_GETTHISPROP, cg);
2794             }
2795         } else if (pn2->pn_type == TOK_NAME) {
2796             /*
2797              * Try to optimize:
2798              *  - arguments.length into JSOP_ARGCNT
2799              *  - argname.prop into JSOP_GETARGPROP
2800              *  - localname.prop into JSOP_GETLOCALPROP
2801              * but don't do this if the property is 'length' -- prefer to emit
2802              * JSOP_GETARG, etc., and then JSOP_LENGTH.
2803              */
2804             if (!BindNameToSlot(cx, cg, pn2))
2805                 return JS_FALSE;
2806             if (pn->pn_atom == cx->runtime->atomState.lengthAtom) {
2807                 if (pn2->pn_op == JSOP_ARGUMENTS)
2808                     return js_Emit1(cx, cg, JSOP_ARGCNT) >= 0;
2809             } else {
2810                 switch (pn2->pn_op) {
2811                   case JSOP_GETARG:
2812                     op = JSOP_GETARGPROP;
2813                     goto do_indexconst;
2814                   case JSOP_GETLOCAL:
2815                     op = JSOP_GETLOCALPROP;
2816                   do_indexconst: {
2817                         JSAtomListElement *ale;
2818                         jsatomid atomIndex;
2819
2820                         ale = cg->atomList.add(cg->parser, pn->pn_atom);
2821                         if (!ale)
2822                             return JS_FALSE;
2823                         atomIndex = ALE_INDEX(ale);
2824                         return EmitSlotIndexOp(cx, op, pn2->pn_cookie.asInteger(), atomIndex, cg);
2825                     }
2826
2827                   default:;
2828                 }
2829             }
2830         }
2831     }
2832
2833     /*
2834      * If the object operand is also a dotted property reference, reverse the
2835      * list linked via pn_expr temporarily so we can iterate over it from the
2836      * bottom up (reversing again as we go), to avoid excessive recursion.
2837      */
2838     if (pn2->pn_type == TOK_DOT) {
2839         pndot = pn2;
2840         pnup = NULL;
2841         top = CG_OFFSET(cg);
2842         for (;;) {
2843             /* Reverse pndot->pn_expr to point up, not down. */
2844             pndot->pn_offset = top;
2845             JS_ASSERT(!pndot->pn_used);
2846             pndown = pndot->pn_expr;
2847             pndot->pn_expr = pnup;
2848             if (pndown->pn_type != TOK_DOT)
2849                 break;
2850             pnup = pndot;
2851             pndot = pndown;
2852         }
2853
2854         /* pndown is a primary expression, not a dotted property reference. */
2855         if (!js_EmitTree(cx, cg, pndown))
2856             return JS_FALSE;
2857
2858         do {
2859             /* Walk back up the list, emitting annotated name ops. */
2860             if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
2861                                CG_OFFSET(cg) - pndown->pn_offset) < 0) {
2862                 return JS_FALSE;
2863             }
2864
2865             /* Special case deoptimization on __proto__, as above. */
2866             if (pndot->pn_arity == PN_NAME && pndot->pn_atom == cx->runtime->atomState.protoAtom) {
2867                 if (!EmitSpecialPropOp(cx, pndot, JSOP_GETELEM, cg))
2868                     return JS_FALSE;
2869             } else if (!EmitAtomOp(cx, pndot, PN_OP(pndot), cg)) {
2870                 return JS_FALSE;
2871             }
2872
2873             /* Reverse the pn_expr link again. */
2874             pnup = pndot->pn_expr;
2875             pndot->pn_expr = pndown;
2876             pndown = pndot;
2877         } while ((pndot = pnup) != NULL);
2878     } else {
2879         if (!js_EmitTree(cx, cg, pn2))
2880             return JS_FALSE;
2881     }
2882
2883     if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
2884                        CG_OFFSET(cg) - pn2->pn_offset) < 0) {
2885         return JS_FALSE;
2886     }
2887
2888     return EmitAtomOp(cx, pn, op, cg);
2889 }
2890
2891 static JSBool
2892 EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
2893 {
2894     ptrdiff_t top;
2895     JSParseNode *left, *right, *next, ltmp, rtmp;
2896     int32_t slot;
2897
2898     top = CG_OFFSET(cg);
2899     if (pn->pn_arity == PN_LIST) {
2900         /* Left-associative operator chain to avoid too much recursion. */
2901         JS_ASSERT(pn->pn_op == JSOP_GETELEM);
2902         JS_ASSERT(pn->pn_count >= 3);
2903         left = pn->pn_head;
2904         right = pn->last();
2905         next = left->pn_next;
2906         JS_ASSERT(next != right);
2907
2908         /*
2909          * Try to optimize arguments[0][j]... into JSOP_ARGSUB<0> followed by
2910          * one or more index expression and JSOP_GETELEM op pairs.
2911          */
2912         if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) {
2913             if (!BindNameToSlot(cx, cg, left))
2914                 return JS_FALSE;
2915             if (left->pn_op == JSOP_ARGUMENTS &&
2916                 JSDOUBLE_IS_INT32(next->pn_dval, &slot) &&
2917                 jsuint(slot) < JS_BIT(16) &&
2918                 (!cg->inStrictMode() ||
2919                  (!cg->mutatesParameter() && !cg->callsEval()))) {
2920                 /*
2921                  * arguments[i]() requires arguments object as "this".
2922                  * Check that we never generates list for that usage.
2923                  */
2924                 JS_ASSERT(op != JSOP_CALLELEM || next->pn_next);
2925                 left->pn_offset = next->pn_offset = top;
2926                 EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
2927                 left = next;
2928                 next = left->pn_next;
2929             }
2930         }
2931
2932         /*
2933          * Check whether we generated JSOP_ARGSUB, just above, and have only
2934          * one more index expression to emit.  Given arguments[0][j], we must
2935          * skip the while loop altogether, falling through to emit code for j
2936          * (in the subtree referenced by right), followed by the annotated op,
2937          * at the bottom of this function.
2938          */
2939         JS_ASSERT(next != right || pn->pn_count == 3);
2940         if (left == pn->pn_head) {
2941             if (!js_EmitTree(cx, cg, left))
2942                 return JS_FALSE;
2943         }
2944         while (next != right) {
2945             if (!js_EmitTree(cx, cg, next))
2946                 return JS_FALSE;
2947             if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
2948                 return JS_FALSE;
2949             if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
2950                 return JS_FALSE;
2951             next = next->pn_next;
2952         }
2953     } else {
2954         if (pn->pn_arity == PN_NAME) {
2955             /*
2956              * Set left and right so pn appears to be a TOK_LB node, instead
2957              * of a TOK_DOT node.  See the TOK_FOR/IN case in js_EmitTree, and
2958              * EmitDestructuringOps nearer below.  In the destructuring case,
2959              * the base expression (pn_expr) of the name may be null, which
2960              * means we have to emit a JSOP_BINDNAME.
2961              */
2962             left = pn->maybeExpr();
2963             if (!left) {
2964                 left = &ltmp;
2965                 left->pn_type = TOK_STRING;
2966                 left->pn_op = JSOP_BINDNAME;
2967                 left->pn_arity = PN_NULLARY;
2968                 left->pn_pos = pn->pn_pos;
2969                 left->pn_atom = pn->pn_atom;
2970             }
2971             right = &rtmp;
2972             right->pn_type = TOK_STRING;
2973             right->pn_op = js_IsIdentifier(ATOM_TO_STRING(pn->pn_atom))
2974                            ? JSOP_QNAMEPART
2975                            : JSOP_STRING;
2976             right->pn_arity = PN_NULLARY;
2977             right->pn_pos = pn->pn_pos;
2978             right->pn_atom = pn->pn_atom;
2979         } else {
2980             JS_ASSERT(pn->pn_arity == PN_BINARY);
2981             left = pn->pn_left;
2982             right = pn->pn_right;
2983         }
2984
2985         /* Try to optimize arguments[0] (e.g.) into JSOP_ARGSUB<0>. */
2986         if (op == JSOP_GETELEM &&
2987             left->pn_type == TOK_NAME &&
2988             right->pn_type == TOK_NUMBER) {
2989             if (!BindNameToSlot(cx, cg, left))
2990                 return JS_FALSE;
2991             if (left->pn_op == JSOP_ARGUMENTS &&
2992                 JSDOUBLE_IS_INT32(right->pn_dval, &slot) &&
2993                 jsuint(slot) < JS_BIT(16) &&
2994                 (!cg->inStrictMode() ||
2995                  (!cg->mutatesParameter() && !cg->callsEval()))) {
2996                 left->pn_offset = right->pn_offset = top;
2997                 EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
2998                 return JS_TRUE;
2999             }
3000         }
3001
3002         if (!js_EmitTree(cx, cg, left))
3003             return JS_FALSE;
3004     }
3005
3006     /* The right side of the descendant operator is implicitly quoted. */
3007     JS_ASSERT(op != JSOP_DESCENDANTS || right->pn_type != TOK_STRING ||
3008               right->pn_op == JSOP_QNAMEPART);
3009     if (!js_EmitTree(cx, cg, right))
3010         return JS_FALSE;
3011     if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
3012         return JS_FALSE;
3013     return js_Emit1(cx, cg, op) >= 0;
3014 }
3015
3016 static JSBool
3017 EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg)
3018 {
3019     int32_t ival;
3020     uint32 u;
3021     ptrdiff_t off;
3022     jsbytecode *pc;
3023
3024     if (JSDOUBLE_IS_INT32(dval, &ival)) {
3025         if (ival == 0)
3026             return js_Emit1(cx, cg, JSOP_ZERO) >= 0;
3027         if (ival == 1)
3028             return js_Emit1(cx, cg, JSOP_ONE) >= 0;
3029         if ((jsint)(int8)ival == ival)
3030             return js_Emit2(cx, cg, JSOP_INT8, (jsbytecode)(int8)ival) >= 0;
3031
3032         u = (uint32)ival;
3033         if (u < JS_BIT(16)) {
3034             EMIT_UINT16_IMM_OP(JSOP_UINT16, u);
3035         } else if (u < JS_BIT(24)) {
3036             off = js_EmitN(cx, cg, JSOP_UINT24, 3);
3037             if (off < 0)
3038                 return JS_FALSE;
3039             pc = CG_CODE(cg, off);
3040             SET_UINT24(pc, u);
3041         } else {
3042             off = js_EmitN(cx, cg, JSOP_INT32, 4);
3043             if (off < 0)
3044                 return JS_FALSE;
3045             pc = CG_CODE(cg, off);
3046             SET_INT32(pc, ival);
3047         }
3048         return JS_TRUE;
3049     }
3050
3051     if (!cg->constList.append(DoubleValue(dval)))
3052         return JS_FALSE;
3053
3054     return EmitIndexOp(cx, JSOP_DOUBLE, cg->constList.length() - 1, cg);
3055 }
3056
3057 /*
3058  * To avoid bloating all parse nodes for the special case of switch, values are
3059  * allocated in the temp pool and pointed to by the parse node. These values
3060  * are not currently recycled (like parse nodes) and the temp pool is only
3061  * flushed at the end of compiling a script, so these values are technically
3062  * leaked. This would only be a problem for scripts containing a large number
3063  * of large switches, which seems unlikely.
3064  */
3065 static Value *
3066 AllocateSwitchConstant(JSContext *cx)
3067 {
3068     Value *pv;
3069     JS_ARENA_ALLOCATE_TYPE(pv, Value, &cx->tempPool);
3070     return pv;
3071 }
3072
3073 static JSBool
3074 EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
3075            JSStmtInfo *stmtInfo)
3076 {
3077     JSOp switchOp;
3078     JSBool ok, hasDefault, constPropagated;
3079     ptrdiff_t top, off, defaultOffset;
3080     JSParseNode *pn2, *pn3, *pn4;
3081     uint32 caseCount, tableLength;
3082     JSParseNode **table;
3083     int32_t i, low, high;
3084     JSAtomListElement *ale;
3085     intN noteIndex;
3086     size_t switchSize, tableSize;
3087     jsbytecode *pc, *savepc;
3088 #if JS_HAS_BLOCK_SCOPE
3089     JSObjectBox *box;
3090 #endif
3091
3092     /* Try for most optimal, fall back if not dense ints, and per ECMAv2. */
3093     switchOp = JSOP_TABLESWITCH;
3094     ok = JS_TRUE;
3095     hasDefault = constPropagated = JS_FALSE;
3096     defaultOffset = -1;
3097
3098     /*
3099      * If the switch contains let variables scoped by its body, model the
3100      * resulting block on the stack first, before emitting the discriminant's
3101      * bytecode (in case the discriminant contains a stack-model dependency
3102      * such as a let expression).
3103      */
3104     pn2 = pn->pn_right;
3105 #if JS_HAS_BLOCK_SCOPE
3106     if (pn2->pn_type == TOK_LEXICALSCOPE) {
3107         /*
3108          * Push the body's block scope before discriminant code-gen for proper
3109          * static block scope linkage in case the discriminant contains a let
3110          * expression.  The block's locals must lie under the discriminant on
3111          * the stack so that case-dispatch bytecodes can find the discriminant
3112          * on top of stack.
3113          */
3114         box = pn2->pn_objbox;
3115         js_PushBlockScope(cg, stmtInfo, box, -1);
3116         stmtInfo->type = STMT_SWITCH;
3117
3118         /* Emit JSOP_ENTERBLOCK before code to evaluate the discriminant. */
3119         if (!EmitEnterBlock(cx, pn2, cg))
3120             return JS_FALSE;
3121
3122         /*
3123          * Pop the switch's statement info around discriminant code-gen.  Note
3124          * how this leaves cg->blockChain referencing the switch's
3125          * block scope object, which is necessary for correct block parenting
3126          * in the case where the discriminant contains a let expression.
3127          */
3128         cg->topStmt = stmtInfo->down;
3129         cg->topScopeStmt = stmtInfo->downScope;
3130     }
3131 #ifdef __GNUC__
3132     else {
3133         box = NULL;
3134     }
3135 #endif
3136 #endif
3137
3138     /*
3139      * Emit code for the discriminant first (or nearly first, in the case of a
3140      * switch whose body is a block scope).
3141      */
3142     if (!js_EmitTree(cx, cg, pn->pn_left))
3143         return JS_FALSE;
3144
3145     /* Switch bytecodes run from here till end of final case. */
3146     top = CG_OFFSET(cg);
3147 #if !JS_HAS_BLOCK_SCOPE
3148     js_PushStatement(cg, stmtInfo, STMT_SWITCH, top);
3149 #else
3150     if (pn2->pn_type == TOK_LC) {
3151         js_PushStatement(cg, stmtInfo, STMT_SWITCH, top);
3152     } else {
3153         /* Re-push the switch's statement info record. */
3154         cg->topStmt = cg->topScopeStmt = stmtInfo;
3155         cg->blockChainBox = stmtInfo->blockBox;
3156
3157         /* Set the statement info record's idea of top. */
3158         stmtInfo->update = top;
3159
3160         /* Advance pn2 to refer to the switch case list. */
3161         pn2 = pn2->expr();
3162     }
3163 #endif
3164
3165     caseCount = pn2->pn_count;
3166     tableLength = 0;
3167     table = NULL;
3168
3169     if (caseCount == 0 ||
3170         (caseCount == 1 &&
3171          (hasDefault = (pn2->pn_head->pn_type == TOK_DEFAULT)))) {
3172         caseCount = 0;
3173         low = 0;
3174         high = -1;
3175     } else {
3176 #define INTMAP_LENGTH   256
3177         jsbitmap intmap_space[INTMAP_LENGTH];
3178         jsbitmap *intmap = NULL;
3179         int32 intmap_bitlen = 0;
3180
3181         low  = JSVAL_INT_MAX;
3182         high = JSVAL_INT_MIN;
3183
3184         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
3185             if (pn3->pn_type == TOK_DEFAULT) {
3186                 hasDefault = JS_TRUE;
3187                 caseCount--;    /* one of the "cases" was the default */
3188                 continue;
3189             }
3190
3191             JS_ASSERT(pn3->pn_type == TOK_CASE);
3192             if (switchOp == JSOP_CONDSWITCH)
3193                 continue;
3194
3195             pn4 = pn3->pn_left;
3196             while (pn4->pn_type == TOK_RP)
3197                 pn4 = pn4->pn_kid;
3198
3199             Value constVal;
3200             switch (pn4->pn_type) {
3201               case TOK_NUMBER:
3202                 constVal.setNumber(pn4->pn_dval);
3203                 break;
3204               case TOK_STRING:
3205                 constVal.setString(ATOM_TO_STRING(pn4->pn_atom));
3206                 break;
3207               case TOK_NAME:
3208                 if (!pn4->maybeExpr()) {
3209                     ok = LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &constVal);
3210                     if (!ok)
3211                         goto release;
3212                     if (!constVal.isMagic(JS_NO_CONSTANT)) {
3213                         if (constVal.isObject()) {
3214                             /*
3215                              * XXX JSOP_LOOKUPSWITCH does not support const-
3216                              * propagated object values, see bug 407186.
3217                              */
3218                             switchOp = JSOP_CONDSWITCH;
3219                             continue;
3220                         }
3221                         constPropagated = JS_TRUE;
3222                         break;
3223                     }
3224                 }
3225                 /* FALL THROUGH */
3226               case TOK_PRIMARY:
3227                 if (pn4->pn_op == JSOP_TRUE) {
3228                     constVal.setBoolean(true);
3229                     break;
3230                 }
3231                 if (pn4->pn_op == JSOP_FALSE) {
3232                     constVal.setBoolean(false);
3233                     break;
3234                 }
3235                 if (pn4->pn_op == JSOP_NULL) {
3236                     constVal.setNull();
3237                     break;
3238                 }
3239                 /* FALL THROUGH */
3240               default:
3241                 switchOp = JSOP_CONDSWITCH;
3242                 continue;
3243             }
3244             JS_ASSERT(constVal.isPrimitive());
3245
3246             pn3->pn_pval = AllocateSwitchConstant(cx);
3247             if (!pn3->pn_pval) {
3248                 ok = JS_FALSE;
3249                 goto release;
3250             }
3251
3252             *pn3->pn_pval = constVal;
3253
3254             if (switchOp != JSOP_TABLESWITCH)
3255                 continue;
3256             if (!pn3->pn_pval->isInt32()) {
3257                 switchOp = JSOP_LOOKUPSWITCH;
3258                 continue;
3259             }
3260             i = pn3->pn_pval->toInt32();
3261             if ((jsuint)(i + (jsint)JS_BIT(15)) >= (jsuint)JS_BIT(16)) {
3262                 switchOp = JSOP_LOOKUPSWITCH;
3263                 continue;
3264             }
3265             if (i < low)
3266                 low = i;
3267             if (high < i)
3268                 high = i;
3269
3270             /*
3271              * Check for duplicates, which require a JSOP_LOOKUPSWITCH.
3272              * We bias i by 65536 if it's negative, and hope that's a rare
3273              * case (because it requires a malloc'd bitmap).
3274              */
3275             if (i < 0)
3276                 i += JS_BIT(16);
3277             if (i >= intmap_bitlen) {
3278                 if (!intmap &&
3279                     i < (INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2)) {
3280                     intmap = intmap_space;
3281                     intmap_bitlen = INTMAP_LENGTH << JS_BITS_PER_WORD_LOG2;
3282                 } else {
3283                     /* Just grab 8K for the worst-case bitmap. */
3284                     intmap_bitlen = JS_BIT(16);
3285                     intmap = (jsbitmap *)
3286                         cx->malloc((JS_BIT(16) >> JS_BITS_PER_WORD_LOG2)
3287                                    * sizeof(jsbitmap));
3288                     if (!intmap) {
3289                         JS_ReportOutOfMemory(cx);
3290                         return JS_FALSE;
3291                     }
3292                 }
3293                 memset(intmap, 0, intmap_bitlen >> JS_BITS_PER_BYTE_LOG2);
3294             }
3295             if (JS_TEST_BIT(intmap, i)) {
3296                 switchOp = JSOP_LOOKUPSWITCH;
3297                 continue;
3298             }
3299             JS_SET_BIT(intmap, i);
3300         }
3301
3302       release:
3303         if (intmap && intmap != intmap_space)
3304             cx->free(intmap);
3305         if (!ok)
3306             return JS_FALSE;
3307
3308         /*
3309          * Compute table length and select lookup instead if overlarge or
3310          * more than half-sparse.
3311          */
3312         if (switchOp == JSOP_TABLESWITCH) {
3313             tableLength = (uint32)(high - low + 1);
3314             if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount)
3315                 switchOp = JSOP_LOOKUPSWITCH;
3316         } else if (switchOp == JSOP_LOOKUPSWITCH) {
3317             /*
3318              * Lookup switch supports only atom indexes below 64K limit.
3319              * Conservatively estimate the maximum possible index during
3320              * switch generation and use conditional switch if it exceeds
3321              * the limit.
3322              */
3323             if (caseCount + cg->constList.length() > JS_BIT(16))
3324                 switchOp = JSOP_CONDSWITCH;
3325         }
3326     }
3327
3328     /*
3329      * Emit a note with two offsets: first tells total switch code length,
3330      * second tells offset to first JSOP_CASE if condswitch.
3331      */
3332     noteIndex = js_NewSrcNote3(cx, cg, SRC_SWITCH, 0, 0);
3333     if (noteIndex < 0)
3334         return JS_FALSE;
3335
3336     if (switchOp == JSOP_CONDSWITCH) {
3337         /*
3338          * 0 bytes of immediate for unoptimized ECMAv2 switch.
3339          */
3340         switchSize = 0;
3341     } else if (switchOp == JSOP_TABLESWITCH) {
3342         /*
3343          * 3 offsets (len, low, high) before the table, 1 per entry.
3344          */
3345         switchSize = (size_t)(JUMP_OFFSET_LEN * (3 + tableLength));
3346     } else {
3347         /*
3348          * JSOP_LOOKUPSWITCH:
3349          * 1 offset (len) and 1 atom index (npairs) before the table,
3350          * 1 atom index and 1 jump offset per entry.
3351          */
3352         switchSize = (size_t)(JUMP_OFFSET_LEN + INDEX_LEN +
3353                               (INDEX_LEN + JUMP_OFFSET_LEN) * caseCount);
3354     }
3355
3356     /*
3357      * Emit switchOp followed by switchSize bytes of jump or lookup table.
3358      *
3359      * If switchOp is JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH, it is crucial
3360      * to emit the immediate operand(s) by which bytecode readers such as
3361      * BuildSpanDepTable discover the length of the switch opcode *before*
3362      * calling js_SetJumpOffset (which may call BuildSpanDepTable).  It's
3363      * also important to zero all unknown jump offset immediate operands,
3364      * so they can be converted to span dependencies with null targets to
3365      * be computed later (js_EmitN zeros switchSize bytes after switchOp).
3366      */
3367     if (js_EmitN(cx, cg, switchOp, switchSize) < 0)
3368         return JS_FALSE;
3369
3370     off = -1;
3371     if (switchOp == JSOP_CONDSWITCH) {
3372         intN caseNoteIndex = -1;
3373         JSBool beforeCases = JS_TRUE;
3374
3375         /* Emit code for evaluating cases and jumping to case statements. */
3376         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
3377             pn4 = pn3->pn_left;
3378             if (pn4 && !js_EmitTree(cx, cg, pn4))
3379                 return JS_FALSE;
3380             if (caseNoteIndex >= 0) {
3381                 /* off is the previous JSOP_CASE's bytecode offset. */
3382                 if (!js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0,
3383                                          CG_OFFSET(cg) - off)) {
3384                     return JS_FALSE;
3385                 }
3386             }
3387             if (!pn4) {
3388                 JS_ASSERT(pn3->pn_type == TOK_DEFAULT);
3389                 continue;
3390             }
3391             caseNoteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
3392             if (caseNoteIndex < 0)
3393                 return JS_FALSE;
3394             off = EmitJump(cx, cg, JSOP_CASE, 0);
3395             if (off < 0)
3396                 return JS_FALSE;
3397             pn3->pn_offset = off;
3398             if (beforeCases) {
3399                 uintN noteCount, noteCountDelta;
3400
3401                 /* Switch note's second offset is to first JSOP_CASE. */
3402                 noteCount = CG_NOTE_COUNT(cg);
3403                 if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,
3404                                          off - top)) {
3405                     return JS_FALSE;
3406                 }
3407                 noteCountDelta = CG_NOTE_COUNT(cg) - noteCount;
3408                 if (noteCountDelta != 0)
3409                     caseNoteIndex += noteCountDelta;
3410                 beforeCases = JS_FALSE;
3411             }
3412         }
3413
3414         /*
3415          * If we didn't have an explicit default (which could fall in between
3416          * cases, preventing us from fusing this js_SetSrcNoteOffset with the
3417          * call in the loop above), link the last case to the implicit default
3418          * for the decompiler.
3419          */
3420         if (!hasDefault &&
3421             caseNoteIndex >= 0 &&
3422             !js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0,
3423                                  CG_OFFSET(cg) - off)) {
3424             return JS_FALSE;
3425         }
3426
3427         /* Emit default even if no explicit default statement. */
3428         defaultOffset = EmitJump(cx, cg, JSOP_DEFAULT, 0);
3429         if (defaultOffset < 0)
3430             return JS_FALSE;
3431     } else {
3432         pc = CG_CODE(cg, top + JUMP_OFFSET_LEN);
3433
3434         if (switchOp == JSOP_TABLESWITCH) {
3435             /* Fill in switch bounds, which we know fit in 16-bit offsets. */
3436             SET_JUMP_OFFSET(pc, low);
3437             pc += JUMP_OFFSET_LEN;
3438             SET_JUMP_OFFSET(pc, high);
3439             pc += JUMP_OFFSET_LEN;
3440
3441             /*
3442              * Use malloc to avoid arena bloat for programs with many switches.
3443              * We free table if non-null at label out, so all control flow must
3444              * exit this function through goto out or goto bad.
3445              */
3446             if (tableLength != 0) {
3447                 tableSize = (size_t)tableLength * sizeof *table;
3448                 table = (JSParseNode **) cx->malloc(tableSize);
3449                 if (!table)
3450                     return JS_FALSE;
3451                 memset(table, 0, tableSize);
3452                 for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
3453                     if (pn3->pn_type == TOK_DEFAULT)
3454                         continue;
3455                     i = pn3->pn_pval->toInt32();
3456                     i -= low;
3457                     JS_ASSERT((uint32)i < tableLength);
3458                     table[i] = pn3;
3459                 }
3460             }
3461         } else {
3462             JS_ASSERT(switchOp == JSOP_LOOKUPSWITCH);
3463
3464             /* Fill in the number of cases. */
3465             SET_INDEX(pc, caseCount);
3466             pc += INDEX_LEN;
3467         }
3468
3469         /*
3470          * After this point, all control flow involving JSOP_TABLESWITCH
3471          * must set ok and goto out to exit this function.  To keep things
3472          * simple, all switchOp cases exit that way.
3473          */
3474         MUST_FLOW_THROUGH("out");
3475         if (cg->spanDeps) {
3476             /*
3477              * We have already generated at least one big jump so we must
3478              * explicitly add span dependencies for the switch jumps. When
3479              * called below, js_SetJumpOffset can only do it when patching
3480              * the first big jump or when cg->spanDeps is null.
3481              */
3482             if (!AddSwitchSpanDeps(cx, cg, CG_CODE(cg, top)))
3483                 goto bad;
3484         }
3485
3486         if (constPropagated) {
3487             /*
3488              * Skip switchOp, as we are not setting jump offsets in the two
3489              * for loops below.  We'll restore CG_NEXT(cg) from savepc after,
3490              * unless there was an error.
3491              */
3492             savepc = CG_NEXT(cg);
3493             CG_NEXT(cg) = pc + 1;
3494             if (switchOp == JSOP_TABLESWITCH) {
3495                 for (i = 0; i < (jsint)tableLength; i++) {
3496                     pn3 = table[i];
3497                     if (pn3 &&
3498                         (pn4 = pn3->pn_left) != NULL &&
3499                         pn4->pn_type == TOK_NAME) {
3500                         /* Note a propagated constant with the const's name. */
3501                         JS_ASSERT(!pn4->maybeExpr());
3502                         ale = cg->atomList.add(cg->parser, pn4->pn_atom);
3503                         if (!ale)
3504                             goto bad;
3505                         CG_NEXT(cg) = pc;
3506                         if (js_NewSrcNote2(cx, cg, SRC_LABEL, (ptrdiff_t)
3507                                            ALE_INDEX(ale)) < 0) {
3508                             goto bad;
3509                         }
3510                     }
3511                     pc += JUMP_OFFSET_LEN;
3512                 }
3513             } else {
3514                 for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
3515                     pn4 = pn3->pn_left;
3516                     if (pn4 && pn4->pn_type == TOK_NAME) {
3517                         /* Note a propagated constant with the const's name. */
3518                         JS_ASSERT(!pn4->maybeExpr());
3519                         ale = cg->atomList.add(cg->parser, pn4->pn_atom);
3520                         if (!ale)
3521                             goto bad;
3522                         CG_NEXT(cg) = pc;
3523                         if (js_NewSrcNote2(cx, cg, SRC_LABEL, (ptrdiff_t)
3524                                            ALE_INDEX(ale)) < 0) {
3525                             goto bad;
3526                         }
3527                     }
3528                     pc += INDEX_LEN + JUMP_OFFSET_LEN;
3529                 }
3530             }
3531             CG_NEXT(cg) = savepc;
3532         }
3533     }
3534
3535     /* Emit code for each case's statements, copying pn_offset up to pn3. */
3536     for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
3537         if (switchOp == JSOP_CONDSWITCH && pn3->pn_type != TOK_DEFAULT)
3538             CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, pn3->pn_offset, goto bad);
3539         pn4 = pn3->pn_right;
3540         ok = js_EmitTree(cx, cg, pn4);
3541         if (!ok)
3542             goto out;
3543         pn3->pn_offset = pn4->pn_offset;
3544         if (pn3->pn_type == TOK_DEFAULT)
3545             off = pn3->pn_offset - top;
3546     }
3547
3548     if (!hasDefault) {
3549         /* If no default case, offset for default is to end of switch. */
3550         off = CG_OFFSET(cg) - top;
3551     }
3552
3553     /* We better have set "off" by now. */
3554     JS_ASSERT(off != -1);
3555
3556     /* Set the default offset (to end of switch if no default). */
3557     if (switchOp == JSOP_CONDSWITCH) {
3558         pc = NULL;
3559         JS_ASSERT(defaultOffset != -1);
3560         ok = js_SetJumpOffset(cx, cg, CG_CODE(cg, defaultOffset),
3561                               off - (defaultOffset - top));
3562         if (!ok)
3563             goto out;
3564     } else {
3565         pc = CG_CODE(cg, top);
3566         ok = js_SetJumpOffset(cx, cg, pc, off);
3567         if (!ok)
3568             goto out;
3569         pc += JUMP_OFFSET_LEN;
3570     }
3571
3572     /* Set the SRC_SWITCH note's offset operand to tell end of switch. */
3573     off = CG_OFFSET(cg) - top;
3574     ok = js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, off);
3575     if (!ok)
3576         goto out;
3577
3578     if (switchOp == JSOP_TABLESWITCH) {
3579         /* Skip over the already-initialized switch bounds. */
3580         pc += 2 * JUMP_OFFSET_LEN;
3581
3582         /* Fill in the jump table, if there is one. */
3583         for (i = 0; i < (jsint)tableLength; i++) {
3584             pn3 = table[i];
3585             off = pn3 ? pn3->pn_offset - top : 0;
3586             ok = js_SetJumpOffset(cx, cg, pc, off);
3587             if (!ok)
3588                 goto out;
3589             pc += JUMP_OFFSET_LEN;
3590         }
3591     } else if (switchOp == JSOP_LOOKUPSWITCH) {
3592         /* Skip over the already-initialized number of cases. */
3593         pc += INDEX_LEN;
3594
3595         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
3596             if (pn3->pn_type == TOK_DEFAULT)
3597                 continue;
3598             if (!cg->constList.append(*pn3->pn_pval))
3599                 goto bad;
3600             SET_INDEX(pc, cg->constList.length() - 1);
3601             pc += INDEX_LEN;
3602
3603             off = pn3->pn_offset - top;
3604             ok = js_SetJumpOffset(cx, cg, pc, off);
3605             if (!ok)
3606                 goto out;
3607             pc += JUMP_OFFSET_LEN;
3608         }
3609     }
3610
3611 out:
3612     if (table)
3613         cx->free(table);
3614     if (ok) {
3615         ok = js_PopStatementCG(cx, cg);
3616
3617 #if JS_HAS_BLOCK_SCOPE
3618         if (ok && pn->pn_right->pn_type == TOK_LEXICALSCOPE)
3619             ok = EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, box);
3620 #endif
3621     }
3622     return ok;
3623
3624 bad:
3625     ok = JS_FALSE;
3626     goto out;
3627 }
3628
3629 JSBool
3630 js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
3631 {
3632     /*
3633      * The decompiler has assumptions about what may occur immediately after
3634      * script->main (e.g., in the case of destructuring params). Thus, put the
3635      * following ops into the range [script->code, script->main). Note:
3636      * execution starts from script->code, so this has no semantic effect.
3637      */
3638
3639     if (cg->flags & TCF_FUN_IS_GENERATOR) {
3640         /* JSOP_GENERATOR must be the first instruction. */
3641         CG_SWITCH_TO_PROLOG(cg);
3642         JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg));
3643         if (js_Emit1(cx, cg, JSOP_GENERATOR) < 0)
3644             return false;
3645         CG_SWITCH_TO_MAIN(cg);
3646     }
3647
3648     /*
3649      * Strict mode functions' arguments objects copy initial parameter values.
3650      * We create arguments objects lazily -- but that doesn't work for strict
3651      * mode functions where a parameter might be modified and arguments might
3652      * be accessed. For such functions we synthesize an access to arguments to
3653      * initialize it with the original parameter values.
3654      */
3655     if (cg->needsEagerArguments()) {
3656         CG_SWITCH_TO_PROLOG(cg);
3657         if (js_Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
3658             return false;
3659         CG_SWITCH_TO_MAIN(cg);
3660     }
3661
3662     if (cg->flags & TCF_FUN_UNBRAND_THIS) {
3663         CG_SWITCH_TO_PROLOG(cg);
3664         if (js_Emit1(cx, cg, JSOP_UNBRANDTHIS) < 0)
3665             return false;
3666         CG_SWITCH_TO_MAIN(cg);
3667     }
3668
3669     return js_EmitTree(cx, cg, body) &&
3670            js_Emit1(cx, cg, JSOP_STOP) >= 0 &&
3671            JSScript::NewScriptFromCG(cx, cg);
3672 }
3673
3674 /* A macro for inlining at the top of js_EmitTree (whence it came). */
3675 #define UPDATE_LINE_NUMBER_NOTES(cx, cg, line)                                \
3676     JS_BEGIN_MACRO                                                            \
3677         uintN line_ = (line);                                                 \
3678         uintN delta_ = line_ - CG_CURRENT_LINE(cg);                           \
3679         if (delta_ != 0) {                                                    \
3680             /*                                                                \
3681              * Encode any change in the current source line number by using   \
3682              * either several SRC_NEWLINE notes or just one SRC_SETLINE note, \
3683              * whichever consumes less space.                                 \
3684              *                                                                \
3685              * NB: We handle backward line number deltas (possible with for   \
3686              * loops where the update part is emitted after the body, but its \
3687              * line number is <= any line number in the body) here by letting \
3688              * unsigned delta_ wrap to a very large number, which triggers a  \
3689              * SRC_SETLINE.                                                   \
3690              */                                                               \
3691             CG_CURRENT_LINE(cg) = line_;                                      \
3692             if (delta_ >= (uintN)(2 + ((line_ > SN_3BYTE_OFFSET_MASK)<<1))) { \
3693                 if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)line_) < 0)\
3694                     return JS_FALSE;                                          \
3695             } else {                                                          \
3696                 do {                                                          \
3697                     if (js_NewSrcNote(cx, cg, SRC_NEWLINE) < 0)               \
3698                         return JS_FALSE;                                      \
3699                 } while (--delta_ != 0);                                      \
3700             }                                                                 \
3701         }                                                                     \
3702     JS_END_MACRO
3703
3704 /* A function, so that we avoid macro-bloating all the other callsites. */
3705 static JSBool
3706 UpdateLineNumberNotes(JSContext *cx, JSCodeGenerator *cg, uintN line)
3707 {
3708     UPDATE_LINE_NUMBER_NOTES(cx, cg, line);
3709     return JS_TRUE;
3710 }
3711
3712 static JSBool
3713 MaybeEmitVarDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
3714                  JSParseNode *pn, jsatomid *result)
3715 {
3716     jsatomid atomIndex;
3717     JSAtomListElement *ale;
3718
3719     if (!pn->pn_cookie.isFree()) {
3720         atomIndex = (jsatomid) pn->pn_cookie.slot();
3721     } else {
3722         ale = cg->atomList.add(cg->parser, pn->pn_atom);
3723         if (!ale)
3724             return JS_FALSE;
3725         atomIndex = ALE_INDEX(ale);
3726     }
3727
3728     if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM &&
3729         (!cg->inFunction() || (cg->flags & TCF_FUN_HEAVYWEIGHT)) &&
3730         !(pn->pn_dflags & PND_GVAR))
3731     {
3732         CG_SWITCH_TO_PROLOG(cg);
3733         if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno))
3734             return JS_FALSE;
3735         EMIT_INDEX_OP(prologOp, atomIndex);
3736         CG_SWITCH_TO_MAIN(cg);
3737     }
3738
3739     if (cg->inFunction() &&
3740         JOF_OPTYPE(pn->pn_op) == JOF_LOCAL &&
3741         pn->pn_cookie.slot() < cg->bindings.countVars() &&
3742         cg->shouldNoteClosedName(pn))
3743     {
3744         if (!cg->closedVars.append(pn->pn_cookie.slot()))
3745             return JS_FALSE;
3746     }
3747
3748     if (result)
3749         *result = atomIndex;
3750     return JS_TRUE;
3751 }
3752
3753 #if JS_HAS_DESTRUCTURING
3754
3755 typedef JSBool
3756 (*DestructuringDeclEmitter)(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
3757                             JSParseNode *pn);
3758
3759 static JSBool
3760 EmitDestructuringDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
3761                       JSParseNode *pn)
3762 {
3763     JS_ASSERT(pn->pn_type == TOK_NAME);
3764     if (!BindNameToSlot(cx, cg, pn))
3765         return JS_FALSE;
3766
3767     JS_ASSERT(PN_OP(pn) != JSOP_ARGUMENTS && PN_OP(pn) != JSOP_CALLEE);
3768     return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL);
3769 }
3770
3771 static JSBool
3772 EmitDestructuringDecls(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
3773                        JSParseNode *pn)
3774 {
3775     JSParseNode *pn2, *pn3;
3776     DestructuringDeclEmitter emitter;
3777
3778     if (pn->pn_type == TOK_RB) {
3779         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
3780             if (pn2->pn_type == TOK_COMMA)
3781                 continue;
3782             emitter = (pn2->pn_type == TOK_NAME)
3783                       ? EmitDestructuringDecl
3784                       : EmitDestructuringDecls;
3785             if (!emitter(cx, cg, prologOp, pn2))
3786                 return JS_FALSE;
3787         }
3788     } else {
3789         JS_ASSERT(pn->pn_type == TOK_RC);
3790         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
3791             pn3 = pn2->pn_right;
3792             emitter = (pn3->pn_type == TOK_NAME)
3793                       ? EmitDestructuringDecl
3794                       : EmitDestructuringDecls;
3795             if (!emitter(cx, cg, prologOp, pn3))
3796                 return JS_FALSE;
3797         }
3798     }
3799     return JS_TRUE;
3800 }
3801
3802 static JSBool
3803 EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn);
3804
3805 static JSBool
3806 EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
3807 {
3808     /*
3809      * Now emit the lvalue opcode sequence.  If the lvalue is a nested
3810      * destructuring initialiser-form, call ourselves to handle it, then
3811      * pop the matched value.  Otherwise emit an lvalue bytecode sequence
3812      * ending with a JSOP_ENUMELEM or equivalent op.
3813      */
3814     if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) {
3815         if (!EmitDestructuringOpsHelper(cx, cg, pn))
3816             return JS_FALSE;
3817         if (js_Emit1(cx, cg, JSOP_POP) < 0)
3818             return JS_FALSE;
3819     } else {
3820         if (pn->pn_type == TOK_NAME) {
3821             if (!BindNameToSlot(cx, cg, pn))
3822                 return JS_FALSE;
3823             if (pn->isConst() && !pn->isInitialized())
3824                 return js_Emit1(cx, cg, JSOP_POP) >= 0;
3825         }
3826
3827         switch (pn->pn_op) {
3828           case JSOP_SETNAME:
3829           case JSOP_SETGNAME:
3830             /*
3831              * NB: pn is a PN_NAME node, not a PN_BINARY.  Nevertheless,
3832              * we want to emit JSOP_ENUMELEM, which has format JOF_ELEM.
3833              * So here and for JSOP_ENUMCONSTELEM, we use EmitElemOp.
3834              */
3835             if (!EmitElemOp(cx, pn, JSOP_ENUMELEM, cg))
3836                 return JS_FALSE;
3837             break;
3838
3839           case JSOP_SETCONST:
3840             if (!EmitElemOp(cx, pn, JSOP_ENUMCONSTELEM, cg))
3841                 return JS_FALSE;
3842             break;
3843
3844           case JSOP_SETLOCAL:
3845           {
3846             jsuint slot = pn->pn_cookie.asInteger();
3847             EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
3848             break;
3849           }
3850
3851           case JSOP_SETARG:
3852           {
3853             jsuint slot = pn->pn_cookie.asInteger();
3854             EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
3855             if (js_Emit1(cx, cg, JSOP_POP) < 0)
3856                 return JS_FALSE;
3857             break;
3858           }
3859
3860           default:
3861           {
3862             ptrdiff_t top;
3863
3864             top = CG_OFFSET(cg);
3865             if (!js_EmitTree(cx, cg, pn))
3866                 return JS_FALSE;
3867             if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
3868                 return JS_FALSE;
3869             if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)
3870                 return JS_FALSE;
3871             break;
3872           }
3873
3874           case JSOP_ENUMELEM:
3875             JS_ASSERT(0);
3876         }
3877     }
3878
3879     return JS_TRUE;
3880 }
3881
3882 /*
3883  * Recursive helper for EmitDestructuringOps.
3884  *
3885  * Given a value to destructure on the stack, walk over an object or array
3886  * initialiser at pn, emitting bytecodes to match property values and store
3887  * them in the lvalues identified by the matched property names.
3888  */
3889 static JSBool
3890 EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
3891 {
3892     jsuint index;
3893     JSParseNode *pn2, *pn3;
3894     JSBool doElemOp;
3895
3896 #ifdef DEBUG
3897     intN stackDepth = cg->stackDepth;
3898     JS_ASSERT(stackDepth != 0);
3899     JS_ASSERT(pn->pn_arity == PN_LIST);
3900     JS_ASSERT(pn->pn_type == TOK_RB || pn->pn_type == TOK_RC);
3901 #endif
3902
3903     if (pn->pn_count == 0) {
3904         /* Emit a DUP;POP sequence for the decompiler. */
3905         return js_Emit1(cx, cg, JSOP_DUP) >= 0 &&
3906                js_Emit1(cx, cg, JSOP_POP) >= 0;
3907     }
3908
3909     index = 0;
3910     for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
3911         /*
3912          * Duplicate the value being destructured to use as a reference base.
3913          * If dup is not the first one, annotate it for the decompiler.
3914          */
3915         if (pn2 != pn->pn_head && js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0)
3916             return JS_FALSE;
3917         if (js_Emit1(cx, cg, JSOP_DUP) < 0)
3918             return JS_FALSE;
3919
3920         /*
3921          * Now push the property name currently being matched, which is either
3922          * the array initialiser's current index, or the current property name
3923          * "label" on the left of a colon in the object initialiser.  Set pn3
3924          * to the lvalue node, which is in the value-initializing position.
3925          */
3926         doElemOp = JS_TRUE;
3927         if (pn->pn_type == TOK_RB) {
3928             if (!EmitNumberOp(cx, index, cg))
3929                 return JS_FALSE;
3930             pn3 = pn2;
3931         } else {
3932             JS_ASSERT(pn->pn_type == TOK_RC);
3933             JS_ASSERT(pn2->pn_type == TOK_COLON);
3934             pn3 = pn2->pn_left;
3935             if (pn3->pn_type == TOK_NUMBER) {
3936                 /*
3937                  * If we are emitting an object destructuring initialiser,
3938                  * annotate the index op with SRC_INITPROP so we know we are
3939                  * not decompiling an array initialiser.
3940                  */
3941                 if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0)
3942                     return JS_FALSE;
3943                 if (!EmitNumberOp(cx, pn3->pn_dval, cg))
3944                     return JS_FALSE;
3945             } else {
3946                 JS_ASSERT(pn3->pn_type == TOK_STRING ||
3947                           pn3->pn_type == TOK_NAME);
3948                 if (!EmitAtomOp(cx, pn3, JSOP_GETPROP, cg))
3949                     return JS_FALSE;
3950                 doElemOp = JS_FALSE;
3951             }
3952             pn3 = pn2->pn_right;
3953         }
3954
3955         if (doElemOp) {
3956             /*
3957              * Ok, get the value of the matching property name.  This leaves
3958              * that value on top of the value being destructured, so the stack
3959              * is one deeper than when we started.
3960              */
3961             if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
3962                 return JS_FALSE;
3963             JS_ASSERT(cg->stackDepth == stackDepth + 1);
3964         }
3965
3966         /* Nullary comma node makes a hole in the array destructurer. */
3967         if (pn3->pn_type == TOK_COMMA && pn3->pn_arity == PN_NULLARY) {
3968             JS_ASSERT(pn->pn_type == TOK_RB);
3969             JS_ASSERT(pn2 == pn3);
3970             if (js_Emit1(cx, cg, JSOP_POP) < 0)
3971                 return JS_FALSE;
3972         } else {
3973             if (!EmitDestructuringLHS(cx, cg, pn3))
3974                 return JS_FALSE;
3975         }
3976
3977         JS_ASSERT(cg->stackDepth == stackDepth);
3978         ++index;
3979     }
3980
3981     return JS_TRUE;
3982 }
3983
3984 static ptrdiff_t
3985 OpToDeclType(JSOp op)
3986 {
3987     switch (op) {
3988       case JSOP_NOP:
3989         return SRC_DECL_LET;
3990       case JSOP_DEFCONST:
3991         return SRC_DECL_CONST;
3992       case JSOP_DEFVAR:
3993         return SRC_DECL_VAR;
3994       default:
3995         return SRC_DECL_NONE;
3996     }
3997 }
3998
3999 static JSBool
4000 EmitDestructuringOps(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
4001                      JSParseNode *pn)
4002 {
4003     /*
4004      * If we're called from a variable declaration, help the decompiler by
4005      * annotating the first JSOP_DUP that EmitDestructuringOpsHelper emits.
4006      * If the destructuring initialiser is empty, our helper will emit a
4007      * JSOP_DUP followed by a JSOP_POP for the decompiler.
4008      */
4009     if (js_NewSrcNote2(cx, cg, SRC_DESTRUCT, OpToDeclType(prologOp)) < 0)
4010         return JS_FALSE;
4011
4012     /*
4013      * Call our recursive helper to emit the destructuring assignments and
4014      * related stack manipulations.
4015      */
4016     return EmitDestructuringOpsHelper(cx, cg, pn);
4017 }
4018
4019 static JSBool
4020 EmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
4021                     JSParseNode *lhs, JSParseNode *rhs)
4022 {
4023     jsuint depth, limit, i, nslots;
4024     JSParseNode *pn;
4025
4026     depth = limit = (uintN) cg->stackDepth;
4027     for (pn = rhs->pn_head; pn; pn = pn->pn_next) {
4028         if (limit == JS_BIT(16)) {
4029             ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG);
4030             return JS_FALSE;
4031         }
4032
4033         /* MaybeEmitGroupAssignment won't call us if rhs is holey. */
4034         JS_ASSERT(!(pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY));
4035         if (!js_EmitTree(cx, cg, pn))
4036             return JS_FALSE;
4037         ++limit;
4038     }
4039
4040     if (js_NewSrcNote2(cx, cg, SRC_GROUPASSIGN, OpToDeclType(prologOp)) < 0)
4041         return JS_FALSE;
4042
4043     i = depth;
4044     for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) {
4045         /* MaybeEmitGroupAssignment requires lhs->pn_count <= rhs->pn_count. */
4046         JS_ASSERT(i < limit);
4047         jsint slot = AdjustBlockSlot(cx, cg, i);
4048         if (slot < 0)
4049             return JS_FALSE;
4050         EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot);
4051
4052         if (pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY) {
4053             if (js_Emit1(cx, cg, JSOP_POP) < 0)
4054                 return JS_FALSE;
4055         } else {
4056             if (!EmitDestructuringLHS(cx, cg, pn))
4057                 return JS_FALSE;
4058         }
4059     }
4060
4061     nslots = limit - depth;
4062     EMIT_UINT16_IMM_OP(JSOP_POPN, nslots);
4063     cg->stackDepth = (uintN) depth;
4064     return JS_TRUE;
4065 }
4066
4067 /*
4068  * Helper called with pop out param initialized to a JSOP_POP* opcode.  If we
4069  * can emit a group assignment sequence, which results in 0 stack depth delta,
4070  * we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop.
4071  */
4072 static JSBool
4073 MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
4074                          JSParseNode *pn, JSOp *pop)
4075 {
4076     JSParseNode *lhs, *rhs;
4077
4078     JS_ASSERT(pn->pn_type == TOK_ASSIGN);
4079     JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV);
4080     lhs = pn->pn_left;
4081     rhs = pn->pn_right;
4082     if (lhs->pn_type == TOK_RB && rhs->pn_type == TOK_RB &&
4083         !(rhs->pn_xflags & PNX_HOLEY) &&
4084         lhs->pn_count <= rhs->pn_count) {
4085         if (!EmitGroupAssignment(cx, cg, prologOp, lhs, rhs))
4086             return JS_FALSE;
4087         *pop = JSOP_NOP;
4088     }
4089     return JS_TRUE;
4090 }
4091
4092 #endif /* JS_HAS_DESTRUCTURING */
4093
4094 static JSBool
4095 EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
4096               JSBool inLetHead, ptrdiff_t *headNoteIndex)
4097 {
4098     bool let, forInVar, first;
4099 #if JS_HAS_BLOCK_SCOPE
4100     bool forInLet, popScope;
4101     JSStmtInfo *stmt, *scopeStmt;
4102 #endif
4103     ptrdiff_t off, noteIndex, tmp;
4104     JSParseNode *pn2, *pn3, *next;
4105     JSOp op;
4106     jsatomid atomIndex;
4107     uintN oldflags;
4108
4109     /* Default in case of JS_HAS_BLOCK_SCOPE early return, below. */
4110     *headNoteIndex = -1;
4111
4112     /*
4113      * Let blocks and expressions have a parenthesized head in which the new
4114      * scope is not yet open. Initializer evaluation uses the parent node's
4115      * lexical scope. If popScope is true below, then we hide the top lexical
4116      * block from any calls to BindNameToSlot hiding in pn2->pn_expr so that
4117      * it won't find any names in the new let block.
4118      *
4119      * The same goes for let declarations in the head of any kind of for loop.
4120      * Unlike a let declaration 'let x = i' within a block, where x is hoisted
4121      * to the start of the block, a 'for (let x = i...) ...' loop evaluates i
4122      * in the containing scope, and puts x in the loop body's scope.
4123      */
4124     let = (pn->pn_op == JSOP_NOP);
4125     forInVar = (pn->pn_xflags & PNX_FORINVAR) != 0;
4126 #if JS_HAS_BLOCK_SCOPE
4127     forInLet = let && forInVar;
4128     popScope = (inLetHead || (let && (cg->flags & TCF_IN_FOR_INIT)));
4129     if (popScope) {
4130         stmt = cg->topStmt;
4131         scopeStmt = cg->topScopeStmt;
4132     }
4133 # ifdef __GNUC__
4134     else stmt = scopeStmt = NULL;   /* quell GCC overwarning */
4135 # endif
4136     JS_ASSERT(!popScope || let);
4137 #endif
4138
4139     off = noteIndex = -1;
4140     for (pn2 = pn->pn_head; ; pn2 = next) {
4141         first = pn2 == pn->pn_head;
4142         next = pn2->pn_next;
4143
4144         if (pn2->pn_type != TOK_NAME) {
4145 #if JS_HAS_DESTRUCTURING
4146             if (pn2->pn_type == TOK_RB || pn2->pn_type == TOK_RC) {
4147                 /*
4148                  * Emit variable binding ops, but not destructuring ops.
4149                  * The parser (see Variables, jsparse.c) has ensured that
4150                  * our caller will be the TOK_FOR/TOK_IN case in js_EmitTree,
4151                  * and that case will emit the destructuring code only after
4152                  * emitting an enumerating opcode and a branch that tests
4153                  * whether the enumeration ended.
4154                  */
4155                 JS_ASSERT(forInVar);
4156                 JS_ASSERT(pn->pn_count == 1);
4157                 if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn2))
4158                     return JS_FALSE;
4159                 break;
4160             }
4161 #endif
4162
4163             /*
4164              * A destructuring initialiser assignment preceded by var will
4165              * never occur to the left of 'in' in a for-in loop.  As with 'for
4166              * (var x = i in o)...', this will cause the entire 'var [a, b] =
4167              * i' to be hoisted out of the loop.
4168              */
4169             JS_ASSERT(pn2->pn_type == TOK_ASSIGN);
4170             JS_ASSERT(!forInVar);
4171
4172             /*
4173              * To allow the front end to rewrite var f = x; as f = x; when a
4174              * function f(){} precedes the var, detect simple name assignment
4175              * here and initialize the name.
4176              */
4177 #if !JS_HAS_DESTRUCTURING
4178             JS_ASSERT(pn2->pn_left->pn_type == TOK_NAME);
4179 #else
4180             if (pn2->pn_left->pn_type == TOK_NAME)
4181 #endif
4182             {
4183                 pn3 = pn2->pn_right;
4184                 pn2 = pn2->pn_left;
4185                 goto do_name;
4186             }
4187
4188 #if JS_HAS_DESTRUCTURING
4189             if (pn->pn_count == 1) {
4190                 /*
4191                  * If this is the only destructuring assignment in the list,
4192                  * try to optimize to a group assignment.  If we're in a let
4193                  * head, pass JSOP_POP rather than the pseudo-prolog JSOP_NOP
4194                  * in pn->pn_op, to suppress a second (and misplaced) 'let'.
4195                  */
4196                 JS_ASSERT(noteIndex < 0 && !pn2->pn_next);
4197                 op = JSOP_POP;
4198                 if (!MaybeEmitGroupAssignment(cx, cg,
4199                                               inLetHead ? JSOP_POP : PN_OP(pn),
4200                                               pn2, &op)) {
4201                     return JS_FALSE;
4202                 }
4203                 if (op == JSOP_NOP) {
4204                     pn->pn_xflags = (pn->pn_xflags & ~PNX_POPVAR) | PNX_GROUPINIT;
4205                     break;
4206                 }
4207             }
4208
4209             pn3 = pn2->pn_left;
4210             if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn3))
4211                 return JS_FALSE;
4212
4213             if (!js_EmitTree(cx, cg, pn2->pn_right))
4214                 return JS_FALSE;
4215
4216             /*
4217              * Veto pn->pn_op if inLetHead to avoid emitting a SRC_DESTRUCT
4218              * that's redundant with respect to the SRC_DECL/SRC_DECL_LET that
4219              * we will emit at the bottom of this function.
4220              */
4221             if (!EmitDestructuringOps(cx, cg,
4222                                       inLetHead ? JSOP_POP : PN_OP(pn),
4223                                       pn3)) {
4224                 return JS_FALSE;
4225             }
4226             goto emit_note_pop;
4227 #endif
4228         }
4229
4230         /*
4231          * Load initializer early to share code above that jumps to do_name.
4232          * NB: if this var redeclares an existing binding, then pn2 is linked
4233          * on its definition's use-chain and pn_expr has been overlayed with
4234          * pn_lexdef.
4235          */
4236         pn3 = pn2->maybeExpr();
4237
4238      do_name:
4239         if (!BindNameToSlot(cx, cg, pn2))
4240             return JS_FALSE;
4241
4242         op = PN_OP(pn2);
4243         if (op == JSOP_ARGUMENTS) {
4244             /* JSOP_ARGUMENTS => no initializer */
4245             JS_ASSERT(!pn3 && !let);
4246             pn3 = NULL;
4247 #ifdef __GNUC__
4248             atomIndex = 0;            /* quell GCC overwarning */
4249 #endif
4250         } else {
4251             JS_ASSERT(op != JSOP_CALLEE);
4252             JS_ASSERT(!pn2->pn_cookie.isFree() || !let);
4253             if (!MaybeEmitVarDecl(cx, cg, PN_OP(pn), pn2, &atomIndex))
4254                 return JS_FALSE;
4255
4256             if (pn3) {
4257                 JS_ASSERT(!forInVar);
4258                 if (op == JSOP_SETNAME) {
4259                     JS_ASSERT(!let);
4260                     EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
4261                 } else if (op == JSOP_SETGNAME) {
4262                     JS_ASSERT(!let);
4263                     EMIT_INDEX_OP(JSOP_BINDGNAME, atomIndex);
4264                 }
4265                 if (pn->pn_op == JSOP_DEFCONST &&
4266                     !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom, pn3)) {
4267                     return JS_FALSE;
4268                 }
4269
4270 #if JS_HAS_BLOCK_SCOPE
4271                 /* Evaluate expr in the outer lexical scope if requested. */
4272                 if (popScope) {
4273                     cg->topStmt = stmt->down;
4274                     cg->topScopeStmt = scopeStmt->downScope;
4275                 }
4276 #endif
4277
4278                 oldflags = cg->flags;
4279                 cg->flags &= ~TCF_IN_FOR_INIT;
4280                 if (!js_EmitTree(cx, cg, pn3))
4281                     return JS_FALSE;
4282                 cg->flags |= oldflags & TCF_IN_FOR_INIT;
4283
4284 #if JS_HAS_BLOCK_SCOPE
4285                 if (popScope) {
4286                     cg->topStmt = stmt;
4287                     cg->topScopeStmt = scopeStmt;
4288                     JS_ASSERT(cg->blockChainBox == scopeStmt->blockBox);
4289                 }
4290 #endif
4291             }
4292         }
4293
4294         /*
4295          * The parser rewrites 'for (var x = i in o)' to hoist 'var x = i' --
4296          * likewise 'for (let x = i in o)' becomes 'i; for (let x in o)' using
4297          * a TOK_SEQ node to make the two statements appear as one. Therefore
4298          * if this declaration is part of a for-in loop head, we do not need to
4299          * emit op or any source note. Our caller, the TOK_FOR/TOK_IN case in
4300          * js_EmitTree, will annotate appropriately.
4301          */
4302         JS_ASSERT_IF(pn2->pn_defn, pn3 == pn2->pn_expr);
4303         if (forInVar) {
4304             JS_ASSERT(pn->pn_count == 1);
4305             JS_ASSERT(!pn3);
4306             break;
4307         }
4308
4309         if (first &&
4310             !inLetHead &&
4311             js_NewSrcNote2(cx, cg, SRC_DECL,
4312                            (pn->pn_op == JSOP_DEFCONST)
4313                            ? SRC_DECL_CONST
4314                            : (pn->pn_op == JSOP_DEFVAR)
4315                            ? SRC_DECL_VAR
4316                            : SRC_DECL_LET) < 0) {
4317             return JS_FALSE;
4318         }
4319         if (op == JSOP_ARGUMENTS) {
4320             if (js_Emit1(cx, cg, op) < 0)
4321                 return JS_FALSE;
4322         } else if (!pn2->pn_cookie.isFree()) {
4323             EMIT_UINT16_IMM_OP(op, atomIndex);
4324         } else {
4325             EMIT_INDEX_OP(op, atomIndex);
4326         }
4327
4328 #if JS_HAS_DESTRUCTURING
4329     emit_note_pop:
4330 #endif
4331         tmp = CG_OFFSET(cg);
4332         if (noteIndex >= 0) {
4333             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))
4334                 return JS_FALSE;
4335         }
4336         if (!next)
4337             break;
4338         off = tmp;
4339         noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
4340         if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
4341             return JS_FALSE;
4342     }
4343
4344     /* If this is a let head, emit and return a srcnote on the pop. */
4345     if (inLetHead) {
4346         *headNoteIndex = js_NewSrcNote(cx, cg, SRC_DECL);
4347         if (*headNoteIndex < 0)
4348             return JS_FALSE;
4349         if (!(pn->pn_xflags & PNX_POPVAR))
4350             return js_Emit1(cx, cg, JSOP_NOP) >= 0;
4351     }
4352
4353     return !(pn->pn_xflags & PNX_POPVAR) || js_Emit1(cx, cg, JSOP_POP) >= 0;
4354 }
4355
4356 #if defined DEBUG_brendan || defined DEBUG_mrbkap
4357 static JSBool
4358 GettableNoteForNextOp(JSCodeGenerator *cg)
4359 {
4360     ptrdiff_t offset, target;
4361     jssrcnote *sn, *end;
4362
4363     offset = 0;
4364     target = CG_OFFSET(cg);
4365     for (sn = CG_NOTES(cg), end = sn + CG_NOTE_COUNT(cg); sn < end;
4366          sn = SN_NEXT(sn)) {
4367         if (offset == target && SN_IS_GETTABLE(sn))
4368             return JS_TRUE;
4369         offset += SN_DELTA(sn);
4370     }
4371     return JS_FALSE;
4372 }
4373 #endif
4374
4375 /* Top-level named functions need a nop for decompilation. */
4376 static JSBool
4377 EmitFunctionDefNop(JSContext *cx, JSCodeGenerator *cg, uintN index)
4378 {
4379     return js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)index) >= 0 &&
4380            js_Emit1(cx, cg, JSOP_NOP) >= 0;
4381 }
4382
4383 static bool
4384 EmitNewInit(JSContext *cx, JSCodeGenerator *cg, JSProtoKey key, JSParseNode *pn, int sharpnum)
4385 {
4386     if (js_Emit3(cx, cg, JSOP_NEWINIT, (jsbytecode) key, 0) < 0)
4387         return false;
4388 #if JS_HAS_SHARP_VARS
4389     if (cg->hasSharps()) {
4390         if (pn->pn_count != 0)
4391             EMIT_UINT16_IMM_OP(JSOP_SHARPINIT, cg->sharpSlotBase);
4392         if (sharpnum >= 0)
4393             EMIT_UINT16PAIR_IMM_OP(JSOP_DEFSHARP, cg->sharpSlotBase, sharpnum);
4394     } else {
4395         JS_ASSERT(sharpnum < 0);
4396     }
4397 #endif
4398     return true;
4399 }
4400
4401 static bool
4402 EmitEndInit(JSContext *cx, JSCodeGenerator *cg, uint32 count)
4403 {
4404 #if JS_HAS_SHARP_VARS
4405     /* Emit an op for sharp array cleanup and decompilation. */
4406     if (cg->hasSharps() && count != 0)
4407         EMIT_UINT16_IMM_OP(JSOP_SHARPINIT, cg->sharpSlotBase);
4408 #endif
4409     return js_Emit1(cx, cg, JSOP_ENDINIT) >= 0;
4410 }
4411
4412 bool
4413 JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
4414 {
4415     switch (pn_type) {
4416       case TOK_NUMBER:
4417         vp->setNumber(pn_dval);
4418         return true;
4419       case TOK_STRING:
4420         vp->setString(ATOM_TO_STRING(pn_atom));
4421         return true;
4422       case TOK_PRIMARY:
4423         switch (pn_op) {
4424           case JSOP_NULL:
4425             vp->setNull();
4426             return true;
4427           case JSOP_FALSE:
4428             vp->setBoolean(false);
4429             return true;
4430           case JSOP_TRUE:
4431             vp->setBoolean(true);
4432             return true;
4433           default:
4434             JS_NOT_REACHED("Unexpected node");
4435             return false;
4436         }
4437       case TOK_RB: {
4438         JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
4439  
4440         JSObject *obj = NewDenseAllocatedArray(cx, pn_count);
4441         if (!obj || !obj->ensureSlots(cx, pn_count))
4442             return false;
4443
4444         unsigned idx = 0;
4445         for (JSParseNode *pn = pn_head; pn; idx++, pn = pn->pn_next) {
4446             Value value;
4447             if (!pn->getConstantValue(cx, strictChecks, &value))
4448                 return false;
4449             obj->setDenseArrayElement(idx, value);
4450         }
4451         JS_ASSERT(idx == pn_count);
4452
4453         vp->setObject(*obj);
4454         return true;
4455       }
4456       case TOK_RC: {
4457         JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
4458
4459         gc::FinalizeKind kind = GuessObjectGCKind(pn_count, false);
4460         JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
4461         if (!obj)
4462             return false;
4463
4464         for (JSParseNode *pn = pn_head; pn; pn = pn->pn_next) {
4465             Value value;
4466             if (!pn->pn_right->getConstantValue(cx, strictChecks, &value))
4467                 return false;
4468
4469             JSParseNode *pnid = pn->pn_left;
4470             if (pnid->pn_type == TOK_NUMBER) {
4471                 Value idvalue = NumberValue(pnid->pn_dval);
4472                 jsid id;
4473                 if (idvalue.isInt32() && INT_FITS_IN_JSID(idvalue.toInt32()))
4474                     id = INT_TO_JSID(idvalue.toInt32());
4475                 else if (!js_InternNonIntElementId(cx, obj, idvalue, &id))
4476                     return false;
4477                 if (!obj->defineProperty(cx, id, value, NULL, NULL, JSPROP_ENUMERATE))
4478                     return false;
4479             } else {
4480                 JS_ASSERT(pnid->pn_type == TOK_NAME ||
4481                           pnid->pn_type == TOK_STRING);
4482                 jsid id = ATOM_TO_JSID(pnid->pn_atom);
4483                 if (!((pnid->pn_atom == cx->runtime->atomState.protoAtom)
4484                       ? js_SetPropertyHelper(cx, obj, id, 0, &value, strictChecks)
4485                       : js_DefineNativeProperty(cx, obj, id, value, NULL, NULL,
4486                                                 JSPROP_ENUMERATE, 0, 0, NULL, 0))) {
4487                     return false;
4488                 }
4489             }
4490         }
4491
4492         vp->setObject(*obj);
4493         return true;
4494       }
4495       default:
4496         JS_NOT_REACHED("Unexpected node");
4497     }
4498     return false;
4499 }
4500
4501 static bool
4502 EmitSingletonInitialiser(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
4503 {
4504     Value value;
4505     if (!pn->getConstantValue(cx, cg->needStrictChecks(), &value))
4506         return false;
4507
4508     JS_ASSERT(value.isObject());
4509     JSObjectBox *objbox = cg->parser->newObjectBox(&value.toObject());
4510     if (!objbox)
4511         return false;
4512
4513     return EmitObjectOp(cx, objbox, JSOP_OBJECT, cg);
4514 }
4515
4516 /* See the SRC_FOR source note offsetBias comments later in this file. */
4517 JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
4518 JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1);
4519
4520 class EmitLevelManager
4521 {
4522 private:
4523     JSCodeGenerator *cg;
4524     
4525 public:
4526     EmitLevelManager(JSCodeGenerator *cg) : cg(cg) { cg->emitLevel++; }
4527
4528     ~EmitLevelManager() { cg->emitLevel--; }
4529 };
4530
4531 JSBool
4532 js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
4533 {
4534     JSBool ok, useful, wantval;
4535     JSStmtInfo *stmt, stmtInfo;
4536     ptrdiff_t top, off, tmp, beq, jmp, tmp2, tmp3;
4537     JSParseNode *pn2, *pn3;
4538     JSAtom *atom;
4539     JSAtomListElement *ale;
4540     jsatomid atomIndex;
4541     uintN index;
4542     ptrdiff_t noteIndex, noteIndex2;
4543     JSSrcNoteType noteType;
4544     jsbytecode *pc;
4545     JSOp op;
4546     TokenKind type;
4547     uint32 argc;
4548     EmitLevelManager elm(cg);
4549 #if JS_HAS_SHARP_VARS
4550     jsint sharpnum;
4551 #endif
4552
4553     JS_CHECK_RECURSION(cx, return JS_FALSE);
4554
4555     ok = JS_TRUE;
4556     pn->pn_offset = top = CG_OFFSET(cg);
4557
4558     /* Emit notes to tell the current bytecode's source line number. */
4559     UPDATE_LINE_NUMBER_NOTES(cx, cg, pn->pn_pos.begin.lineno);
4560
4561     switch (pn->pn_type) {
4562       case TOK_FUNCTION:
4563       {
4564         JSFunction *fun;
4565         uintN slot;
4566
4567 #if JS_HAS_XML_SUPPORT
4568         if (pn->pn_arity == PN_NULLARY) {
4569             if (js_Emit1(cx, cg, JSOP_GETFUNNS) < 0)
4570                 return JS_FALSE;
4571             break;
4572         }
4573 #endif
4574
4575         fun = (JSFunction *) pn->pn_funbox->object;
4576         JS_ASSERT(FUN_INTERPRETED(fun));
4577         if (fun->u.i.script) {
4578             /*
4579              * This second pass is needed to emit JSOP_NOP with a source note
4580              * for the already-emitted function definition prolog opcode. See
4581              * comments in the TOK_LC case.
4582              */
4583             JS_ASSERT(pn->pn_op == JSOP_NOP);
4584             JS_ASSERT(cg->inFunction());
4585             if (!EmitFunctionDefNop(cx, cg, pn->pn_index))
4586                 return JS_FALSE;
4587             break;
4588         }
4589
4590         JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
4591                      FUN_KIND(fun) == JSFUN_INTERPRETED);
4592
4593         /* Generate code for the function's body. */
4594         void *cg2mark = JS_ARENA_MARK(cg->codePool);
4595         void *cg2space;
4596         JS_ARENA_ALLOCATE_TYPE(cg2space, JSCodeGenerator, cg->codePool);
4597         if (!cg2space) {
4598             js_ReportOutOfScriptQuota(cx);
4599             return JS_FALSE;
4600         }
4601         JSCodeGenerator *cg2 =
4602             new (cg2space) JSCodeGenerator(cg->parser,
4603                                            cg->codePool, cg->notePool,
4604                                            pn->pn_pos.begin.lineno);
4605
4606         if (!cg2->init())
4607             return JS_FALSE;
4608
4609         cg2->flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION |
4610                      (cg->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
4611         cg2->bindings.transfer(cx, &pn->pn_funbox->bindings);
4612 #if JS_HAS_SHARP_VARS
4613         if (cg2->flags & TCF_HAS_SHARPS) {
4614             cg2->sharpSlotBase = cg2->bindings.sharpSlotBase(cx);
4615             if (cg2->sharpSlotBase < 0)
4616                 return JS_FALSE;
4617         }
4618 #endif
4619         cg2->setFunction(fun);
4620         cg2->funbox = pn->pn_funbox;
4621         cg2->parent = cg;
4622
4623         /*
4624          * jsparse.cpp:SetStaticLevel limited static nesting depth to fit in 16
4625          * bits and to reserve the all-ones value, thereby reserving the magic
4626          * FREE_UPVAR_COOKIE value. Note the cg2->staticLevel assignment below.
4627          */
4628         JS_ASSERT(cg->staticLevel < JS_BITMASK(16) - 1);
4629         cg2->staticLevel = cg->staticLevel + 1;
4630
4631         /* We measured the max scope depth when we parsed the function. */
4632         JS_SCOPE_DEPTH_METERING(cg2->maxScopeDepth = uint16(-1));
4633         if (!js_EmitFunctionScript(cx, cg2, pn->pn_body))
4634             pn = NULL;
4635
4636         cg2->~JSCodeGenerator();
4637         JS_ARENA_RELEASE(cg->codePool, cg2mark);
4638         cg2 = NULL;
4639         if (!pn)
4640             return JS_FALSE;
4641
4642         /* Make the function object a literal in the outer script's pool. */
4643         index = cg->objectList.index(pn->pn_funbox);
4644
4645         /* Emit a bytecode pointing to the closure object in its immediate. */
4646         op = PN_OP(pn);
4647         if (op != JSOP_NOP) {
4648             if ((pn->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) &&
4649                 js_NewSrcNote(cx, cg, SRC_GENEXP) < 0) {
4650                 return JS_FALSE;
4651             }
4652             EMIT_INDEX_OP(op, index);
4653
4654             /* Make blockChain determination quicker. */
4655             if (EmitBlockChain(cx, cg) < 0)
4656                 return JS_FALSE;
4657             break;
4658         }
4659
4660         /*
4661          * For a script we emit the code as we parse. Thus the bytecode for
4662          * top-level functions should go in the prolog to predefine their
4663          * names in the variable object before the already-generated main code
4664          * is executed. This extra work for top-level scripts is not necessary
4665          * when we emit the code for a function. It is fully parsed prior to
4666          * invocation of the emitter and calls to js_EmitTree for function
4667          * definitions can be scheduled before generating the rest of code.
4668          */
4669         if (!cg->inFunction()) {
4670             JS_ASSERT(!cg->topStmt);
4671             if (!BindGlobal(cx, cg, pn, fun->atom))
4672                 return false;
4673             if (pn->pn_cookie.isFree()) {
4674                 CG_SWITCH_TO_PROLOG(cg);
4675                 op = FUN_FLAT_CLOSURE(fun) ? JSOP_DEFFUN_FC : JSOP_DEFFUN;
4676                 EMIT_INDEX_OP(op, index);
4677
4678                 /* Make blockChain determination quicker. */
4679                 if (EmitBlockChain(cx, cg) < 0)
4680                     return JS_FALSE;
4681                 CG_SWITCH_TO_MAIN(cg);
4682             }
4683
4684             /* Emit NOP for the decompiler. */
4685             if (!EmitFunctionDefNop(cx, cg, index))
4686                 return JS_FALSE;
4687         } else {
4688 #ifdef DEBUG
4689             BindingKind kind =
4690 #endif
4691                 cg->bindings.lookup(cx, fun->atom, &slot);
4692             JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
4693             JS_ASSERT(index < JS_BIT(20));
4694             pn->pn_index = index;
4695             op = fun->isFlatClosure() ? JSOP_DEFLOCALFUN_FC : JSOP_DEFLOCALFUN;
4696             if (pn->isClosed() &&
4697                 !cg->callsEval() &&
4698                 !cg->closedVars.append(pn->pn_cookie.slot())) {
4699                 return JS_FALSE;
4700             }
4701             if (!EmitSlotIndexOp(cx, op, slot, index, cg))
4702                 return JS_FALSE;
4703
4704             /* Make blockChain determination quicker. */
4705             if (EmitBlockChain(cx, cg) < 0)
4706                 return JS_FALSE;
4707         }
4708         break;
4709       }
4710
4711       case TOK_ARGSBODY:
4712       {
4713         JSParseNode *pnlast = pn->last();
4714         for (JSParseNode *pn2 = pn->pn_head; pn2 != pnlast; pn2 = pn2->pn_next) {
4715             if (!pn2->pn_defn)
4716                 continue;
4717             if (!BindNameToSlot(cx, cg, pn2))
4718                 return JS_FALSE;
4719             if (JOF_OPTYPE(pn2->pn_op) == JOF_QARG && cg->shouldNoteClosedName(pn2)) {
4720                 if (!cg->closedArgs.append(pn2->pn_cookie.slot()))
4721                     return JS_FALSE;
4722             }
4723         }
4724         ok = js_EmitTree(cx, cg, pnlast);
4725         break;
4726       }
4727
4728       case TOK_UPVARS:
4729         JS_ASSERT(cg->lexdeps.count == 0);
4730         JS_ASSERT(pn->pn_names.count != 0);
4731         cg->lexdeps = pn->pn_names;
4732         ok = js_EmitTree(cx, cg, pn->pn_tree);
4733         break;
4734
4735       case TOK_IF:
4736         /* Initialize so we can detect else-if chains and avoid recursion. */
4737         stmtInfo.type = STMT_IF;
4738         beq = jmp = -1;
4739         noteIndex = -1;
4740
4741       if_again:
4742         /* Emit code for the condition before pushing stmtInfo. */
4743         if (!js_EmitTree(cx, cg, pn->pn_kid1))
4744             return JS_FALSE;
4745         top = CG_OFFSET(cg);
4746         if (stmtInfo.type == STMT_IF) {
4747             js_PushStatement(cg, &stmtInfo, STMT_IF, top);
4748         } else {
4749             /*
4750              * We came here from the goto further below that detects else-if
4751              * chains, so we must mutate stmtInfo back into a STMT_IF record.
4752              * Also (see below for why) we need a note offset for SRC_IF_ELSE
4753              * to help the decompiler.  Actually, we need two offsets, one for
4754              * decompiling any else clause and the second for decompiling an
4755              * else-if chain without bracing, overindenting, or incorrectly
4756              * scoping let declarations.
4757              */
4758             JS_ASSERT(stmtInfo.type == STMT_ELSE);
4759             stmtInfo.type = STMT_IF;
4760             stmtInfo.update = top;
4761             if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))
4762                 return JS_FALSE;
4763             if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 1, top - beq))
4764                 return JS_FALSE;
4765         }
4766
4767         /* Emit an annotated branch-if-false around the then part. */
4768         pn3 = pn->pn_kid3;
4769         noteIndex = js_NewSrcNote(cx, cg, pn3 ? SRC_IF_ELSE : SRC_IF);
4770         if (noteIndex < 0)
4771             return JS_FALSE;
4772         beq = EmitJump(cx, cg, JSOP_IFEQ, 0);
4773         if (beq < 0)
4774             return JS_FALSE;
4775
4776         /* Emit code for the then and optional else parts. */
4777         if (!js_EmitTree(cx, cg, pn->pn_kid2))
4778             return JS_FALSE;
4779         if (pn3) {
4780             /* Modify stmtInfo so we know we're in the else part. */
4781             stmtInfo.type = STMT_ELSE;
4782
4783             /*
4784              * Emit a JSOP_BACKPATCH op to jump from the end of our then part
4785              * around the else part.  The js_PopStatementCG call at the bottom
4786              * of this switch case will fix up the backpatch chain linked from
4787              * stmtInfo.breaks.
4788              */
4789             jmp = EmitGoto(cx, cg, &stmtInfo, &stmtInfo.breaks, NULL, SRC_NULL);
4790             if (jmp < 0)
4791                 return JS_FALSE;
4792
4793             /* Ensure the branch-if-false comes here, then emit the else. */
4794             CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
4795             if (pn3->pn_type == TOK_IF) {
4796                 pn = pn3;
4797                 goto if_again;
4798             }
4799
4800             if (!js_EmitTree(cx, cg, pn3))
4801                 return JS_FALSE;
4802
4803             /*
4804              * Annotate SRC_IF_ELSE with the offset from branch to jump, for
4805              * the decompiler's benefit.  We can't just "back up" from the pc
4806              * of the else clause, because we don't know whether an extended
4807              * jump was required to leap from the end of the then clause over
4808              * the else clause.
4809              */
4810             if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))
4811                 return JS_FALSE;
4812         } else {
4813             /* No else part, fixup the branch-if-false to come here. */
4814             CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
4815         }
4816         ok = js_PopStatementCG(cx, cg);
4817         break;
4818
4819       case TOK_SWITCH:
4820         /* Out of line to avoid bloating js_EmitTree's stack frame size. */
4821         ok = EmitSwitch(cx, cg, pn, &stmtInfo);
4822         break;
4823
4824       case TOK_WHILE:
4825         /*
4826          * Minimize bytecodes issued for one or more iterations by jumping to
4827          * the condition below the body and closing the loop if the condition
4828          * is true with a backward branch. For iteration count i:
4829          *
4830          *  i    test at the top                 test at the bottom
4831          *  =    ===============                 ==================
4832          *  0    ifeq-pass                       goto; ifne-fail
4833          *  1    ifeq-fail; goto; ifne-pass      goto; ifne-pass; ifne-fail
4834          *  2    2*(ifeq-fail; goto); ifeq-pass  goto; 2*ifne-pass; ifne-fail
4835          *  . . .
4836          *  N    N*(ifeq-fail; goto); ifeq-pass  goto; N*ifne-pass; ifne-fail
4837          *
4838          * SpiderMonkey, pre-mozilla.org, emitted while parsing and so used
4839          * test at the top. When JSParseNode trees were added during the ES3
4840          * work (1998-9), the code generation scheme was not optimized, and
4841          * the decompiler continued to take advantage of the branch and jump
4842          * that bracketed the body. But given the SRC_WHILE note, it is easy
4843          * to support the more efficient scheme.
4844          */
4845         js_PushStatement(cg, &stmtInfo, STMT_WHILE_LOOP, top);
4846         noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);
4847         if (noteIndex < 0)
4848             return JS_FALSE;
4849         jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
4850         if (jmp < 0)
4851             return JS_FALSE;
4852         noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE);
4853         if (noteIndex2 < 0)
4854             return JS_FALSE;
4855         top = EmitTraceOp(cx, cg);
4856         if (top < 0)
4857             return JS_FALSE;
4858         if (!js_EmitTree(cx, cg, pn->pn_right))
4859             return JS_FALSE;
4860         CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
4861         if (!js_EmitTree(cx, cg, pn->pn_left))
4862             return JS_FALSE;
4863         beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
4864         if (beq < 0)
4865             return JS_FALSE;
4866         /*
4867          * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
4868          * note gets bigger.
4869          */
4870         if (!js_SetSrcNoteOffset(cx, cg, noteIndex2, 0, beq - top))
4871             return JS_FALSE;
4872         if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, beq - jmp))
4873             return JS_FALSE;
4874         ok = js_PopStatementCG(cx, cg);
4875         break;
4876
4877       case TOK_DO:
4878         /* Emit an annotated nop so we know to decompile a 'do' keyword. */
4879         noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);
4880         if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0)
4881             return JS_FALSE;
4882
4883         noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE);
4884         if (noteIndex2 < 0)
4885             return JS_FALSE;
4886
4887         /* Compile the loop body. */
4888         top = EmitTraceOp(cx, cg);
4889         if (top < 0)
4890             return JS_FALSE;
4891         js_PushStatement(cg, &stmtInfo, STMT_DO_LOOP, top);
4892         if (!js_EmitTree(cx, cg, pn->pn_left))
4893             return JS_FALSE;
4894
4895         /* Set loop and enclosing label update offsets, for continue. */
4896         stmt = &stmtInfo;
4897         do {
4898             stmt->update = CG_OFFSET(cg);
4899         } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
4900
4901         /* Compile the loop condition, now that continues know where to go. */
4902         if (!js_EmitTree(cx, cg, pn->pn_right))
4903             return JS_FALSE;
4904
4905         /*
4906          * Since we use JSOP_IFNE for other purposes as well as for do-while
4907          * loops, we must store 1 + (beq - top) in the SRC_WHILE note offset,
4908          * and the decompiler must get that delta and decompile recursively.
4909          */
4910         beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
4911         if (beq < 0)
4912             return JS_FALSE;
4913         /*
4914          * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
4915          * note gets bigger.
4916          */
4917         if (!js_SetSrcNoteOffset(cx, cg, noteIndex2, 0, beq - top))
4918             return JS_FALSE;
4919         if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, 1 + (beq - top)))
4920             return JS_FALSE;
4921         ok = js_PopStatementCG(cx, cg);
4922         break;
4923
4924       case TOK_FOR:
4925         beq = 0;                /* suppress gcc warnings */
4926         jmp = -1;
4927         pn2 = pn->pn_left;
4928         js_PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top);
4929
4930         if (pn2->pn_type == TOK_IN) {
4931             /* Set stmtInfo type for later testing. */
4932             stmtInfo.type = STMT_FOR_IN_LOOP;
4933
4934             /*
4935              * If the left part is 'var x', emit code to define x if necessary
4936              * using a prolog opcode, but do not emit a pop.  If the left part
4937              * is 'var x = i', emit prolog code to define x if necessary; then
4938              * emit code to evaluate i, assign the result to x, and pop the
4939              * result off the stack.
4940              *
4941              * All the logic to do this is implemented in the outer switch's
4942              * TOK_VAR case, conditioned on pn_xflags flags set by the parser.
4943              *
4944              * In the 'for (var x = i in o) ...' case, the js_EmitTree(...pn3)
4945              * called here will generate the proper note for the assignment
4946              * op that sets x = i, hoisting the initialized var declaration
4947              * out of the loop: 'var x = i; for (x in o) ...'.
4948              *
4949              * In the 'for (var x in o) ...' case, nothing but the prolog op
4950              * (if needed) should be generated here, we must emit the note
4951              * just before the JSOP_FOR* opcode in the switch on pn3->pn_type
4952              * a bit below, so nothing is hoisted: 'for (var x in o) ...'.
4953              *
4954              * A 'for (let x = i in o)' loop must not be hoisted, since in
4955              * this form the let variable is scoped by the loop body (but not
4956              * the head).  The initializer expression i must be evaluated for
4957              * any side effects.  So we hoist only i in the let case.
4958              */
4959             pn3 = pn2->pn_left;
4960             type = PN_TYPE(pn3);
4961             cg->flags |= TCF_IN_FOR_INIT;
4962             if (TokenKindIsDecl(type) && !js_EmitTree(cx, cg, pn3))
4963                 return JS_FALSE;
4964             cg->flags &= ~TCF_IN_FOR_INIT;
4965
4966             /* Compile the object expression to the right of 'in'. */
4967             if (!js_EmitTree(cx, cg, pn2->pn_right))
4968                 return JS_FALSE;
4969
4970             /*
4971              * Emit a bytecode to convert top of stack value to the iterator
4972              * object depending on the loop variant (for-in, for-each-in, or
4973              * destructuring for-in).
4974              */
4975             JS_ASSERT(pn->pn_op == JSOP_ITER);
4976             if (js_Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
4977                 return JS_FALSE;
4978
4979             /* Annotate so the decompiler can find the loop-closing jump. */
4980             noteIndex = js_NewSrcNote(cx, cg, SRC_FOR_IN);
4981             if (noteIndex < 0)
4982                 return JS_FALSE;
4983
4984             /*
4985              * Jump down to the loop condition to minimize overhead assuming at
4986              * least one iteration, as the other loop forms do.
4987              */
4988             jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
4989             if (jmp < 0)
4990                 return JS_FALSE;
4991
4992             noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE);
4993             if (noteIndex2 < 0)
4994                 return JS_FALSE;
4995             
4996             top = CG_OFFSET(cg);
4997             SET_STATEMENT_TOP(&stmtInfo, top);
4998             if (EmitTraceOp(cx, cg) < 0)
4999                 return JS_FALSE;
5000
5001 #ifdef DEBUG
5002             intN loopDepth = cg->stackDepth;
5003 #endif
5004
5005             /*
5006              * Compile a JSOP_FOR* bytecode based on the left hand side.
5007              *
5008              * Initialize op to JSOP_SETNAME in case of |for ([a, b] in o)...|
5009              * or similar, to signify assignment, rather than declaration, to
5010              * the decompiler.  EmitDestructuringOps takes a prolog bytecode
5011              * parameter and emits the appropriate source note, defaulting to
5012              * assignment, so JSOP_SETNAME is not critical here; many similar
5013              * ops could be used -- just not JSOP_NOP (which means 'let').
5014              */
5015             op = JSOP_SETNAME;
5016             switch (type) {
5017 #if JS_HAS_BLOCK_SCOPE
5018               case TOK_LET:
5019 #endif
5020               case TOK_VAR:
5021                 JS_ASSERT(pn3->pn_arity == PN_LIST && pn3->pn_count == 1);
5022                 pn3 = pn3->pn_head;
5023 #if JS_HAS_DESTRUCTURING
5024                 if (pn3->pn_type == TOK_ASSIGN) {
5025                     pn3 = pn3->pn_left;
5026                     JS_ASSERT(pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC);
5027                 }
5028                 if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) {
5029                     op = PN_OP(pn2->pn_left);
5030                     goto destructuring_for;
5031                 }
5032 #else
5033                 JS_ASSERT(pn3->pn_type == TOK_NAME);
5034 #endif
5035                 /* FALL THROUGH */
5036
5037               case TOK_NAME:
5038               {
5039                 /*
5040                  * Always annotate JSOP_FORLOCAL if given input of the form
5041                  * 'for (let x in * o)' -- the decompiler must not hoist the
5042                  * 'let x' out of the loop head, or x will be bound in the
5043                  * wrong scope.  Likewise, but in this case only for the sake
5044                  * of higher decompilation fidelity only, do not hoist 'var x'
5045                  * when given 'for (var x in o)'.
5046                  */
5047                 if ((
5048 #if JS_HAS_BLOCK_SCOPE
5049                      type == TOK_LET ||
5050 #endif
5051                      (type == TOK_VAR && !pn3->maybeExpr())) &&
5052                     js_NewSrcNote2(cx, cg, SRC_DECL,
5053                                    (type == TOK_VAR)
5054                                    ? SRC_DECL_VAR
5055                                    : SRC_DECL_LET) < 0) {
5056                     return JS_FALSE;
5057                 }
5058                 UpvarCookie cookie = pn3->pn_cookie;
5059                 if (!cookie.isFree()) {
5060                     op = PN_OP(pn3);
5061                     switch (op) {
5062                       case JSOP_GETARG:
5063                       case JSOP_SETARG:
5064                         op = JSOP_FORARG;
5065                         break;
5066                       case JSOP_GETLOCAL:
5067                       case JSOP_SETLOCAL:
5068                         op = JSOP_FORLOCAL;
5069                         break;
5070                       case JSOP_GETGLOBAL:
5071                         op = JSOP_FORGNAME;
5072                         cookie.makeFree();
5073                         break;
5074                       default:
5075                         JS_NOT_REACHED("unexpected opcode");
5076                     }
5077                 } else {
5078                     pn3->pn_op = JSOP_FORNAME;
5079                     if (!BindNameToSlot(cx, cg, pn3))
5080                         return JS_FALSE;
5081                     op = PN_OP(pn3);
5082                     cookie = pn3->pn_cookie;
5083                 }
5084                 if (pn3->isConst()) {
5085                     ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR,
5086                                              JSMSG_BAD_FOR_LEFTSIDE);
5087                     return JS_FALSE;
5088                 }
5089                 if (!cookie.isFree()) {
5090                     atomIndex = (jsatomid) cookie.asInteger();
5091                     EMIT_UINT16_IMM_OP(op, atomIndex);
5092                 } else {
5093                     if (!EmitAtomOp(cx, pn3, op, cg))
5094                         return JS_FALSE;
5095                 }
5096                 break;
5097               }
5098
5099               case TOK_DOT:
5100                 /*
5101                  * 'for (o.p in q)' can use JSOP_FORPROP only if evaluating 'o'
5102                  * has no side effects.
5103                  */
5104                 useful = JS_FALSE;
5105                 if (!CheckSideEffects(cx, cg, pn3->expr(), &useful))
5106                     return JS_FALSE;
5107                 if (!useful) {
5108                     if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE))
5109                         return JS_FALSE;
5110                     break;
5111                 }
5112                 /* FALL THROUGH */
5113
5114 #if JS_HAS_DESTRUCTURING
5115               destructuring_for:
5116 #endif
5117               default:
5118                 if (js_Emit1(cx, cg, JSOP_FORELEM) < 0)
5119                     return JS_FALSE;
5120                 JS_ASSERT(cg->stackDepth >= 2);
5121
5122 #if JS_HAS_DESTRUCTURING
5123                 if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) {
5124                     if (!EmitDestructuringOps(cx, cg, op, pn3))
5125                         return JS_FALSE;
5126                     if (js_Emit1(cx, cg, JSOP_POP) < 0)
5127                         return JS_FALSE;
5128                 } else
5129 #endif
5130                 if (pn3->pn_type == TOK_LP) {
5131                     JS_ASSERT(pn3->pn_xflags & PNX_SETCALL);
5132                     if (!js_EmitTree(cx, cg, pn3))
5133                         return JS_FALSE;
5134                     if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)
5135                         return JS_FALSE;
5136                 } else
5137 #if JS_HAS_XML_SUPPORT
5138                 if (pn3->pn_type == TOK_UNARYOP) {
5139                     JS_ASSERT(pn3->pn_op == JSOP_BINDXMLNAME);
5140                     if (!js_EmitTree(cx, cg, pn3))
5141                         return JS_FALSE;
5142                     if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)
5143                         return JS_FALSE;
5144                 } else
5145 #endif
5146                 if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))
5147                     return JS_FALSE;
5148                 break;
5149             }
5150
5151             /* The stack should be balanced around the JSOP_FOR* opcode sequence. */
5152             JS_ASSERT(cg->stackDepth == loopDepth);
5153
5154             tmp2 = CG_OFFSET(cg);
5155
5156             /* Emit code for the loop body. */
5157             if (!js_EmitTree(cx, cg, pn->pn_right))
5158                 return JS_FALSE;
5159
5160             /* Set loop and enclosing "update" offsets, for continue. */
5161             stmt = &stmtInfo;
5162             do {
5163                 stmt->update = CG_OFFSET(cg);
5164             } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
5165
5166             /*
5167              * Fixup the goto that starts the loop to jump down to JSOP_MOREITER.
5168              */
5169             CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
5170             if (js_Emit1(cx, cg, JSOP_MOREITER) < 0)
5171                 return JS_FALSE;
5172             beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
5173             if (beq < 0)
5174                 return JS_FALSE;
5175
5176             /*
5177              * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
5178              * note gets bigger.
5179              */
5180             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, beq - top))
5181                 return JS_FALSE;
5182             /* Set the first srcnote offset so we can find the start of the loop body. */
5183             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp2 - jmp))
5184                 return JS_FALSE;
5185             /* Set the second srcnote offset so we can find the closing jump. */
5186             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp))
5187                 return JS_FALSE;
5188         } else {
5189             /* C-style for (init; cond; update) ... loop. */
5190             op = JSOP_POP;
5191             pn3 = pn2->pn_kid1;
5192             if (!pn3) {
5193                 /* No initializer: emit an annotated nop for the decompiler. */
5194                 op = JSOP_NOP;
5195             } else {
5196                 cg->flags |= TCF_IN_FOR_INIT;
5197 #if JS_HAS_DESTRUCTURING
5198                 if (pn3->pn_type == TOK_ASSIGN &&
5199                     !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
5200                     return JS_FALSE;
5201                 }
5202 #endif
5203                 if (op == JSOP_POP) {
5204                     if (!js_EmitTree(cx, cg, pn3))
5205                         return JS_FALSE;
5206                     if (TokenKindIsDecl(PN_TYPE(pn3))) {
5207                         /*
5208                          * Check whether a destructuring-initialized var decl
5209                          * was optimized to a group assignment.  If so, we do
5210                          * not need to emit a pop below, so switch to a nop,
5211                          * just for the decompiler.
5212                          */
5213                         JS_ASSERT(pn3->pn_arity == PN_LIST);
5214                         if (pn3->pn_xflags & PNX_GROUPINIT)
5215                             op = JSOP_NOP;
5216                     }
5217                 }
5218                 cg->flags &= ~TCF_IN_FOR_INIT;
5219             }
5220
5221             /*
5222              * NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH).
5223              * Use tmp to hold the biased srcnote "top" offset, which differs
5224              * from the top local variable by the length of the JSOP_GOTO{,X}
5225              * emitted in between tmp and top if this loop has a condition.
5226              */
5227             noteIndex = js_NewSrcNote(cx, cg, SRC_FOR);
5228             if (noteIndex < 0 || js_Emit1(cx, cg, op) < 0)
5229                 return JS_FALSE;
5230             tmp = CG_OFFSET(cg);
5231
5232             if (pn2->pn_kid2) {
5233                 /* Goto the loop condition, which branches back to iterate. */
5234                 jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
5235                 if (jmp < 0)
5236                     return JS_FALSE;
5237             }
5238
5239             top = CG_OFFSET(cg);
5240             SET_STATEMENT_TOP(&stmtInfo, top);
5241
5242             noteIndex2 = js_NewSrcNote(cx, cg, SRC_TRACE);
5243             if (noteIndex2 < 0)
5244                 return JS_FALSE;
5245             
5246             /* Emit code for the loop body. */
5247             if (EmitTraceOp(cx, cg) < 0)
5248                 return JS_FALSE;
5249             if (!js_EmitTree(cx, cg, pn->pn_right))
5250                 return JS_FALSE;
5251
5252             /* Set the second note offset so we can find the update part. */
5253             JS_ASSERT(noteIndex != -1);
5254             tmp2 = CG_OFFSET(cg);
5255
5256             /* Set loop and enclosing "update" offsets, for continue. */
5257             stmt = &stmtInfo;
5258             do {
5259                 stmt->update = CG_OFFSET(cg);
5260             } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
5261
5262             /* Check for update code to do before the condition (if any). */
5263             pn3 = pn2->pn_kid3;
5264             if (pn3) {
5265                 op = JSOP_POP;
5266 #if JS_HAS_DESTRUCTURING
5267                 if (pn3->pn_type == TOK_ASSIGN &&
5268                     !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
5269                     return JS_FALSE;
5270                 }
5271 #endif
5272                 if (op == JSOP_POP && !js_EmitTree(cx, cg, pn3))
5273                     return JS_FALSE;
5274
5275                 /* Always emit the POP or NOP, to help the decompiler. */
5276                 if (js_Emit1(cx, cg, op) < 0)
5277                     return JS_FALSE;
5278
5279                 /* Restore the absolute line number for source note readers. */
5280                 off = (ptrdiff_t) pn->pn_pos.end.lineno;
5281                 if (CG_CURRENT_LINE(cg) != (uintN) off) {
5282                     if (js_NewSrcNote2(cx, cg, SRC_SETLINE, off) < 0)
5283                         return JS_FALSE;
5284                     CG_CURRENT_LINE(cg) = (uintN) off;
5285                 }
5286             }
5287
5288             tmp3 = CG_OFFSET(cg);
5289
5290             if (pn2->pn_kid2) {
5291                 /* Fix up the goto from top to target the loop condition. */
5292                 JS_ASSERT(jmp >= 0);
5293                 CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
5294
5295                 if (!js_EmitTree(cx, cg, pn2->pn_kid2))
5296                     return JS_FALSE;
5297             }
5298
5299             /*
5300              * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
5301              * note gets bigger.
5302              */
5303             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0,
5304                                      CG_OFFSET(cg) - top)) {
5305                 return JS_FALSE;
5306             }
5307             /* Set the first note offset so we can find the loop condition. */
5308             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
5309                                      tmp3 - tmp)) {
5310                 return JS_FALSE;
5311             }
5312             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,
5313                                      tmp2 - tmp)) {
5314                 return JS_FALSE;
5315             }
5316             /* The third note offset helps us find the loop-closing jump. */
5317             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2,
5318                                      CG_OFFSET(cg) - tmp)) {
5319                 return JS_FALSE;
5320             }
5321
5322             if (pn2->pn_kid2) {
5323                 beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
5324                 if (beq < 0)
5325                     return JS_FALSE;
5326             } else {
5327                 /* No loop condition -- emit the loop-closing jump. */
5328                 jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg));
5329                 if (jmp < 0)
5330                     return JS_FALSE;
5331             }
5332         }
5333
5334         /* Now fixup all breaks and continues (before for/in's JSOP_ENDITER). */
5335         if (!js_PopStatementCG(cx, cg))
5336             return JS_FALSE;
5337
5338         if (pn2->pn_type == TOK_IN) {
5339             if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) ||
5340                 js_Emit1(cx, cg, JSOP_ENDITER) < 0) {
5341                 return JS_FALSE;
5342             }
5343         }
5344         break;
5345
5346       case TOK_BREAK:
5347         stmt = cg->topStmt;
5348         atom = pn->pn_atom;
5349         if (atom) {
5350             ale = cg->atomList.add(cg->parser, atom);
5351             if (!ale)
5352                 return JS_FALSE;
5353             while (stmt->type != STMT_LABEL || stmt->label != atom)
5354                 stmt = stmt->down;
5355             noteType = SRC_BREAK2LABEL;
5356         } else {
5357             ale = NULL;
5358             while (!STMT_IS_LOOP(stmt) && stmt->type != STMT_SWITCH)
5359                 stmt = stmt->down;
5360             noteType = (stmt->type == STMT_SWITCH) ? SRC_NULL : SRC_BREAK;
5361         }
5362
5363         if (EmitGoto(cx, cg, stmt, &stmt->breaks, ale, noteType) < 0)
5364             return JS_FALSE;
5365         break;
5366
5367       case TOK_CONTINUE:
5368         stmt = cg->topStmt;
5369         atom = pn->pn_atom;
5370         if (atom) {
5371             /* Find the loop statement enclosed by the matching label. */
5372             JSStmtInfo *loop = NULL;
5373             ale = cg->atomList.add(cg->parser, atom);
5374             if (!ale)
5375                 return JS_FALSE;
5376             while (stmt->type != STMT_LABEL || stmt->label != atom) {
5377                 if (STMT_IS_LOOP(stmt))
5378                     loop = stmt;
5379                 stmt = stmt->down;
5380             }
5381             stmt = loop;
5382             noteType = SRC_CONT2LABEL;
5383         } else {
5384             ale = NULL;
5385             while (!STMT_IS_LOOP(stmt))
5386                 stmt = stmt->down;
5387             noteType = SRC_CONTINUE;
5388         }
5389
5390         if (EmitGoto(cx, cg, stmt, &stmt->continues, ale, noteType) < 0)
5391             return JS_FALSE;
5392         break;
5393
5394       case TOK_WITH:
5395         if (!js_EmitTree(cx, cg, pn->pn_left))
5396             return JS_FALSE;
5397         js_PushStatement(cg, &stmtInfo, STMT_WITH, CG_OFFSET(cg));
5398         if (js_Emit1(cx, cg, JSOP_ENTERWITH) < 0)
5399             return JS_FALSE;
5400
5401         /* Make blockChain determination quicker. */
5402         if (EmitBlockChain(cx, cg) < 0)
5403             return JS_FALSE;
5404         if (!js_EmitTree(cx, cg, pn->pn_right))
5405             return JS_FALSE;
5406         if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0)
5407             return JS_FALSE;
5408         ok = js_PopStatementCG(cx, cg);
5409         break;
5410
5411       case TOK_TRY:
5412       {
5413         ptrdiff_t tryStart, tryEnd, catchJump, finallyStart;
5414         intN depth;
5415         JSParseNode *lastCatch;
5416
5417         catchJump = -1;
5418
5419         /*
5420          * Push stmtInfo to track jumps-over-catches and gosubs-to-finally
5421          * for later fixup.
5422          *
5423          * When a finally block is active (STMT_FINALLY in our tree context),
5424          * non-local jumps (including jumps-over-catches) result in a GOSUB
5425          * being written into the bytecode stream and fixed-up later (c.f.
5426          * EmitBackPatchOp and BackPatch).
5427          */
5428         js_PushStatement(cg, &stmtInfo,
5429                          pn->pn_kid3 ? STMT_FINALLY : STMT_TRY,
5430                          CG_OFFSET(cg));
5431
5432         /*
5433          * Since an exception can be thrown at any place inside the try block,
5434          * we need to restore the stack and the scope chain before we transfer
5435          * the control to the exception handler.
5436          *
5437          * For that we store in a try note associated with the catch or
5438          * finally block the stack depth upon the try entry. The interpreter
5439          * uses this depth to properly unwind the stack and the scope chain.
5440          */
5441         depth = cg->stackDepth;
5442
5443         /* Mark try location for decompilation, then emit try block. */
5444         if (js_Emit1(cx, cg, JSOP_TRY) < 0)
5445             return JS_FALSE;
5446         tryStart = CG_OFFSET(cg);
5447         if (!js_EmitTree(cx, cg, pn->pn_kid1))
5448             return JS_FALSE;
5449         JS_ASSERT(depth == cg->stackDepth);
5450
5451         /* GOSUB to finally, if present. */
5452         if (pn->pn_kid3) {
5453             if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
5454                 return JS_FALSE;
5455             jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(stmtInfo));
5456             if (jmp < 0)
5457                 return JS_FALSE;
5458         }
5459
5460         /* Emit (hidden) jump over catch and/or finally. */
5461         if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
5462             return JS_FALSE;
5463         jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &catchJump);
5464         if (jmp < 0)
5465             return JS_FALSE;
5466
5467         tryEnd = CG_OFFSET(cg);
5468
5469         JSObjectBox *prevBox = NULL;
5470         /* If this try has a catch block, emit it. */
5471         pn2 = pn->pn_kid2;
5472         lastCatch = NULL;
5473         if (pn2) {
5474             uintN count = 0;    /* previous catch block's population */
5475             
5476             /*
5477              * The emitted code for a catch block looks like:
5478              *
5479              * blockchain
5480              * [throwing]                          only if 2nd+ catch block
5481              * [leaveblock]                        only if 2nd+ catch block
5482              * enterblock                          with SRC_CATCH
5483              * exception
5484              * [dup]                               only if catchguard
5485              * setlocalpop <slot>                  or destructuring code
5486              * [< catchguard code >]               if there's a catchguard
5487              * [ifeq <offset to next catch block>]         " "
5488              * [pop]                               only if catchguard
5489              * < catch block contents >
5490              * leaveblock
5491              * goto <end of catch blocks>          non-local; finally applies
5492              *
5493              * If there's no catch block without a catchguard, the last
5494              * <offset to next catch block> points to rethrow code.  This
5495              * code will [gosub] to the finally code if appropriate, and is
5496              * also used for the catch-all trynote for capturing exceptions
5497              * thrown from catch{} blocks.
5498              */
5499             for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
5500                 ptrdiff_t guardJump, catchNote;
5501
5502                 JS_ASSERT(cg->stackDepth == depth);
5503                 guardJump = GUARDJUMP(stmtInfo);
5504                 if (guardJump != -1) {
5505                     if (EmitKnownBlockChain(cx, cg, prevBox) < 0)
5506                         return JS_FALSE;
5507                 
5508                     /* Fix up and clean up previous catch block. */
5509                     CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, guardJump);
5510
5511                     /*
5512                      * Account for JSOP_ENTERBLOCK (whose block object count
5513                      * is saved below) and pushed exception object that we
5514                      * still have after the jumping from the previous guard.
5515                      */
5516                     cg->stackDepth = depth + count + 1;
5517
5518                     /*
5519                      * Move exception back to cx->exception to prepare for
5520                      * the next catch. We hide [throwing] from the decompiler
5521                      * since it compensates for the hidden JSOP_DUP at the
5522                      * start of the previous guarded catch.
5523                      */
5524                     if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
5525                         js_Emit1(cx, cg, JSOP_THROWING) < 0) {
5526                         return JS_FALSE;
5527                     }
5528                     if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
5529                         return JS_FALSE;
5530                     if (!EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, prevBox))
5531                         return JS_FALSE;
5532                     JS_ASSERT(cg->stackDepth == depth);
5533                 }
5534
5535                 /*
5536                  * Annotate the JSOP_ENTERBLOCK that's about to be generated
5537                  * by the call to js_EmitTree immediately below.  Save this
5538                  * source note's index in stmtInfo for use by the TOK_CATCH:
5539                  * case, where the length of the catch guard is set as the
5540                  * note's offset.
5541                  */
5542                 catchNote = js_NewSrcNote2(cx, cg, SRC_CATCH, 0);
5543                 if (catchNote < 0)
5544                     return JS_FALSE;
5545                 CATCHNOTE(stmtInfo) = catchNote;
5546
5547                 /*
5548                  * Emit the lexical scope and catch body.  Save the catch's
5549                  * block object population via count, for use when targeting
5550                  * guardJump at the next catch (the guard mismatch case).
5551                  */
5552                 JS_ASSERT(pn3->pn_type == TOK_LEXICALSCOPE);
5553                 count = OBJ_BLOCK_COUNT(cx, pn3->pn_objbox->object);
5554                 prevBox = pn3->pn_objbox;
5555                 if (!js_EmitTree(cx, cg, pn3))
5556                     return JS_FALSE;
5557
5558                 /* gosub <finally>, if required */
5559                 if (pn->pn_kid3) {
5560                     jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH,
5561                                           &GOSUBS(stmtInfo));
5562                     if (jmp < 0)
5563                         return JS_FALSE;
5564                     JS_ASSERT(cg->stackDepth == depth);
5565                 }
5566
5567                 /*
5568                  * Jump over the remaining catch blocks.  This will get fixed
5569                  * up to jump to after catch/finally.
5570                  */
5571                 if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
5572                     return JS_FALSE;
5573                 jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &catchJump);
5574                 if (jmp < 0)
5575                     return JS_FALSE;
5576
5577                 /*
5578                  * Save a pointer to the last catch node to handle try-finally
5579                  * and try-catch(guard)-finally special cases.
5580                  */
5581                 lastCatch = pn3->expr();
5582             }
5583         }
5584
5585         /*
5586          * Last catch guard jumps to the rethrow code sequence if none of the
5587          * guards match. Target guardJump at the beginning of the rethrow
5588          * sequence, just in case a guard expression throws and leaves the
5589          * stack unbalanced.
5590          */
5591         if (lastCatch && lastCatch->pn_kid2) {
5592             if (EmitKnownBlockChain(cx, cg, prevBox) < 0)
5593                 return JS_FALSE;
5594             
5595             CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, GUARDJUMP(stmtInfo));
5596
5597             /* Sync the stack to take into account pushed exception. */
5598             JS_ASSERT(cg->stackDepth == depth);
5599             cg->stackDepth = depth + 1;
5600
5601             /*
5602              * Rethrow the exception, delegating executing of finally if any
5603              * to the exception handler.
5604              */
5605             if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
5606                 js_Emit1(cx, cg, JSOP_THROW) < 0) {
5607                 return JS_FALSE;
5608             }
5609
5610             if (EmitBlockChain(cx, cg) < 0)
5611                 return JS_FALSE;
5612         }
5613
5614         JS_ASSERT(cg->stackDepth == depth);
5615
5616         /* Emit finally handler if any. */
5617         finallyStart = 0;   /* to quell GCC uninitialized warnings */
5618         if (pn->pn_kid3) {
5619             /*
5620              * Fix up the gosubs that might have been emitted before non-local
5621              * jumps to the finally code.
5622              */
5623             if (!BackPatch(cx, cg, GOSUBS(stmtInfo), CG_NEXT(cg), JSOP_GOSUB))
5624                 return JS_FALSE;
5625
5626             finallyStart = CG_OFFSET(cg);
5627
5628             /* Indicate that we're emitting a subroutine body. */
5629             stmtInfo.type = STMT_SUBROUTINE;
5630             if (!UpdateLineNumberNotes(cx, cg, pn->pn_kid3->pn_pos.begin.lineno))
5631                 return JS_FALSE;
5632             if (js_Emit1(cx, cg, JSOP_FINALLY) < 0 ||
5633                 !js_EmitTree(cx, cg, pn->pn_kid3) ||
5634                 js_Emit1(cx, cg, JSOP_RETSUB) < 0) {
5635                 return JS_FALSE;
5636             }
5637             JS_ASSERT(cg->stackDepth == depth);
5638         }
5639         if (!js_PopStatementCG(cx, cg))
5640             return JS_FALSE;
5641
5642         if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 ||
5643             js_Emit1(cx, cg, JSOP_NOP) < 0) {
5644             return JS_FALSE;
5645         }
5646
5647         /* Fix up the end-of-try/catch jumps to come here. */
5648         if (!BackPatch(cx, cg, catchJump, CG_NEXT(cg), JSOP_GOTO))
5649             return JS_FALSE;
5650
5651         /*
5652          * Add the try note last, to let post-order give us the right ordering
5653          * (first to last for a given nesting level, inner to outer by level).
5654          */
5655         if (pn->pn_kid2 &&
5656             !NewTryNote(cx, cg, JSTRY_CATCH, depth, tryStart, tryEnd)) {
5657             return JS_FALSE;
5658         }
5659
5660         /*
5661          * If we've got a finally, mark try+catch region with additional
5662          * trynote to catch exceptions (re)thrown from a catch block or
5663          * for the try{}finally{} case.
5664          */
5665         if (pn->pn_kid3 &&
5666             !NewTryNote(cx, cg, JSTRY_FINALLY, depth, tryStart, finallyStart)) {
5667             return JS_FALSE;
5668         }
5669         break;
5670       }
5671
5672       case TOK_CATCH:
5673       {
5674         ptrdiff_t catchStart, guardJump;
5675         JSObject *blockObj;
5676
5677         /*
5678          * Morph STMT_BLOCK to STMT_CATCH, note the block entry code offset,
5679          * and save the block object atom.
5680          */
5681         stmt = cg->topStmt;
5682         JS_ASSERT(stmt->type == STMT_BLOCK && (stmt->flags & SIF_SCOPE));
5683         stmt->type = STMT_CATCH;
5684         catchStart = stmt->update;
5685         blockObj = stmt->blockBox->object;
5686
5687         /* Go up one statement info record to the TRY or FINALLY record. */
5688         stmt = stmt->down;
5689         JS_ASSERT(stmt->type == STMT_TRY || stmt->type == STMT_FINALLY);
5690
5691         /* Pick up the pending exception and bind it to the catch variable. */
5692         if (js_Emit1(cx, cg, JSOP_EXCEPTION) < 0)
5693             return JS_FALSE;
5694
5695         /*
5696          * Dup the exception object if there is a guard for rethrowing to use
5697          * it later when rethrowing or in other catches.
5698          */
5699         if (pn->pn_kid2 && js_Emit1(cx, cg, JSOP_DUP) < 0)
5700             return JS_FALSE;
5701
5702         pn2 = pn->pn_kid1;
5703         switch (pn2->pn_type) {
5704 #if JS_HAS_DESTRUCTURING
5705           case TOK_RB:
5706           case TOK_RC:
5707             if (!EmitDestructuringOps(cx, cg, JSOP_NOP, pn2))
5708                 return JS_FALSE;
5709             if (js_Emit1(cx, cg, JSOP_POP) < 0)
5710                 return JS_FALSE;
5711             break;
5712 #endif
5713
5714           case TOK_NAME:
5715             /* Inline and specialize BindNameToSlot for pn2. */
5716             JS_ASSERT(!pn2->pn_cookie.isFree());
5717             EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, pn2->pn_cookie.asInteger());
5718             break;
5719
5720           default:
5721             JS_ASSERT(0);
5722         }
5723
5724         /* Emit the guard expression, if there is one. */
5725         if (pn->pn_kid2) {
5726             if (!js_EmitTree(cx, cg, pn->pn_kid2))
5727                 return JS_FALSE;
5728             if (!js_SetSrcNoteOffset(cx, cg, CATCHNOTE(*stmt), 0,
5729                                      CG_OFFSET(cg) - catchStart)) {
5730                 return JS_FALSE;
5731             }
5732             /* ifeq <next block> */
5733             guardJump = EmitJump(cx, cg, JSOP_IFEQ, 0);
5734             if (guardJump < 0)
5735                 return JS_FALSE;
5736             GUARDJUMP(*stmt) = guardJump;
5737
5738             /* Pop duplicated exception object as we no longer need it. */
5739             if (js_Emit1(cx, cg, JSOP_POP) < 0)
5740                 return JS_FALSE;
5741         }
5742
5743         /* Emit the catch body. */
5744         if (!js_EmitTree(cx, cg, pn->pn_kid3))
5745             return JS_FALSE;
5746
5747         /*
5748          * Annotate the JSOP_LEAVEBLOCK that will be emitted as we unwind via
5749          * our TOK_LEXICALSCOPE parent, so the decompiler knows to pop.
5750          */
5751         off = cg->stackDepth;
5752         if (js_NewSrcNote2(cx, cg, SRC_CATCH, off) < 0)
5753             return JS_FALSE;
5754         break;
5755       }
5756
5757       case TOK_VAR:
5758         if (!EmitVariables(cx, cg, pn, JS_FALSE, &noteIndex))
5759             return JS_FALSE;
5760         break;
5761
5762       case TOK_RETURN:
5763         /* Push a return value */
5764         pn2 = pn->pn_kid;
5765         if (pn2) {
5766             if (!js_EmitTree(cx, cg, pn2))
5767                 return JS_FALSE;
5768         } else {
5769             if (js_Emit1(cx, cg, JSOP_PUSH) < 0)
5770                 return JS_FALSE;
5771         }
5772
5773         /*
5774          * EmitNonLocalJumpFixup may add fixup bytecode to close open try
5775          * blocks having finally clauses and to exit intermingled let blocks.
5776          * We can't simply transfer control flow to our caller in that case,
5777          * because we must gosub to those finally clauses from inner to outer,
5778          * with the correct stack pointer (i.e., after popping any with,
5779          * for/in, etc., slots nested inside the finally's try).
5780          *
5781          * In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an
5782          * extra JSOP_RETRVAL after the fixups.
5783          */
5784         top = CG_OFFSET(cg);
5785         if (js_Emit1(cx, cg, JSOP_RETURN) < 0)
5786             return JS_FALSE;
5787         if (!EmitNonLocalJumpFixup(cx, cg, NULL))
5788             return JS_FALSE;
5789         if (top + JSOP_RETURN_LENGTH != CG_OFFSET(cg)) {
5790             CG_BASE(cg)[top] = JSOP_SETRVAL;
5791             if (js_Emit1(cx, cg, JSOP_RETRVAL) < 0)
5792                 return JS_FALSE;
5793             if (EmitBlockChain(cx, cg) < 0)
5794                 return JS_FALSE;
5795         }
5796         break;
5797
5798 #if JS_HAS_GENERATORS
5799       case TOK_YIELD:
5800         if (!cg->inFunction()) {
5801             ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR,
5802                                      JSMSG_BAD_RETURN_OR_YIELD,
5803                                      js_yield_str);
5804             return JS_FALSE;
5805         }
5806         if (pn->pn_kid) {
5807             if (!js_EmitTree(cx, cg, pn->pn_kid))
5808                 return JS_FALSE;
5809         } else {
5810             if (js_Emit1(cx, cg, JSOP_PUSH) < 0)
5811                 return JS_FALSE;
5812         }
5813         if (pn->pn_hidden && js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
5814             return JS_FALSE;
5815         if (js_Emit1(cx, cg, JSOP_YIELD) < 0)
5816             return JS_FALSE;
5817         break;
5818 #endif
5819
5820       case TOK_LC:
5821       {
5822 #if JS_HAS_XML_SUPPORT
5823         if (pn->pn_arity == PN_UNARY) {
5824             if (!js_EmitTree(cx, cg, pn->pn_kid))
5825                 return JS_FALSE;
5826             if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
5827                 return JS_FALSE;
5828             break;
5829         }
5830 #endif
5831
5832         JS_ASSERT(pn->pn_arity == PN_LIST);
5833
5834         noteIndex = -1;
5835         tmp = CG_OFFSET(cg);
5836         if (pn->pn_xflags & PNX_NEEDBRACES) {
5837             noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0);
5838             if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0)
5839                 return JS_FALSE;
5840         }
5841
5842         js_PushStatement(cg, &stmtInfo, STMT_BLOCK, top);
5843
5844         JSParseNode *pnchild = pn->pn_head;
5845         if (pn->pn_xflags & PNX_FUNCDEFS) {
5846             /*
5847              * This block contains top-level function definitions. To ensure
5848              * that we emit the bytecode defining them before the rest of code
5849              * in the block we use a separate pass over functions. During the
5850              * main pass later the emitter will add JSOP_NOP with source notes
5851              * for the function to preserve the original functions position
5852              * when decompiling.
5853              *
5854              * Currently this is used only for functions, as compile-as-we go
5855              * mode for scripts does not allow separate emitter passes.
5856              */
5857             JS_ASSERT(cg->inFunction());
5858             if (pn->pn_xflags & PNX_DESTRUCT) {
5859                 /*
5860                  * Assign the destructuring arguments before defining any
5861                  * functions, see bug 419662.
5862                  */
5863                 JS_ASSERT(pnchild->pn_type == TOK_SEMI);
5864                 JS_ASSERT(pnchild->pn_kid->pn_type == TOK_VAR);
5865                 if (!js_EmitTree(cx, cg, pnchild))
5866                     return JS_FALSE;
5867                 pnchild = pnchild->pn_next;
5868             }
5869
5870             for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
5871                 if (pn2->pn_type == TOK_FUNCTION) {
5872                     if (pn2->pn_op == JSOP_NOP) {
5873                         if (!js_EmitTree(cx, cg, pn2))
5874                             return JS_FALSE;
5875                     } else {
5876                         /*
5877                          * JSOP_DEFFUN in a top-level block with function
5878                          * definitions appears, for example, when "if (true)"
5879                          * is optimized away from "if (true) function x() {}".
5880                          * See bug 428424.
5881                          */
5882                         JS_ASSERT(pn2->pn_op == JSOP_DEFFUN);
5883                     }
5884                 }
5885             }
5886         }
5887         for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
5888             if (!js_EmitTree(cx, cg, pn2))
5889                 return JS_FALSE;
5890         }
5891
5892         if (noteIndex >= 0 &&
5893             !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
5894                                  CG_OFFSET(cg) - tmp)) {
5895             return JS_FALSE;
5896         }
5897
5898         ok = js_PopStatementCG(cx, cg);
5899         break;
5900       }
5901
5902       case TOK_SEQ:
5903         JS_ASSERT(pn->pn_arity == PN_LIST);
5904         js_PushStatement(cg, &stmtInfo, STMT_SEQ, top);
5905         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
5906             if (!js_EmitTree(cx, cg, pn2))
5907                 return JS_FALSE;
5908         }
5909         ok = js_PopStatementCG(cx, cg);
5910         break;
5911
5912       case TOK_SEMI:
5913         pn2 = pn->pn_kid;
5914         if (pn2) {
5915             /*
5916              * Top-level or called-from-a-native JS_Execute/EvaluateScript,
5917              * debugger, and eval frames may need the value of the ultimate
5918              * expression statement as the script's result, despite the fact
5919              * that it appears useless to the compiler.
5920              *
5921              * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
5922              * calling JS_Compile* to suppress JSOP_POPV.
5923              */
5924             useful = wantval = !(cg->flags & (TCF_IN_FUNCTION | TCF_NO_SCRIPT_RVAL));
5925
5926             /* Don't eliminate expressions with side effects. */
5927             if (!useful) {
5928                 if (!CheckSideEffects(cx, cg, pn2, &useful))
5929                     return JS_FALSE;
5930             }
5931
5932             /*
5933              * Don't eliminate apparently useless expressions if they are
5934              * labeled expression statements.  The tc->topStmt->update test
5935              * catches the case where we are nesting in js_EmitTree for a
5936              * labeled compound statement.
5937              */
5938             if (!useful &&
5939                 cg->topStmt &&
5940                 cg->topStmt->type == STMT_LABEL &&
5941                 cg->topStmt->update >= CG_OFFSET(cg)) {
5942                 useful = true;
5943             }
5944
5945             if (!useful) {
5946                 /* Don't complain about directive prologue members; just don't emit their code. */
5947                 if (!pn->isDirectivePrologueMember()) {
5948                     CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno;
5949                     if (!ReportCompileErrorNumber(cx, CG_TS(cg), pn2,
5950                                                   JSREPORT_WARNING | JSREPORT_STRICT,
5951                                                   JSMSG_USELESS_EXPR)) {
5952                         return JS_FALSE;
5953                     }
5954                 }
5955             } else {
5956                 op = wantval ? JSOP_POPV : JSOP_POP;
5957 #if JS_HAS_DESTRUCTURING
5958                 if (!wantval &&
5959                     pn2->pn_type == TOK_ASSIGN &&
5960                     !MaybeEmitGroupAssignment(cx, cg, op, pn2, &op)) {
5961                     return JS_FALSE;
5962                 }
5963 #endif
5964                 if (op != JSOP_NOP) {
5965                     /*
5966                      * Specialize JSOP_SETPROP to JSOP_SETMETHOD to defer or
5967                      * avoid null closure cloning. Do this only for assignment
5968                      * statements that are not completion values wanted by a
5969                      * script evaluator, to ensure that the joined function
5970                      * can't escape directly.
5971                      */
5972                     if (!wantval &&
5973                         PN_TYPE(pn2) == TOK_ASSIGN &&
5974                         PN_OP(pn2) == JSOP_NOP &&
5975                         PN_OP(pn2->pn_left) == JSOP_SETPROP &&
5976                         PN_OP(pn2->pn_right) == JSOP_LAMBDA &&
5977                         pn2->pn_right->pn_funbox->joinable()) {
5978                         pn2->pn_left->pn_op = JSOP_SETMETHOD;
5979                     }
5980                     if (!js_EmitTree(cx, cg, pn2))
5981                         return JS_FALSE;
5982                     if (js_Emit1(cx, cg, op) < 0)
5983                         return JS_FALSE;
5984                 }
5985             }
5986         }
5987         break;
5988
5989       case TOK_COLON:
5990         /* Emit an annotated nop so we know to decompile a label. */
5991         atom = pn->pn_atom;
5992         ale = cg->atomList.add(cg->parser, atom);
5993         if (!ale)
5994             return JS_FALSE;
5995         pn2 = pn->expr();
5996         noteType = (pn2->pn_type == TOK_LC ||
5997                     (pn2->pn_type == TOK_LEXICALSCOPE &&
5998                      pn2->expr()->pn_type == TOK_LC))
5999                    ? SRC_LABELBRACE
6000                    : SRC_LABEL;
6001         noteIndex = js_NewSrcNote2(cx, cg, noteType,
6002                                    (ptrdiff_t) ALE_INDEX(ale));
6003         if (noteIndex < 0 ||
6004             js_Emit1(cx, cg, JSOP_NOP) < 0) {
6005             return JS_FALSE;
6006         }
6007
6008         /* Emit code for the labeled statement. */
6009         js_PushStatement(cg, &stmtInfo, STMT_LABEL, CG_OFFSET(cg));
6010         stmtInfo.label = atom;
6011         if (!js_EmitTree(cx, cg, pn2))
6012             return JS_FALSE;
6013         if (!js_PopStatementCG(cx, cg))
6014             return JS_FALSE;
6015
6016         /* If the statement was compound, emit a note for the end brace. */
6017         if (noteType == SRC_LABELBRACE) {
6018             if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 ||
6019                 js_Emit1(cx, cg, JSOP_NOP) < 0) {
6020                 return JS_FALSE;
6021             }
6022         }
6023         break;
6024
6025       case TOK_COMMA:
6026         /*
6027          * Emit SRC_PCDELTA notes on each JSOP_POP between comma operands.
6028          * These notes help the decompiler bracket the bytecodes generated
6029          * from each sub-expression that follows a comma.
6030          */
6031         off = noteIndex = -1;
6032         for (pn2 = pn->pn_head; ; pn2 = pn2->pn_next) {
6033             if (!js_EmitTree(cx, cg, pn2))
6034                 return JS_FALSE;
6035             tmp = CG_OFFSET(cg);
6036             if (noteIndex >= 0) {
6037                 if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))
6038                     return JS_FALSE;
6039             }
6040             if (!pn2->pn_next)
6041                 break;
6042             off = tmp;
6043             noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
6044             if (noteIndex < 0 ||
6045                 js_Emit1(cx, cg, JSOP_POP) < 0) {
6046                 return JS_FALSE;
6047             }
6048         }
6049         break;
6050
6051       case TOK_ASSIGN:
6052         /*
6053          * Check left operand type and generate specialized code for it.
6054          * Specialize to avoid ECMA "reference type" values on the operand
6055          * stack, which impose pervasive runtime "GetValue" costs.
6056          */
6057         pn2 = pn->pn_left;
6058         atomIndex = (jsatomid) -1;              /* quell GCC overwarning */
6059         switch (PN_TYPE(pn2)) {
6060           case TOK_NAME:
6061             if (!BindNameToSlot(cx, cg, pn2))
6062                 return JS_FALSE;
6063             if (!pn2->pn_cookie.isFree()) {
6064                 atomIndex = (jsatomid) pn2->pn_cookie.asInteger();
6065             } else {
6066                 ale = cg->atomList.add(cg->parser, pn2->pn_atom);
6067                 if (!ale)
6068                     return JS_FALSE;
6069                 atomIndex = ALE_INDEX(ale);
6070                 if (!pn2->isConst()) {
6071                     JSOp op = PN_OP(pn2) == JSOP_SETGNAME ? JSOP_BINDGNAME : JSOP_BINDNAME;
6072                     EMIT_INDEX_OP(op, atomIndex);
6073                 }
6074             }
6075             break;
6076           case TOK_DOT:
6077             if (!js_EmitTree(cx, cg, pn2->expr()))
6078                 return JS_FALSE;
6079             ale = cg->atomList.add(cg->parser, pn2->pn_atom);
6080             if (!ale)
6081                 return JS_FALSE;
6082             atomIndex = ALE_INDEX(ale);
6083             break;
6084           case TOK_LB:
6085             JS_ASSERT(pn2->pn_arity == PN_BINARY);
6086             if (!js_EmitTree(cx, cg, pn2->pn_left))
6087                 return JS_FALSE;
6088             if (!js_EmitTree(cx, cg, pn2->pn_right))
6089                 return JS_FALSE;
6090             break;
6091 #if JS_HAS_DESTRUCTURING
6092           case TOK_RB:
6093           case TOK_RC:
6094             break;
6095 #endif
6096           case TOK_LP:
6097             if (!js_EmitTree(cx, cg, pn2))
6098                 return JS_FALSE;
6099             break;
6100 #if JS_HAS_XML_SUPPORT
6101           case TOK_UNARYOP:
6102             JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME);
6103             if (!js_EmitTree(cx, cg, pn2->pn_kid))
6104                 return JS_FALSE;
6105             if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0)
6106                 return JS_FALSE;
6107             break;
6108 #endif
6109           default:
6110             JS_ASSERT(0);
6111         }
6112
6113         op = PN_OP(pn);
6114         if (op != JSOP_NOP) {
6115             switch (pn2->pn_type) {
6116               case TOK_NAME:
6117                 if (pn2->isConst()) {
6118                     if (PN_OP(pn2) == JSOP_CALLEE) {
6119                         if (js_Emit1(cx, cg, JSOP_CALLEE) < 0)
6120                             return JS_FALSE;
6121                     } else {
6122                         EMIT_INDEX_OP(PN_OP(pn2), atomIndex);
6123                     }
6124                 } else if (PN_OP(pn2) == JSOP_SETNAME) {
6125                     if (js_Emit1(cx, cg, JSOP_DUP) < 0)
6126                         return JS_FALSE;
6127                     EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex);
6128                 } else if (PN_OP(pn2) == JSOP_SETGNAME) {
6129                     if (!BindGlobal(cx, cg, pn2, pn2->pn_atom))
6130                         return JS_FALSE;
6131                     if (pn2->pn_cookie.isFree())
6132                         EmitAtomOp(cx, pn2, JSOP_GETGNAME, cg);
6133                     else
6134                         EMIT_UINT16_IMM_OP(JSOP_GETGLOBAL, pn2->pn_cookie.asInteger());
6135                 } else {
6136                     EMIT_UINT16_IMM_OP((PN_OP(pn2) == JSOP_SETARG)
6137                                        ? JSOP_GETARG
6138                                        : JSOP_GETLOCAL,
6139                                        atomIndex);
6140                 }
6141                 break;
6142               case TOK_DOT:
6143                 if (js_Emit1(cx, cg, JSOP_DUP) < 0)
6144                     return JS_FALSE;
6145                 if (pn2->pn_atom == cx->runtime->atomState.lengthAtom) {
6146                     if (js_Emit1(cx, cg, JSOP_LENGTH) < 0)
6147                         return JS_FALSE;
6148                 } else if (pn2->pn_atom == cx->runtime->atomState.protoAtom) {
6149                     if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, cg))
6150                         return JS_FALSE;
6151                     if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
6152                         return JS_FALSE;
6153                 } else {
6154                     EMIT_INDEX_OP(JSOP_GETPROP, atomIndex);
6155                 }
6156                 break;
6157               case TOK_LB:
6158               case TOK_LP:
6159 #if JS_HAS_XML_SUPPORT
6160               case TOK_UNARYOP:
6161 #endif
6162                 if (js_Emit1(cx, cg, JSOP_DUP2) < 0)
6163                     return JS_FALSE;
6164                 if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
6165                     return JS_FALSE;
6166                 break;
6167               default:;
6168             }
6169         }
6170
6171         /* Now emit the right operand (it may affect the namespace). */
6172         if (!js_EmitTree(cx, cg, pn->pn_right))
6173             return JS_FALSE;
6174
6175         /* If += etc., emit the binary operator with a decompiler note. */
6176         if (op != JSOP_NOP) {
6177             /*
6178              * Take care to avoid SRC_ASSIGNOP if the left-hand side is a const
6179              * declared in the current compilation unit, as in this case (just
6180              * a bit further below) we will avoid emitting the assignment op.
6181              */
6182             if (pn2->pn_type != TOK_NAME || !pn2->isConst()) {
6183                 if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0)
6184                     return JS_FALSE;
6185             }
6186             if (js_Emit1(cx, cg, op) < 0)
6187                 return JS_FALSE;
6188         }
6189
6190         /* Left parts such as a.b.c and a[b].c need a decompiler note. */
6191         if (pn2->pn_type != TOK_NAME &&
6192 #if JS_HAS_DESTRUCTURING
6193             pn2->pn_type != TOK_RB &&
6194             pn2->pn_type != TOK_RC &&
6195 #endif
6196             js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) {
6197             return JS_FALSE;
6198         }
6199
6200         /* Finally, emit the specialized assignment bytecode. */
6201         switch (pn2->pn_type) {
6202           case TOK_NAME:
6203             if (pn2->isConst())
6204                 break;
6205             /* FALL THROUGH */
6206           case TOK_DOT:
6207             EMIT_INDEX_OP(PN_OP(pn2), atomIndex);
6208             break;
6209           case TOK_LB:
6210           case TOK_LP:
6211             if (js_Emit1(cx, cg, JSOP_SETELEM) < 0)
6212                 return JS_FALSE;
6213             break;
6214 #if JS_HAS_DESTRUCTURING
6215           case TOK_RB:
6216           case TOK_RC:
6217             if (!EmitDestructuringOps(cx, cg, JSOP_SETNAME, pn2))
6218                 return JS_FALSE;
6219             break;
6220 #endif
6221 #if JS_HAS_XML_SUPPORT
6222           case TOK_UNARYOP:
6223             if (js_Emit1(cx, cg, JSOP_SETXMLNAME) < 0)
6224                 return JS_FALSE;
6225             break;
6226 #endif
6227           default:
6228             JS_ASSERT(0);
6229         }
6230         break;
6231
6232       case TOK_HOOK:
6233         /* Emit the condition, then branch if false to the else part. */
6234         if (!js_EmitTree(cx, cg, pn->pn_kid1))
6235             return JS_FALSE;
6236         noteIndex = js_NewSrcNote(cx, cg, SRC_COND);
6237         if (noteIndex < 0)
6238             return JS_FALSE;
6239         beq = EmitJump(cx, cg, JSOP_IFEQ, 0);
6240         if (beq < 0 || !js_EmitTree(cx, cg, pn->pn_kid2))
6241             return JS_FALSE;
6242
6243         /* Jump around else, fixup the branch, emit else, fixup jump. */
6244         jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
6245         if (jmp < 0)
6246             return JS_FALSE;
6247         CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
6248
6249         /*
6250          * Because each branch pushes a single value, but our stack budgeting
6251          * analysis ignores branches, we now have to adjust cg->stackDepth to
6252          * ignore the value pushed by the first branch.  Execution will follow
6253          * only one path, so we must decrement cg->stackDepth.
6254          *
6255          * Failing to do this will foil code, such as the try/catch/finally
6256          * exception handling code generator, that samples cg->stackDepth for
6257          * use at runtime (JSOP_SETSP), or in let expression and block code
6258          * generation, which must use the stack depth to compute local stack
6259          * indexes correctly.
6260          */
6261         JS_ASSERT(cg->stackDepth > 0);
6262         cg->stackDepth--;
6263         if (!js_EmitTree(cx, cg, pn->pn_kid3))
6264             return JS_FALSE;
6265         CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
6266         if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, jmp - beq))
6267             return JS_FALSE;
6268         break;
6269
6270       case TOK_OR:
6271       case TOK_AND:
6272         /*
6273          * JSOP_OR converts the operand on the stack to boolean, and if true,
6274          * leaves the original operand value on the stack and jumps; otherwise
6275          * it pops and falls into the next bytecode, which evaluates the right
6276          * operand.  The jump goes around the right operand evaluation.
6277          *
6278          * JSOP_AND converts the operand on the stack to boolean, and if false,
6279          * leaves the original operand value on the stack and jumps; otherwise
6280          * it pops and falls into the right operand's bytecode.
6281          */
6282         if (pn->pn_arity == PN_BINARY) {
6283             if (!js_EmitTree(cx, cg, pn->pn_left))
6284                 return JS_FALSE;
6285             top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);
6286             if (top < 0)
6287                 return JS_FALSE;
6288             if (!js_EmitTree(cx, cg, pn->pn_right))
6289                 return JS_FALSE;
6290             off = CG_OFFSET(cg);
6291             pc = CG_CODE(cg, top);
6292             CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top);
6293             *pc = pn->pn_op;
6294         } else {
6295             JS_ASSERT(pn->pn_arity == PN_LIST);
6296             JS_ASSERT(pn->pn_head->pn_next->pn_next);
6297
6298             /* Left-associative operator chain: avoid too much recursion. */
6299             pn2 = pn->pn_head;
6300             if (!js_EmitTree(cx, cg, pn2))
6301                 return JS_FALSE;
6302             top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);
6303             if (top < 0)
6304                 return JS_FALSE;
6305
6306             /* Emit nodes between the head and the tail. */
6307             jmp = top;
6308             while ((pn2 = pn2->pn_next)->pn_next) {
6309                 if (!js_EmitTree(cx, cg, pn2))
6310                     return JS_FALSE;
6311                 off = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);
6312                 if (off < 0)
6313                     return JS_FALSE;
6314                 if (!SetBackPatchDelta(cx, cg, CG_CODE(cg, jmp), off - jmp))
6315                     return JS_FALSE;
6316                 jmp = off;
6317
6318             }
6319             if (!js_EmitTree(cx, cg, pn2))
6320                 return JS_FALSE;
6321
6322             pn2 = pn->pn_head;
6323             off = CG_OFFSET(cg);
6324             do {
6325                 pc = CG_CODE(cg, top);
6326                 tmp = GetJumpOffset(cg, pc);
6327                 CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top);
6328                 *pc = pn->pn_op;
6329                 top += tmp;
6330             } while ((pn2 = pn2->pn_next)->pn_next);
6331         }
6332         break;
6333
6334       case TOK_PLUS:
6335       case TOK_BITOR:
6336       case TOK_BITXOR:
6337       case TOK_BITAND:
6338       case TOK_EQOP:
6339       case TOK_RELOP:
6340       case TOK_IN:
6341       case TOK_INSTANCEOF:
6342       case TOK_SHOP:
6343       case TOK_MINUS:
6344       case TOK_STAR:
6345       case TOK_DIVOP:
6346         if (pn->pn_arity == PN_LIST) {
6347             /* Left-associative operator chain: avoid too much recursion. */
6348             pn2 = pn->pn_head;
6349             if (!js_EmitTree(cx, cg, pn2))
6350                 return JS_FALSE;
6351             op = PN_OP(pn);
6352             while ((pn2 = pn2->pn_next) != NULL) {
6353                 if (!js_EmitTree(cx, cg, pn2))
6354                     return JS_FALSE;
6355                 if (js_Emit1(cx, cg, op) < 0)
6356                     return JS_FALSE;
6357             }
6358         } else {
6359 #if JS_HAS_XML_SUPPORT
6360             uintN oldflags;
6361
6362       case TOK_DBLCOLON:
6363             if (pn->pn_arity == PN_NAME) {
6364                 if (!js_EmitTree(cx, cg, pn->expr()))
6365                     return JS_FALSE;
6366                 if (!EmitAtomOp(cx, pn, PN_OP(pn), cg))
6367                     return JS_FALSE;
6368                 break;
6369             }
6370
6371             /*
6372              * Binary :: has a right operand that brackets arbitrary code,
6373              * possibly including a let (a = b) ... expression.  We must clear
6374              * TCF_IN_FOR_INIT to avoid mis-compiling such beasts.
6375              */
6376             oldflags = cg->flags;
6377             cg->flags &= ~TCF_IN_FOR_INIT;
6378 #endif
6379
6380             /* Binary operators that evaluate both operands unconditionally. */
6381             if (!js_EmitTree(cx, cg, pn->pn_left))
6382                 return JS_FALSE;
6383             if (!js_EmitTree(cx, cg, pn->pn_right))
6384                 return JS_FALSE;
6385 #if JS_HAS_XML_SUPPORT
6386             cg->flags |= oldflags & TCF_IN_FOR_INIT;
6387 #endif
6388             if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
6389                 return JS_FALSE;
6390         }
6391         break;
6392
6393       case TOK_THROW:
6394 #if JS_HAS_XML_SUPPORT
6395       case TOK_AT:
6396       case TOK_DEFAULT:
6397         JS_ASSERT(pn->pn_arity == PN_UNARY);
6398         /* FALL THROUGH */
6399 #endif
6400       case TOK_UNARYOP:
6401       {
6402         uintN oldflags;
6403
6404         /* Unary op, including unary +/-. */
6405         op = PN_OP(pn);
6406 #if JS_HAS_XML_SUPPORT
6407         if (op == JSOP_XMLNAME) {
6408             if (!EmitXMLName(cx, pn, op, cg))
6409                 return JS_FALSE;
6410             break;
6411         }
6412 #endif
6413         pn2 = pn->pn_kid;
6414
6415         if (op == JSOP_TYPEOF && pn2->pn_type != TOK_NAME)
6416             op = JSOP_TYPEOFEXPR;
6417
6418         oldflags = cg->flags;
6419         cg->flags &= ~TCF_IN_FOR_INIT;
6420         if (!js_EmitTree(cx, cg, pn2))
6421             return JS_FALSE;
6422         cg->flags |= oldflags & TCF_IN_FOR_INIT;
6423         if (js_Emit1(cx, cg, op) < 0)
6424             return JS_FALSE;
6425         break;
6426       }
6427
6428       case TOK_INC:
6429       case TOK_DEC:
6430         /* Emit lvalue-specialized code for ++/-- operators. */
6431         pn2 = pn->pn_kid;
6432         JS_ASSERT(pn2->pn_type != TOK_RP);
6433         op = PN_OP(pn);
6434         switch (pn2->pn_type) {
6435           default:
6436             JS_ASSERT(pn2->pn_type == TOK_NAME);
6437             pn2->pn_op = op;
6438             if (!BindNameToSlot(cx, cg, pn2))
6439                 return JS_FALSE;
6440             op = PN_OP(pn2);
6441             if (op == JSOP_CALLEE) {
6442                 if (js_Emit1(cx, cg, op) < 0)
6443                     return JS_FALSE;
6444             } else if (!pn2->pn_cookie.isFree()) {
6445                 atomIndex = (jsatomid) pn2->pn_cookie.asInteger();
6446                 EMIT_UINT16_IMM_OP(op, atomIndex);
6447             } else {
6448                 JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
6449                 if (!EmitAtomOp(cx, pn2, op, cg))
6450                     return JS_FALSE;
6451                 break;
6452             }
6453             if (pn2->isConst()) {
6454                 if (js_Emit1(cx, cg, JSOP_POS) < 0)
6455                     return JS_FALSE;
6456                 op = PN_OP(pn);
6457                 if (!(js_CodeSpec[op].format & JOF_POST)) {
6458                     if (js_Emit1(cx, cg, JSOP_ONE) < 0)
6459                         return JS_FALSE;
6460                     op = (js_CodeSpec[op].format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
6461                     if (js_Emit1(cx, cg, op) < 0)
6462                         return JS_FALSE;
6463                 }
6464             }
6465             break;
6466           case TOK_DOT:
6467             if (!EmitPropOp(cx, pn2, op, cg, JS_FALSE))
6468                 return JS_FALSE;
6469             break;
6470           case TOK_LB:
6471             if (!EmitElemOp(cx, pn2, op, cg))
6472                 return JS_FALSE;
6473             break;
6474           case TOK_LP:
6475             if (!js_EmitTree(cx, cg, pn2))
6476                 return JS_FALSE;
6477             if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
6478                                CG_OFFSET(cg) - pn2->pn_offset) < 0) {
6479                 return JS_FALSE;
6480             }
6481             if (js_Emit1(cx, cg, op) < 0)
6482                 return JS_FALSE;
6483             break;
6484 #if JS_HAS_XML_SUPPORT
6485           case TOK_UNARYOP:
6486             JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME);
6487             if (!js_EmitTree(cx, cg, pn2->pn_kid))
6488                 return JS_FALSE;
6489             if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0)
6490                 return JS_FALSE;
6491             if (js_Emit1(cx, cg, op) < 0)
6492                 return JS_FALSE;
6493             break;
6494 #endif
6495         }
6496         break;
6497
6498       case TOK_DELETE:
6499         /*
6500          * Under ECMA 3, deleting a non-reference returns true -- but alas we
6501          * must evaluate the operand if it appears it might have side effects.
6502          */
6503         pn2 = pn->pn_kid;
6504         switch (pn2->pn_type) {
6505           case TOK_NAME:
6506             if (!BindNameToSlot(cx, cg, pn2))
6507                 return JS_FALSE;
6508             op = PN_OP(pn2);
6509             if (op == JSOP_FALSE) {
6510                 if (js_Emit1(cx, cg, op) < 0)
6511                     return JS_FALSE;
6512             } else {
6513                 if (!EmitAtomOp(cx, pn2, op, cg))
6514                     return JS_FALSE;
6515             }
6516             break;
6517           case TOK_DOT:
6518             if (!EmitPropOp(cx, pn2, JSOP_DELPROP, cg, JS_FALSE))
6519                 return JS_FALSE;
6520             break;
6521 #if JS_HAS_XML_SUPPORT
6522           case TOK_DBLDOT:
6523             if (!EmitElemOp(cx, pn2, JSOP_DELDESC, cg))
6524                 return JS_FALSE;
6525             break;
6526 #endif
6527           case TOK_LB:
6528             if (!EmitElemOp(cx, pn2, JSOP_DELELEM, cg))
6529                 return JS_FALSE;
6530             break;
6531           default:
6532             /*
6533              * If useless, just emit JSOP_TRUE; otherwise convert delete foo()
6534              * to foo(), true (a comma expression, requiring SRC_PCDELTA).
6535              */
6536             useful = JS_FALSE;
6537             if (!CheckSideEffects(cx, cg, pn2, &useful))
6538                 return JS_FALSE;
6539             if (!useful) {
6540                 off = noteIndex = -1;
6541             } else {
6542                 JS_ASSERT_IF(pn2->pn_type == TOK_LP, !(pn2->pn_xflags & PNX_SETCALL));
6543                 if (!js_EmitTree(cx, cg, pn2))
6544                     return JS_FALSE;
6545                 off = CG_OFFSET(cg);
6546                 noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
6547                 if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
6548                     return JS_FALSE;
6549             }
6550             if (js_Emit1(cx, cg, JSOP_TRUE) < 0)
6551                 return JS_FALSE;
6552             if (noteIndex >= 0) {
6553                 tmp = CG_OFFSET(cg);
6554                 if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))
6555                     return JS_FALSE;
6556             }
6557         }
6558         break;
6559
6560 #if JS_HAS_XML_SUPPORT
6561       case TOK_FILTER:
6562         if (!js_EmitTree(cx, cg, pn->pn_left))
6563             return JS_FALSE;
6564         jmp = EmitJump(cx, cg, JSOP_FILTER, 0);
6565         if (jmp < 0)
6566             return JS_FALSE;
6567         top = EmitTraceOp(cx, cg);
6568         if (top < 0)
6569             return JS_FALSE;
6570         if (!js_EmitTree(cx, cg, pn->pn_right))
6571             return JS_FALSE;
6572         CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
6573         if (EmitJump(cx, cg, JSOP_ENDFILTER, top - CG_OFFSET(cg)) < 0)
6574             return JS_FALSE;
6575
6576         /* Make blockChain determination quicker. */
6577         if (EmitBlockChain(cx, cg) < 0)
6578             return JS_FALSE;
6579         break;
6580 #endif
6581
6582       case TOK_DOT:
6583         /*
6584          * Pop a stack operand, convert it to object, get a property named by
6585          * this bytecode's immediate-indexed atom operand, and push its value
6586          * (not a reference to it).
6587          */
6588         ok = EmitPropOp(cx, pn, PN_OP(pn), cg, JS_FALSE);
6589         break;
6590
6591       case TOK_LB:
6592 #if JS_HAS_XML_SUPPORT
6593       case TOK_DBLDOT:
6594 #endif
6595         /*
6596          * Pop two operands, convert the left one to object and the right one
6597          * to property name (atom or tagged int), get the named property, and
6598          * push its value.  Set the "obj" register to the result of ToObject
6599          * on the left operand.
6600          */
6601         ok = EmitElemOp(cx, pn, PN_OP(pn), cg);
6602         break;
6603
6604       case TOK_NEW:
6605       case TOK_LP:
6606       {
6607         bool callop = (PN_TYPE(pn) == TOK_LP);
6608
6609         /*
6610          * Emit callable invocation or operator new (constructor call) code.
6611          * First, emit code for the left operand to evaluate the callable or
6612          * constructable object expression.
6613          *
6614          * For operator new applied to other expressions than E4X ones, we emit
6615          * JSOP_GETPROP instead of JSOP_CALLPROP, etc. This is necessary to
6616          * interpose the lambda-initialized method read barrier -- see the code
6617          * in jsinterp.cpp for JSOP_LAMBDA followed by JSOP_{SET,INIT}PROP.
6618          *
6619          * Then (or in a call case that has no explicit reference-base
6620          * object) we emit JSOP_PUSH to produce the |this| slot required
6621          * for calls (which non-strict mode functions will box into the
6622          * global object).
6623          */
6624         pn2 = pn->pn_head;
6625         switch (pn2->pn_type) {
6626           case TOK_NAME:
6627             if (!EmitNameOp(cx, cg, pn2, callop))
6628                 return JS_FALSE;
6629             break;
6630           case TOK_DOT:
6631             if (!EmitPropOp(cx, pn2, PN_OP(pn2), cg, callop))
6632                 return JS_FALSE;
6633             break;
6634           case TOK_LB:
6635             JS_ASSERT(pn2->pn_op == JSOP_GETELEM);
6636             if (!EmitElemOp(cx, pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM, cg))
6637                 return JS_FALSE;
6638             break;
6639           case TOK_UNARYOP:
6640 #if JS_HAS_XML_SUPPORT
6641             if (pn2->pn_op == JSOP_XMLNAME) {
6642                 if (!EmitXMLName(cx, pn2, JSOP_CALLXMLNAME, cg))
6643                     return JS_FALSE;
6644                 callop = true;          /* suppress JSOP_PUSH after */
6645                 break;
6646             }
6647 #endif
6648             /* FALL THROUGH */
6649           default:
6650             if (!js_EmitTree(cx, cg, pn2))
6651                 return JS_FALSE;
6652             callop = false;             /* trigger JSOP_PUSH after */
6653             break;
6654         }
6655         if (!callop && js_Emit1(cx, cg, JSOP_PUSH) < 0)
6656             return JS_FALSE;
6657
6658         /* Remember start of callable-object bytecode for decompilation hint. */
6659         off = top;
6660
6661         /*
6662          * Emit code for each argument in order, then emit the JSOP_*CALL or
6663          * JSOP_NEW bytecode with a two-byte immediate telling how many args
6664          * were pushed on the operand stack.
6665          */
6666         uintN oldflags = cg->flags;
6667         cg->flags &= ~TCF_IN_FOR_INIT;
6668         for (pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
6669             if (!js_EmitTree(cx, cg, pn3))
6670                 return JS_FALSE;
6671         }
6672         cg->flags |= oldflags & TCF_IN_FOR_INIT;
6673         if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)
6674             return JS_FALSE;
6675
6676         argc = pn->pn_count - 1;
6677         if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)
6678             return JS_FALSE;
6679         if (PN_OP(pn) == JSOP_EVAL) {
6680             EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
6681             if (EmitBlockChain(cx, cg) < 0)
6682                 return JS_FALSE;
6683         }
6684         if (pn->pn_xflags & PNX_SETCALL) {
6685             if (js_Emit1(cx, cg, JSOP_SETCALL) < 0)
6686                 return JS_FALSE;
6687         }
6688         break;
6689       }
6690
6691       case TOK_LEXICALSCOPE:
6692       {
6693         JSObjectBox *objbox;
6694
6695         objbox = pn->pn_objbox;
6696         js_PushBlockScope(cg, &stmtInfo, objbox, CG_OFFSET(cg));
6697
6698         /*
6699          * If this lexical scope is not for a catch block, let block or let
6700          * expression, or any kind of for loop (where the scope starts in the
6701          * head after the first part if for (;;), else in the body if for-in);
6702          * and if our container is top-level but not a function body, or else
6703          * a block statement; then emit a SRC_BRACE note.  All other container
6704          * statements get braces by default from the decompiler.
6705          */
6706         noteIndex = -1;
6707         type = PN_TYPE(pn->expr());
6708         if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR &&
6709             (!(stmt = stmtInfo.down)
6710              ? !cg->inFunction()
6711              : stmt->type == STMT_BLOCK)) {
6712 #if defined DEBUG_brendan || defined DEBUG_mrbkap
6713             /* There must be no source note already output for the next op. */
6714             JS_ASSERT(CG_NOTE_COUNT(cg) == 0 ||
6715                       CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) ||
6716                       !GettableNoteForNextOp(cg));
6717 #endif
6718             noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0);
6719             if (noteIndex < 0)
6720                 return JS_FALSE;
6721         }
6722
6723         JS_ASSERT(CG_OFFSET(cg) == top);
6724         if (!EmitEnterBlock(cx, pn, cg))
6725             return JS_FALSE;
6726
6727         if (!js_EmitTree(cx, cg, pn->pn_expr))
6728             return JS_FALSE;
6729
6730         op = PN_OP(pn);
6731         if (op == JSOP_LEAVEBLOCKEXPR) {
6732             if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
6733                 return JS_FALSE;
6734         } else {
6735             if (noteIndex >= 0 &&
6736                 !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
6737                                      CG_OFFSET(cg) - top)) {
6738                 return JS_FALSE;
6739             }
6740         }
6741
6742         /* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */
6743         if (!EmitLeaveBlock(cx, cg, op, objbox))
6744             return JS_FALSE;
6745
6746         ok = js_PopStatementCG(cx, cg);
6747         break;
6748       }
6749
6750 #if JS_HAS_BLOCK_SCOPE
6751       case TOK_LET:
6752         /* Let statements have their variable declarations on the left. */
6753         if (pn->pn_arity == PN_BINARY) {
6754             pn2 = pn->pn_right;
6755             pn = pn->pn_left;
6756         } else {
6757             pn2 = NULL;
6758         }
6759
6760         /* Non-null pn2 means that pn is the variable list from a let head. */
6761         JS_ASSERT(pn->pn_arity == PN_LIST);
6762         if (!EmitVariables(cx, cg, pn, pn2 != NULL, &noteIndex))
6763             return JS_FALSE;
6764
6765         /* Thus non-null pn2 is the body of the let block or expression. */
6766         tmp = CG_OFFSET(cg);
6767         if (pn2 && !js_EmitTree(cx, cg, pn2))
6768             return JS_FALSE;
6769
6770         if (noteIndex >= 0 &&
6771             !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
6772                                  CG_OFFSET(cg) - tmp)) {
6773             return JS_FALSE;
6774         }
6775         break;
6776 #endif /* JS_HAS_BLOCK_SCOPE */
6777
6778 #if JS_HAS_GENERATORS
6779       case TOK_ARRAYPUSH: {
6780         jsint slot;
6781
6782         /*
6783          * The array object's stack index is in cg->arrayCompDepth. See below
6784          * under the array initialiser code generator for array comprehension
6785          * special casing.
6786          */
6787         if (!js_EmitTree(cx, cg, pn->pn_kid))
6788             return JS_FALSE;
6789         slot = AdjustBlockSlot(cx, cg, cg->arrayCompDepth);
6790         if (slot < 0)
6791             return JS_FALSE;
6792         EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
6793         break;
6794       }
6795 #endif
6796
6797       case TOK_RB:
6798 #if JS_HAS_GENERATORS
6799       case TOK_ARRAYCOMP:
6800 #endif
6801         /*
6802          * Emit code for [a, b, c] that is equivalent to constructing a new
6803          * array and in source order evaluating each element value and adding
6804          * it to the array, without invoking latent setters.  We use the
6805          * JSOP_NEWINIT and JSOP_INITELEM bytecodes to ignore setters and to
6806          * avoid dup'ing and popping the array as each element is added, as
6807          * JSOP_SETELEM/JSOP_SETPROP would do.
6808          */
6809 #if JS_HAS_SHARP_VARS
6810         sharpnum = -1;
6811       do_emit_array:
6812 #endif
6813
6814 #if JS_HAS_GENERATORS
6815         if (pn->pn_type == TOK_ARRAYCOMP) {
6816             uintN saveDepth;
6817
6818             if (!EmitNewInit(cx, cg, JSProto_Array, pn, sharpnum))
6819                 return JS_FALSE;
6820
6821             /*
6822              * Pass the new array's stack index to the TOK_ARRAYPUSH case via
6823              * cg->arrayCompDepth, then simply traverse the TOK_FOR node and
6824              * its kids under pn2 to generate this comprehension.
6825              */
6826             JS_ASSERT(cg->stackDepth > 0);
6827             saveDepth = cg->arrayCompDepth;
6828             cg->arrayCompDepth = (uint32) (cg->stackDepth - 1);
6829             if (!js_EmitTree(cx, cg, pn->pn_head))
6830                 return JS_FALSE;
6831             cg->arrayCompDepth = saveDepth;
6832
6833             /* Emit the usual op needed for decompilation. */
6834             if (!EmitEndInit(cx, cg, 1))
6835                 return JS_FALSE;
6836             break;
6837         }
6838 #endif /* JS_HAS_GENERATORS */
6839
6840         if (!cg->hasSharps() && !(pn->pn_xflags & PNX_NONCONST) && cg->checkSingletonContext()) {
6841             if (!EmitSingletonInitialiser(cx, cg, pn))
6842                 return JS_FALSE;
6843             break;
6844         }
6845
6846         /* Use the slower NEWINIT for arrays in scripts containing sharps. */
6847         if (cg->hasSharps()) {
6848             if (!EmitNewInit(cx, cg, JSProto_Array, pn, sharpnum))
6849                 return JS_FALSE;
6850         } else {
6851             ptrdiff_t off = js_EmitN(cx, cg, JSOP_NEWARRAY, 3);
6852             if (off < 0)
6853                 return JS_FALSE;
6854             pc = CG_CODE(cg, off);
6855             SET_UINT24(pc, pn->pn_count);
6856         }
6857
6858         pn2 = pn->pn_head;
6859         for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
6860             if (!EmitNumberOp(cx, atomIndex, cg))
6861                 return JS_FALSE;
6862             if (pn2->pn_type == TOK_COMMA && pn2->pn_arity == PN_NULLARY) {
6863                 if (js_Emit1(cx, cg, JSOP_HOLE) < 0)
6864                     return JS_FALSE;
6865             } else {
6866                 if (!js_EmitTree(cx, cg, pn2))
6867                     return JS_FALSE;
6868             }
6869             if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
6870                 return JS_FALSE;
6871         }
6872         JS_ASSERT(atomIndex == pn->pn_count);
6873
6874         if (pn->pn_xflags & PNX_ENDCOMMA) {
6875             /* Emit a source note so we know to decompile an extra comma. */
6876             if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0)
6877                 return JS_FALSE;
6878         }
6879
6880         /*
6881          * Emit an op to finish the array and, secondarily, to aid in sharp
6882          * array cleanup (if JS_HAS_SHARP_VARS) and decompilation.
6883          */
6884         if (!EmitEndInit(cx, cg, atomIndex))
6885             return JS_FALSE;
6886         break;
6887
6888       case TOK_RC: {
6889 #if JS_HAS_SHARP_VARS
6890         sharpnum = -1;
6891       do_emit_object:
6892 #endif
6893 #if JS_HAS_DESTRUCTURING_SHORTHAND
6894         if (pn->pn_xflags & PNX_DESTRUCT) {
6895             ReportCompileErrorNumber(cx, CG_TS(cg), pn, JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT);
6896             return JS_FALSE;
6897         }
6898 #endif
6899
6900         if (!cg->hasSharps() && !(pn->pn_xflags & PNX_NONCONST) && cg->checkSingletonContext()) {
6901             if (!EmitSingletonInitialiser(cx, cg, pn))
6902                 return JS_FALSE;
6903             break;
6904         }
6905
6906         /*
6907          * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
6908          * a new object and in source order evaluating each property value and
6909          * adding the property to the object, without invoking latent setters.
6910          * We use the JSOP_NEWINIT and JSOP_INITELEM/JSOP_INITPROP bytecodes to
6911          * ignore setters and to avoid dup'ing and popping the object as each
6912          * property is added, as JSOP_SETELEM/JSOP_SETPROP would do.
6913          */
6914         ptrdiff_t offset = CG_NEXT(cg) - CG_BASE(cg);
6915         if (!EmitNewInit(cx, cg, JSProto_Object, pn, sharpnum))
6916             return JS_FALSE;
6917
6918         /*
6919          * Try to construct the shape of the object as we go, so we can emit a
6920          * JSOP_NEWOBJECT with the final shape instead.
6921          */
6922         JSObject *obj = NULL;
6923         if (!cg->hasSharps() && cg->compileAndGo()) {
6924             gc::FinalizeKind kind = GuessObjectGCKind(pn->pn_count, false);
6925             obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
6926             if (!obj)
6927                 return JS_FALSE;
6928         }
6929
6930         uintN methodInits = 0, slowMethodInits = 0;
6931         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
6932             /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
6933             pn3 = pn2->pn_left;
6934             if (pn3->pn_type == TOK_NUMBER) {
6935                 if (!EmitNumberOp(cx, pn3->pn_dval, cg))
6936                     return JS_FALSE;
6937             }
6938
6939             /* Emit code for the property initializer. */
6940             if (!js_EmitTree(cx, cg, pn2->pn_right))
6941                 return JS_FALSE;
6942
6943             op = PN_OP(pn2);
6944             if (op == JSOP_GETTER || op == JSOP_SETTER) {
6945                 obj = NULL;
6946                 if (js_Emit1(cx, cg, op) < 0)
6947                     return JS_FALSE;
6948             }
6949
6950             /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */
6951             if (pn3->pn_type == TOK_NUMBER) {
6952                 obj = NULL;
6953                 if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0)
6954                     return JS_FALSE;
6955                 if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
6956                     return JS_FALSE;
6957             } else {
6958                 JS_ASSERT(pn3->pn_type == TOK_NAME ||
6959                           pn3->pn_type == TOK_STRING);
6960                 ale = cg->atomList.add(cg->parser, pn3->pn_atom);
6961                 if (!ale)
6962                     return JS_FALSE;
6963
6964                 /* Check whether we can optimize to JSOP_INITMETHOD. */
6965                 JSParseNode *init = pn2->pn_right;
6966                 bool lambda = PN_OP(init) == JSOP_LAMBDA;
6967                 if (lambda)
6968                     ++methodInits;
6969                 if (op == JSOP_INITPROP && lambda && init->pn_funbox->joinable()) {
6970                     obj = NULL;
6971                     op = JSOP_INITMETHOD;
6972                     pn2->pn_op = uint8(op);
6973                 } else {
6974                     /*
6975                      * Disable NEWOBJECT on initializers that set __proto__, which has
6976                      * a non-standard setter on objects.
6977                      */
6978                     if (pn3->pn_atom == cx->runtime->atomState.protoAtom)
6979                         obj = NULL;
6980                     op = JSOP_INITPROP;
6981                     if (lambda)
6982                         ++slowMethodInits;
6983                 }
6984
6985                 if (obj) {
6986                     JS_ASSERT(!obj->inDictionaryMode());
6987                     if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(pn3->pn_atom),
6988                                                  UndefinedValue(), NULL, NULL,
6989                                                  JSPROP_ENUMERATE, 0, 0, NULL)) {
6990                         return JS_FALSE;
6991                     }
6992                     if (obj->inDictionaryMode())
6993                         obj = NULL;
6994                 }
6995
6996                 EMIT_INDEX_OP(op, ALE_INDEX(ale));
6997             }
6998         }
6999
7000         if (cg->funbox && cg->funbox->shouldUnbrand(methodInits, slowMethodInits)) {
7001             obj = NULL;
7002             if (js_Emit1(cx, cg, JSOP_UNBRAND) < 0)
7003                 return JS_FALSE;
7004         }
7005         if (!EmitEndInit(cx, cg, pn->pn_count))
7006             return JS_FALSE;
7007
7008         if (obj) {
7009             /*
7010              * The object survived and has a predictable shape.  Update the original bytecode,
7011              * as long as we can do so without using a big index prefix/suffix.
7012              */
7013             JSObjectBox *objbox = cg->parser->newObjectBox(obj);
7014             if (!objbox)
7015                 return JS_FALSE;
7016             unsigned index = cg->objectList.index(objbox);
7017             if (FitsWithoutBigIndex(index))
7018                 EMIT_UINT16_IN_PLACE(offset, JSOP_NEWOBJECT, uint16(index));
7019         }
7020
7021         break;
7022       }
7023
7024 #if JS_HAS_SHARP_VARS
7025       case TOK_DEFSHARP:
7026         JS_ASSERT(cg->hasSharps());
7027         sharpnum = pn->pn_num;
7028         pn = pn->pn_kid;
7029         if (pn->pn_type == TOK_RB)
7030             goto do_emit_array;
7031 # if JS_HAS_GENERATORS
7032         if (pn->pn_type == TOK_ARRAYCOMP)
7033             goto do_emit_array;
7034 # endif
7035         if (pn->pn_type == TOK_RC)
7036             goto do_emit_object;
7037
7038         if (!js_EmitTree(cx, cg, pn))
7039             return JS_FALSE;
7040         EMIT_UINT16PAIR_IMM_OP(JSOP_DEFSHARP, cg->sharpSlotBase, (jsatomid) sharpnum);
7041         break;
7042
7043       case TOK_USESHARP:
7044         JS_ASSERT(cg->hasSharps());
7045         EMIT_UINT16PAIR_IMM_OP(JSOP_USESHARP, cg->sharpSlotBase, (jsatomid) pn->pn_num);
7046         break;
7047 #endif /* JS_HAS_SHARP_VARS */
7048
7049       case TOK_NAME:
7050         /*
7051          * Cope with a left-over function definition that was replaced by a use
7052          * of a later function definition of the same name. See FunctionDef and
7053          * MakeDefIntoUse in jsparse.cpp.
7054          */
7055         if (pn->pn_op == JSOP_NOP)
7056             break;
7057         if (!EmitNameOp(cx, cg, pn, JS_FALSE))
7058             return JS_FALSE;
7059         break;
7060
7061 #if JS_HAS_XML_SUPPORT
7062       case TOK_XMLATTR:
7063       case TOK_XMLSPACE:
7064       case TOK_XMLTEXT:
7065       case TOK_XMLCDATA:
7066       case TOK_XMLCOMMENT:
7067 #endif
7068       case TOK_STRING:
7069         ok = EmitAtomOp(cx, pn, PN_OP(pn), cg);
7070         break;
7071
7072       case TOK_NUMBER:
7073         ok = EmitNumberOp(cx, pn->pn_dval, cg);
7074         break;
7075
7076       case TOK_REGEXP: {
7077         JS_ASSERT(pn->pn_op == JSOP_REGEXP);
7078         ok = EmitIndexOp(cx, JSOP_REGEXP,
7079                          cg->regexpList.index(pn->pn_objbox),
7080                          cg);
7081         break;
7082       }
7083
7084 #if JS_HAS_XML_SUPPORT
7085       case TOK_ANYNAME:
7086 #endif
7087       case TOK_PRIMARY:
7088         if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
7089             return JS_FALSE;
7090         break;
7091
7092       case TOK_DEBUGGER:
7093         if (js_Emit1(cx, cg, JSOP_DEBUGGER) < 0)
7094             return JS_FALSE;
7095         break;
7096
7097 #if JS_HAS_XML_SUPPORT
7098       case TOK_XMLELEM:
7099       case TOK_XMLLIST:
7100         JS_ASSERT(PN_TYPE(pn) == TOK_XMLLIST || pn->pn_count != 0);
7101         switch (pn->pn_head ? PN_TYPE(pn->pn_head) : TOK_XMLLIST) {
7102           case TOK_XMLETAGO:
7103             JS_ASSERT(0);
7104             /* FALL THROUGH */
7105           case TOK_XMLPTAGC:
7106           case TOK_XMLSTAGO:
7107             break;
7108           default:
7109             if (js_Emit1(cx, cg, JSOP_STARTXML) < 0)
7110                 return JS_FALSE;
7111         }
7112
7113         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
7114             if (pn2->pn_type == TOK_LC &&
7115                 js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) {
7116                 return JS_FALSE;
7117             }
7118             if (!js_EmitTree(cx, cg, pn2))
7119                 return JS_FALSE;
7120             if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)
7121                 return JS_FALSE;
7122         }
7123
7124         if (pn->pn_xflags & PNX_XMLROOT) {
7125             if (pn->pn_count == 0) {
7126                 JS_ASSERT(pn->pn_type == TOK_XMLLIST);
7127                 atom = cx->runtime->atomState.emptyAtom;
7128                 ale = cg->atomList.add(cg->parser, atom);
7129                 if (!ale)
7130                     return JS_FALSE;
7131                 EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
7132             }
7133             if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
7134                 return JS_FALSE;
7135         }
7136 #ifdef DEBUG
7137         else
7138             JS_ASSERT(pn->pn_count != 0);
7139 #endif
7140         break;
7141
7142       case TOK_XMLPTAGC:
7143       case TOK_XMLSTAGO:
7144       case TOK_XMLETAGO:
7145       {
7146         uint32 i;
7147
7148         if (js_Emit1(cx, cg, JSOP_STARTXML) < 0)
7149             return JS_FALSE;
7150
7151         ale = cg->atomList.add(cg->parser,
7152                                (pn->pn_type == TOK_XMLETAGO)
7153                                ? cx->runtime->atomState.etagoAtom
7154                                : cx->runtime->atomState.stagoAtom);
7155         if (!ale)
7156             return JS_FALSE;
7157         EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
7158
7159         JS_ASSERT(pn->pn_count != 0);
7160         pn2 = pn->pn_head;
7161         if (pn2->pn_type == TOK_LC && js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0)
7162             return JS_FALSE;
7163         if (!js_EmitTree(cx, cg, pn2))
7164             return JS_FALSE;
7165         if (js_Emit1(cx, cg, JSOP_ADD) < 0)
7166             return JS_FALSE;
7167
7168         for (pn2 = pn2->pn_next, i = 0; pn2; pn2 = pn2->pn_next, i++) {
7169             if (pn2->pn_type == TOK_LC &&
7170                 js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) {
7171                 return JS_FALSE;
7172             }
7173             if (!js_EmitTree(cx, cg, pn2))
7174                 return JS_FALSE;
7175             if ((i & 1) && pn2->pn_type == TOK_LC) {
7176                 if (js_Emit1(cx, cg, JSOP_TOATTRVAL) < 0)
7177                     return JS_FALSE;
7178             }
7179             if (js_Emit1(cx, cg,
7180                          (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0) {
7181                 return JS_FALSE;
7182             }
7183         }
7184
7185         ale = cg->atomList.add(cg->parser,
7186                                (pn->pn_type == TOK_XMLPTAGC)
7187                                ? cx->runtime->atomState.ptagcAtom
7188                                : cx->runtime->atomState.tagcAtom);
7189         if (!ale)
7190             return JS_FALSE;
7191         EMIT_INDEX_OP(JSOP_STRING, ALE_INDEX(ale));
7192         if (js_Emit1(cx, cg, JSOP_ADD) < 0)
7193             return JS_FALSE;
7194
7195         if ((pn->pn_xflags & PNX_XMLROOT) && js_Emit1(cx, cg, PN_OP(pn)) < 0)
7196             return JS_FALSE;
7197         break;
7198       }
7199
7200       case TOK_XMLNAME:
7201         if (pn->pn_arity == PN_LIST) {
7202             JS_ASSERT(pn->pn_count != 0);
7203             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
7204                 if (pn2->pn_type == TOK_LC &&
7205                     js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) {
7206                     return JS_FALSE;
7207                 }
7208                 if (!js_EmitTree(cx, cg, pn2))
7209                     return JS_FALSE;
7210                 if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)
7211                     return JS_FALSE;
7212             }
7213         } else {
7214             JS_ASSERT(pn->pn_arity == PN_NULLARY);
7215             ok = (pn->pn_op == JSOP_OBJECT)
7216                  ? EmitObjectOp(cx, pn->pn_objbox, PN_OP(pn), cg)
7217                  : EmitAtomOp(cx, pn, PN_OP(pn), cg);
7218         }
7219         break;
7220
7221       case TOK_XMLPI:
7222         ale = cg->atomList.add(cg->parser, pn->pn_atom2);
7223         if (!ale)
7224             return JS_FALSE;
7225         if (!EmitIndexOp(cx, JSOP_QNAMEPART, ALE_INDEX(ale), cg))
7226             return JS_FALSE;
7227         if (!EmitAtomOp(cx, pn, JSOP_XMLPI, cg))
7228             return JS_FALSE;
7229         break;
7230 #endif /* JS_HAS_XML_SUPPORT */
7231
7232       default:
7233         JS_ASSERT(0);
7234     }
7235
7236     /* cg->emitLevel == 1 means we're last on the stack, so finish up. */
7237     if (ok && cg->emitLevel == 1) {
7238         if (cg->spanDeps)
7239             ok = OptimizeSpanDeps(cx, cg);
7240         if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.end.lineno))
7241             return JS_FALSE;
7242     }
7243
7244     return ok;
7245 }
7246
7247 /*
7248  * We should try to get rid of offsetBias (always 0 or 1, where 1 is
7249  * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL.
7250  */
7251 JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
7252     {"null",            0,      0,      0},
7253     {"if",              0,      0,      0},
7254     {"if-else",         2,      0,      1},
7255     {"for",             3,      1,      1},
7256     {"while",           1,      0,      1},
7257     {"continue",        0,      0,      0},
7258     {"decl",            1,      1,      1},
7259     {"pcdelta",         1,      0,      1},
7260     {"assignop",        0,      0,      0},
7261     {"cond",            1,      0,      1},
7262     {"brace",           1,      0,      1},
7263     {"hidden",          0,      0,      0},
7264     {"pcbase",          1,      0,     -1},
7265     {"label",           1,      0,      0},
7266     {"labelbrace",      1,      0,      0},
7267     {"endbrace",        0,      0,      0},
7268     {"break2label",     1,      0,      0},
7269     {"cont2label",      1,      0,      0},
7270     {"switch",          2,      0,      1},
7271     {"funcdef",         1,      0,      0},
7272     {"catch",           1,      0,      1},
7273     {"extended",       -1,      0,      0},
7274     {"newline",         0,      0,      0},
7275     {"setline",         1,      0,      0},
7276     {"xdelta",          0,      0,      0},
7277 };
7278
7279 static intN
7280 AllocSrcNote(JSContext *cx, JSCodeGenerator *cg)
7281 {
7282     intN index;
7283     JSArenaPool *pool;
7284     size_t size;
7285
7286     index = CG_NOTE_COUNT(cg);
7287     if (((uintN)index & CG_NOTE_MASK(cg)) == 0) {
7288         pool = cg->notePool;
7289         size = SRCNOTE_SIZE(CG_NOTE_MASK(cg) + 1);
7290         if (!CG_NOTES(cg)) {
7291             /* Allocate the first note array lazily; leave noteMask alone. */
7292             JS_ARENA_ALLOCATE_CAST(CG_NOTES(cg), jssrcnote *, pool, size);
7293         } else {
7294             /* Grow by doubling note array size; update noteMask on success. */
7295             JS_ARENA_GROW_CAST(CG_NOTES(cg), jssrcnote *, pool, size, size);
7296             if (CG_NOTES(cg))
7297                 CG_NOTE_MASK(cg) = (CG_NOTE_MASK(cg) << 1) | 1;
7298         }
7299         if (!CG_NOTES(cg)) {
7300             js_ReportOutOfScriptQuota(cx);
7301             return -1;
7302         }
7303     }
7304
7305     CG_NOTE_COUNT(cg) = index + 1;
7306     return index;
7307 }
7308
7309 intN
7310 js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type)
7311 {
7312     intN index, n;
7313     jssrcnote *sn;
7314     ptrdiff_t offset, delta, xdelta;
7315
7316     /*
7317      * Claim a note slot in CG_NOTES(cg) by growing it if necessary and then
7318      * incrementing CG_NOTE_COUNT(cg).
7319      */
7320     index = AllocSrcNote(cx, cg);
7321     if (index < 0)
7322         return -1;
7323     sn = &CG_NOTES(cg)[index];
7324
7325     /*
7326      * Compute delta from the last annotated bytecode's offset.  If it's too
7327      * big to fit in sn, allocate one or more xdelta notes and reset sn.
7328      */
7329     offset = CG_OFFSET(cg);
7330     delta = offset - CG_LAST_NOTE_OFFSET(cg);
7331     CG_LAST_NOTE_OFFSET(cg) = offset;
7332     if (delta >= SN_DELTA_LIMIT) {
7333         do {
7334             xdelta = JS_MIN(delta, SN_XDELTA_MASK);
7335             SN_MAKE_XDELTA(sn, xdelta);
7336             delta -= xdelta;
7337             index = AllocSrcNote(cx, cg);
7338             if (index < 0)
7339                 return -1;
7340             sn = &CG_NOTES(cg)[index];
7341         } while (delta >= SN_DELTA_LIMIT);
7342     }
7343
7344     /*
7345      * Initialize type and delta, then allocate the minimum number of notes
7346      * needed for type's arity.  Usually, we won't need more, but if an offset
7347      * does take two bytes, js_SetSrcNoteOffset will grow CG_NOTES(cg).
7348      */
7349     SN_MAKE_NOTE(sn, type, delta);
7350     for (n = (intN)js_SrcNoteSpec[type].arity; n > 0; n--) {
7351         if (js_NewSrcNote(cx, cg, SRC_NULL) < 0)
7352             return -1;
7353     }
7354     return index;
7355 }
7356
7357 intN
7358 js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
7359                ptrdiff_t offset)
7360 {
7361     intN index;
7362
7363     index = js_NewSrcNote(cx, cg, type);
7364     if (index >= 0) {
7365         if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset))
7366             return -1;
7367     }
7368     return index;
7369 }
7370
7371 intN
7372 js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
7373                ptrdiff_t offset1, ptrdiff_t offset2)
7374 {
7375     intN index;
7376
7377     index = js_NewSrcNote(cx, cg, type);
7378     if (index >= 0) {
7379         if (!js_SetSrcNoteOffset(cx, cg, index, 0, offset1))
7380             return -1;
7381         if (!js_SetSrcNoteOffset(cx, cg, index, 1, offset2))
7382             return -1;
7383     }
7384     return index;
7385 }
7386
7387 static JSBool
7388 GrowSrcNotes(JSContext *cx, JSCodeGenerator *cg)
7389 {
7390     JSArenaPool *pool;
7391     size_t size;
7392
7393     /* Grow by doubling note array size; update noteMask on success. */
7394     pool = cg->notePool;
7395     size = SRCNOTE_SIZE(CG_NOTE_MASK(cg) + 1);
7396     JS_ARENA_GROW_CAST(CG_NOTES(cg), jssrcnote *, pool, size, size);
7397     if (!CG_NOTES(cg)) {
7398         js_ReportOutOfScriptQuota(cx);
7399         return JS_FALSE;
7400     }
7401     CG_NOTE_MASK(cg) = (CG_NOTE_MASK(cg) << 1) | 1;
7402     return JS_TRUE;
7403 }
7404
7405 jssrcnote *
7406 js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn,
7407                      ptrdiff_t delta)
7408 {
7409     ptrdiff_t base, limit, newdelta, diff;
7410     intN index;
7411
7412     /*
7413      * Called only from OptimizeSpanDeps and js_FinishTakingSrcNotes to add to
7414      * main script note deltas, and only by a small positive amount.
7415      */
7416     JS_ASSERT(cg->current == &cg->main);
7417     JS_ASSERT((unsigned) delta < (unsigned) SN_XDELTA_LIMIT);
7418
7419     base = SN_DELTA(sn);
7420     limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
7421     newdelta = base + delta;
7422     if (newdelta < limit) {
7423         SN_SET_DELTA(sn, newdelta);
7424     } else {
7425         index = sn - cg->main.notes;
7426         if ((cg->main.noteCount & cg->main.noteMask) == 0) {
7427             if (!GrowSrcNotes(cx, cg))
7428                 return NULL;
7429             sn = cg->main.notes + index;
7430         }
7431         diff = cg->main.noteCount - index;
7432         cg->main.noteCount++;
7433         memmove(sn + 1, sn, SRCNOTE_SIZE(diff));
7434         SN_MAKE_XDELTA(sn, delta);
7435         sn++;
7436     }
7437     return sn;
7438 }
7439
7440 JS_FRIEND_API(uintN)
7441 js_SrcNoteLength(jssrcnote *sn)
7442 {
7443     uintN arity;
7444     jssrcnote *base;
7445
7446     arity = (intN)js_SrcNoteSpec[SN_TYPE(sn)].arity;
7447     for (base = sn++; arity; sn++, arity--) {
7448         if (*sn & SN_3BYTE_OFFSET_FLAG)
7449             sn += 2;
7450     }
7451     return sn - base;
7452 }
7453
7454 JS_FRIEND_API(ptrdiff_t)
7455 js_GetSrcNoteOffset(jssrcnote *sn, uintN which)
7456 {
7457     /* Find the offset numbered which (i.e., skip exactly which offsets). */
7458     JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
7459     JS_ASSERT((intN) which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
7460     for (sn++; which; sn++, which--) {
7461         if (*sn & SN_3BYTE_OFFSET_FLAG)
7462             sn += 2;
7463     }
7464     if (*sn & SN_3BYTE_OFFSET_FLAG) {
7465         return (ptrdiff_t)(((uint32)(sn[0] & SN_3BYTE_OFFSET_MASK) << 16)
7466                            | (sn[1] << 8)
7467                            | sn[2]);
7468     }
7469     return (ptrdiff_t)*sn;
7470 }
7471
7472 JSBool
7473 js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
7474                     uintN which, ptrdiff_t offset)
7475 {
7476     jssrcnote *sn;
7477     ptrdiff_t diff;
7478
7479     if ((jsuword)offset >= (jsuword)((ptrdiff_t)SN_3BYTE_OFFSET_FLAG << 16)) {
7480         ReportStatementTooLarge(cx, cg);
7481         return JS_FALSE;
7482     }
7483
7484     /* Find the offset numbered which (i.e., skip exactly which offsets). */
7485     sn = &CG_NOTES(cg)[index];
7486     JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
7487     JS_ASSERT((intN) which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
7488     for (sn++; which; sn++, which--) {
7489         if (*sn & SN_3BYTE_OFFSET_FLAG)
7490             sn += 2;
7491     }
7492
7493     /* See if the new offset requires three bytes. */
7494     if (offset > (ptrdiff_t)SN_3BYTE_OFFSET_MASK) {
7495         /* Maybe this offset was already set to a three-byte value. */
7496         if (!(*sn & SN_3BYTE_OFFSET_FLAG)) {
7497             /* Losing, need to insert another two bytes for this offset. */
7498             index = sn - CG_NOTES(cg);
7499
7500             /*
7501              * Simultaneously test to see if the source note array must grow to
7502              * accommodate either the first or second byte of additional storage
7503              * required by this 3-byte offset.
7504              */
7505             if (((CG_NOTE_COUNT(cg) + 1) & CG_NOTE_MASK(cg)) <= 1) {
7506                 if (!GrowSrcNotes(cx, cg))
7507                     return JS_FALSE;
7508                 sn = CG_NOTES(cg) + index;
7509             }
7510             CG_NOTE_COUNT(cg) += 2;
7511
7512             diff = CG_NOTE_COUNT(cg) - (index + 3);
7513             JS_ASSERT(diff >= 0);
7514             if (diff > 0)
7515                 memmove(sn + 3, sn + 1, SRCNOTE_SIZE(diff));
7516         }
7517         *sn++ = (jssrcnote)(SN_3BYTE_OFFSET_FLAG | (offset >> 16));
7518         *sn++ = (jssrcnote)(offset >> 8);
7519     }
7520     *sn = (jssrcnote)offset;
7521     return JS_TRUE;
7522 }
7523
7524 #ifdef DEBUG_notme
7525 #define DEBUG_srcnotesize
7526 #endif
7527
7528 #ifdef DEBUG_srcnotesize
7529 #define NBINS 10
7530 static uint32 hist[NBINS];
7531
7532 void DumpSrcNoteSizeHist()
7533 {
7534     static FILE *fp;
7535     int i, n;
7536
7537     if (!fp) {
7538         fp = fopen("/tmp/srcnotes.hist", "w");
7539         if (!fp)
7540             return;
7541         setvbuf(fp, NULL, _IONBF, 0);
7542     }
7543     fprintf(fp, "SrcNote size histogram:\n");
7544     for (i = 0; i < NBINS; i++) {
7545         fprintf(fp, "%4u %4u ", JS_BIT(i), hist[i]);
7546         for (n = (int) JS_HOWMANY(hist[i], 10); n > 0; --n)
7547             fputc('*', fp);
7548         fputc('\n', fp);
7549     }
7550     fputc('\n', fp);
7551 }
7552 #endif
7553
7554 /*
7555  * Fill in the storage at notes with prolog and main srcnotes; the space at
7556  * notes was allocated using the CG_COUNT_FINAL_SRCNOTES macro from jsemit.h.
7557  * SO DON'T CHANGE THIS FUNCTION WITHOUT AT LEAST CHECKING WHETHER jsemit.h's
7558  * CG_COUNT_FINAL_SRCNOTES MACRO NEEDS CORRESPONDING CHANGES!
7559  */
7560 JSBool
7561 js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes)
7562 {
7563     uintN prologCount, mainCount, totalCount;
7564     ptrdiff_t offset, delta;
7565     jssrcnote *sn;
7566
7567     JS_ASSERT(cg->current == &cg->main);
7568
7569     prologCount = cg->prolog.noteCount;
7570     if (prologCount && cg->prolog.currentLine != cg->firstLine) {
7571         CG_SWITCH_TO_PROLOG(cg);
7572         if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)cg->firstLine) < 0)
7573             return JS_FALSE;
7574         prologCount = cg->prolog.noteCount;
7575         CG_SWITCH_TO_MAIN(cg);
7576     } else {
7577         /*
7578          * Either no prolog srcnotes, or no line number change over prolog.
7579          * We don't need a SRC_SETLINE, but we may need to adjust the offset
7580          * of the first main note, by adding to its delta and possibly even
7581          * prepending SRC_XDELTA notes to it to account for prolog bytecodes
7582          * that came at and after the last annotated bytecode.
7583          */
7584         offset = CG_PROLOG_OFFSET(cg) - cg->prolog.lastNoteOffset;
7585         JS_ASSERT(offset >= 0);
7586         if (offset > 0 && cg->main.noteCount != 0) {
7587             /* NB: Use as much of the first main note's delta as we can. */
7588             sn = cg->main.notes;
7589             delta = SN_IS_XDELTA(sn)
7590                     ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK)
7591                     : SN_DELTA_MASK - (*sn & SN_DELTA_MASK);
7592             if (offset < delta)
7593                 delta = offset;
7594             for (;;) {
7595                 if (!js_AddToSrcNoteDelta(cx, cg, sn, delta))
7596                     return JS_FALSE;
7597                 offset -= delta;
7598                 if (offset == 0)
7599                     break;
7600                 delta = JS_MIN(offset, SN_XDELTA_MASK);
7601                 sn = cg->main.notes;
7602             }
7603         }
7604     }
7605
7606     mainCount = cg->main.noteCount;
7607     totalCount = prologCount + mainCount;
7608     if (prologCount)
7609         memcpy(notes, cg->prolog.notes, SRCNOTE_SIZE(prologCount));
7610     memcpy(notes + prologCount, cg->main.notes, SRCNOTE_SIZE(mainCount));
7611     SN_MAKE_TERMINATOR(&notes[totalCount]);
7612
7613 #ifdef DEBUG_notme
7614   { int bin = JS_CeilingLog2(totalCount);
7615     if (bin >= NBINS)
7616         bin = NBINS - 1;
7617     ++hist[bin];
7618   }
7619 #endif
7620     return JS_TRUE;
7621 }
7622
7623 static JSBool
7624 NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind,
7625            uintN stackDepth, size_t start, size_t end)
7626 {
7627     JSTryNode *tryNode;
7628
7629     JS_ASSERT((uintN)(uint16)stackDepth == stackDepth);
7630     JS_ASSERT(start <= end);
7631     JS_ASSERT((size_t)(uint32)start == start);
7632     JS_ASSERT((size_t)(uint32)end == end);
7633
7634     JS_ARENA_ALLOCATE_TYPE(tryNode, JSTryNode, &cx->tempPool);
7635     if (!tryNode) {
7636         js_ReportOutOfScriptQuota(cx);
7637         return JS_FALSE;
7638     }
7639
7640     tryNode->note.kind = kind;
7641     tryNode->note.stackDepth = (uint16)stackDepth;
7642     tryNode->note.start = (uint32)start;
7643     tryNode->note.length = (uint32)(end - start);
7644     tryNode->prev = cg->lastTryNode;
7645     cg->lastTryNode = tryNode;
7646     cg->ntrynotes++;
7647     return JS_TRUE;
7648 }
7649
7650 void
7651 js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array)
7652 {
7653     JSTryNode *tryNode;
7654     JSTryNote *tn;
7655
7656     JS_ASSERT(array->length > 0 && array->length == cg->ntrynotes);
7657     tn = array->vector + array->length;
7658     tryNode = cg->lastTryNode;
7659     do {
7660         *--tn = tryNode->note;
7661     } while ((tryNode = tryNode->prev) != NULL);
7662     JS_ASSERT(tn == array->vector);
7663 }
7664
7665 /*
7666  * Find the index of the given object for code generator.
7667  *
7668  * Since the emitter refers to each parsed object only once, for the index we
7669  * use the number of already indexes objects. We also add the object to a list
7670  * to convert the list to a fixed-size array when we complete code generation,
7671  * see JSCGObjectList::finish below.
7672  *
7673  * Most of the objects go to JSCodeGenerator.objectList but for regexp we use a
7674  * separated JSCodeGenerator.regexpList. In this way the emitted index can be
7675  * directly used to store and fetch a reference to a cloned RegExp object that
7676  * shares the same JSRegExp private data created for the object literal in
7677  * objbox. We need a cloned object to hold lastIndex and other direct properties
7678  * that should not be shared among threads sharing a precompiled function or
7679  * script.
7680  *
7681  * If the code being compiled is function code, allocate a reserved slot in
7682  * the cloned function object that shares its precompiled script with other
7683  * cloned function objects and with the compiler-created clone-parent. There
7684  * are nregexps = script->regexps()->length such reserved slots in each
7685  * function object cloned from fun->object. NB: during compilation, a funobj
7686  * slots element must never be allocated, because JSObject::allocSlot could
7687  * hand out one of the slots that should be given to a regexp clone.
7688  *
7689  * If the code being compiled is global code, the cloned regexp are stored in
7690  * fp->vars slot and to protect regexp slots from GC we set fp->nvars to
7691  * nregexps.
7692  *
7693  * The slots initially contain undefined or null. We populate them lazily when
7694  * JSOP_REGEXP is executed for the first time.
7695  *
7696  * Why clone regexp objects?  ECMA specifies that when a regular expression
7697  * literal is scanned, a RegExp object is created.  In the spec, compilation
7698  * and execution happen indivisibly, but in this implementation and many of
7699  * its embeddings, code is precompiled early and re-executed in multiple
7700  * threads, or using multiple global objects, or both, for efficiency.
7701  *
7702  * In such cases, naively following ECMA leads to wrongful sharing of RegExp
7703  * objects, which makes for collisions on the lastIndex property (especially
7704  * for global regexps) and on any ad-hoc properties.  Also, __proto__ refers to
7705  * the pre-compilation prototype, a pigeon-hole problem for instanceof tests.
7706  */
7707 uintN
7708 JSCGObjectList::index(JSObjectBox *objbox)
7709 {
7710     JS_ASSERT(!objbox->emitLink);
7711     objbox->emitLink = lastbox;
7712     lastbox = objbox;
7713     objbox->index = length++;
7714     return objbox->index;
7715 }
7716
7717 void
7718 JSCGObjectList::finish(JSObjectArray *array)
7719 {
7720     JSObject **cursor;
7721     JSObjectBox *objbox;
7722
7723     JS_ASSERT(length <= INDEX_LIMIT);
7724     JS_ASSERT(length == array->length);
7725
7726     cursor = array->vector + array->length;
7727     objbox = lastbox;
7728     do {
7729         --cursor;
7730         JS_ASSERT(!*cursor);
7731         *cursor = objbox->object;
7732     } while ((objbox = objbox->emitLink) != NULL);
7733     JS_ASSERT(cursor == array->vector);
7734 }
7735
7736 void
7737 JSGCConstList::finish(JSConstArray *array)
7738 {
7739     JS_ASSERT(array->length == list.length());
7740     Value *src = list.begin(), *srcend = list.end();
7741     Value *dst = array->vector;
7742     for (; src != srcend; ++src, ++dst)
7743         *dst = *src;
7744 }