PageRenderTime 151ms CodeModel.GetById 81ms app.highlight 29ms RepoModel.GetById 31ms app.codeStats 0ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsemit.h

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ Header | 777 lines | 402 code | 98 blank | 277 comment | 17 complexity | 38bc47109b221ec5f26bd211a82181ea MD5 | raw file
  1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2 * vim: set ts=8 sw=4 et tw=79:
  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#ifndef jsemit_h___
 42#define jsemit_h___
 43/*
 44 * JS bytecode generation.
 45 */
 46
 47#include "jsstddef.h"
 48#include "jstypes.h"
 49#include "jsatom.h"
 50#include "jsopcode.h"
 51#include "jsscript.h"
 52#include "jsprvtd.h"
 53#include "jspubtd.h"
 54
 55JS_BEGIN_EXTERN_C
 56
 57/*
 58 * NB: If you add enumerators for scope statements, add them between STMT_WITH
 59 * and STMT_CATCH, or you will break the STMT_TYPE_IS_SCOPE macro. If you add
 60 * non-looping statement enumerators, add them before STMT_DO_LOOP or you will
 61 * break the STMT_TYPE_IS_LOOP macro.
 62 *
 63 * Also remember to keep the statementName array in jsemit.c in sync.
 64 */
 65typedef enum JSStmtType {
 66    STMT_LABEL,                 /* labeled statement:  L: s */
 67    STMT_IF,                    /* if (then) statement */
 68    STMT_ELSE,                  /* else clause of if statement */
 69    STMT_SEQ,                   /* synthetic sequence of statements */
 70    STMT_BLOCK,                 /* compound statement: { s1[;... sN] } */
 71    STMT_SWITCH,                /* switch statement */
 72    STMT_WITH,                  /* with statement */
 73    STMT_CATCH,                 /* catch block */
 74    STMT_TRY,                   /* try block */
 75    STMT_FINALLY,               /* finally block */
 76    STMT_SUBROUTINE,            /* gosub-target subroutine body */
 77    STMT_DO_LOOP,               /* do/while loop statement */
 78    STMT_FOR_LOOP,              /* for loop statement */
 79    STMT_FOR_IN_LOOP,           /* for/in loop statement */
 80    STMT_WHILE_LOOP,            /* while loop statement */
 81    STMT_LIMIT
 82} JSStmtType;
 83
 84#define STMT_TYPE_IN_RANGE(t,b,e) ((uint)((t) - (b)) <= (uintN)((e) - (b)))
 85
 86/*
 87 * A comment on the encoding of the JSStmtType enum and type-testing macros:
 88 *
 89 * STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may
 90 * become, a lexical scope.  It therefore includes block and switch (the two
 91 * low-numbered "maybe" scope types) and excludes with (with has dynamic scope
 92 * pending the "reformed with" in ES4/JS2).  It includes all try-catch-finally
 93 * types, which are high-numbered maybe-scope types.
 94 *
 95 * STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly
 96 * links to other scoping statement info records.  It excludes the two early
 97 * "maybe" types, block and switch, as well as the try and both finally types,
 98 * since try and the other trailing maybe-scope types don't need block scope
 99 * unless they contain let declarations.
100 *
101 * We treat WITH as a static scope because it prevents lexical binding from
102 * continuing further up the static scope chain. With the lost "reformed with"
103 * proposal for ES4, we would be able to model it statically, too.
104 */
105#define STMT_TYPE_MAYBE_SCOPE(type)                                           \
106    (type != STMT_WITH &&                                                     \
107     STMT_TYPE_IN_RANGE(type, STMT_BLOCK, STMT_SUBROUTINE))
108
109#define STMT_TYPE_LINKS_SCOPE(type)                                           \
110    STMT_TYPE_IN_RANGE(type, STMT_WITH, STMT_CATCH)
111
112#define STMT_TYPE_IS_TRYING(type)                                             \
113    STMT_TYPE_IN_RANGE(type, STMT_TRY, STMT_SUBROUTINE)
114
115#define STMT_TYPE_IS_LOOP(type) ((type) >= STMT_DO_LOOP)
116
117#define STMT_MAYBE_SCOPE(stmt)  STMT_TYPE_MAYBE_SCOPE((stmt)->type)
118#define STMT_LINKS_SCOPE(stmt)  (STMT_TYPE_LINKS_SCOPE((stmt)->type) ||       \
119                                 ((stmt)->flags & SIF_SCOPE))
120#define STMT_IS_TRYING(stmt)    STMT_TYPE_IS_TRYING((stmt)->type)
121#define STMT_IS_LOOP(stmt)      STMT_TYPE_IS_LOOP((stmt)->type)
122
123typedef struct JSStmtInfo JSStmtInfo;
124
125struct JSStmtInfo {
126    uint16          type;           /* statement type */
127    uint16          flags;          /* flags, see below */
128    ptrdiff_t       update;         /* loop update offset (top if none) */
129    ptrdiff_t       breaks;         /* offset of last break in loop */
130    ptrdiff_t       continues;      /* offset of last continue in loop */
131    union {
132        JSAtom      *label;         /* name of LABEL */
133        JSObject    *blockObj;      /* block scope object */
134    } u;
135    JSStmtInfo      *down;          /* info for enclosing statement */
136    JSStmtInfo      *downScope;     /* next enclosing lexical scope */
137};
138
139#define SIF_SCOPE        0x0001     /* statement has its own lexical scope */
140#define SIF_BODY_BLOCK   0x0002     /* STMT_BLOCK type is a function body */
141#define SIF_FOR_BLOCK    0x0004     /* for (let ...) induced block scope */
142
143/*
144 * To reuse space in JSStmtInfo, rename breaks and continues for use during
145 * try/catch/finally code generation and backpatching. To match most common
146 * use cases, the macro argument is a struct, not a struct pointer. Only a
147 * loop, switch, or label statement info record can have breaks and continues,
148 * and only a for loop has an update backpatch chain, so it's safe to overlay
149 * these for the "trying" JSStmtTypes.
150 */
151#define CATCHNOTE(stmt)  ((stmt).update)
152#define GOSUBS(stmt)     ((stmt).breaks)
153#define GUARDJUMP(stmt)  ((stmt).continues)
154
155#define AT_TOP_LEVEL(tc)                                                      \
156    (!(tc)->topStmt || ((tc)->topStmt->flags & SIF_BODY_BLOCK))
157
158#define SET_STATEMENT_TOP(stmt, top)                                          \
159    ((stmt)->update = (top), (stmt)->breaks = (stmt)->continues = (-1))
160
161struct JSTreeContext {              /* tree context for semantic checks */
162    uint16          flags;          /* statement state flags, see below */
163    uint16          ngvars;         /* max. no. of global variables/regexps */
164    JSStmtInfo      *topStmt;       /* top of statement info stack */
165    JSStmtInfo      *topScopeStmt;  /* top lexical scope statement */
166    JSObject        *blockChain;    /* compile time block scope chain (NB: one
167                                       deeper than the topScopeStmt/downScope
168                                       chain when in head of let block/expr) */
169    JSParseNode     *blockNode;     /* parse node for a lexical scope.
170                                       XXX combine with blockChain? */
171    JSAtomList      decls;          /* function, const, and var declarations */
172    JSParseContext  *parseContext;
173
174    union {
175
176        JSFunction  *fun;           /* function to store argument and variable
177                                       names when flags & TCF_IN_FUNCTION */
178        JSObject    *scopeChain;    /* scope chain object for the script */
179    } u;
180
181#ifdef JS_SCOPE_DEPTH_METER
182    uint16          scopeDepth;     /* current lexical scope chain depth */
183    uint16          maxScopeDepth;  /* maximum lexical scope chain depth */
184#endif
185};
186
187#define TCF_IN_FUNCTION        0x01 /* parsing inside function body */
188#define TCF_RETURN_EXPR        0x02 /* function has 'return expr;' */
189#define TCF_RETURN_VOID        0x04 /* function has 'return;' */
190#define TCF_IN_FOR_INIT        0x08 /* parsing init expr of for; exclude 'in' */
191#define TCF_FUN_CLOSURE_VS_VAR 0x10 /* function and var with same name */
192#define TCF_FUN_USES_NONLOCALS 0x20 /* function refers to non-local names */
193#define TCF_FUN_HEAVYWEIGHT    0x40 /* function needs Call object per call */
194#define TCF_FUN_IS_GENERATOR   0x80 /* parsed yield statement in function */
195#define TCF_HAS_DEFXMLNS      0x100 /* default xml namespace = ...; parsed */
196#define TCF_HAS_FUNCTION_STMT 0x200 /* block contains a function statement */
197#define TCF_GENEXP_LAMBDA     0x400 /* flag lambda from generator expression */
198#define TCF_COMPILE_N_GO      0x800 /* compiler-and-go mode of script, can
199                                       optimize name references based on scope
200                                       chain */
201#define TCF_NO_SCRIPT_RVAL   0x1000 /* API caller does not want result value
202                                       from global script */
203/*
204 * Flags to propagate out of the blocks.
205 */
206#define TCF_RETURN_FLAGS        (TCF_RETURN_EXPR | TCF_RETURN_VOID)
207
208/*
209 * Flags to propagate from FunctionBody.
210 */
211#define TCF_FUN_FLAGS           (TCF_FUN_IS_GENERATOR   |                     \
212                                 TCF_FUN_HEAVYWEIGHT    |                     \
213                                 TCF_FUN_USES_NONLOCALS |                     \
214                                 TCF_FUN_CLOSURE_VS_VAR)
215
216/*
217 * Flags field, not stored in JSTreeContext.flags, for passing staticDepth
218 * into js_CompileScript.
219 */
220#define TCF_STATIC_DEPTH_MASK   0xffff0000
221#define TCF_GET_STATIC_DEPTH(f) ((uint32)(f) >> 16)
222#define TCF_PUT_STATIC_DEPTH(d) ((uint16)(d) << 16)
223
224#ifdef JS_SCOPE_DEPTH_METER
225# define JS_SCOPE_DEPTH_METERING(code) ((void) (code))
226#else
227# define JS_SCOPE_DEPTH_METERING(code) ((void) 0)
228#endif
229
230#define TREE_CONTEXT_INIT(tc, pc)                                             \
231    ((tc)->flags = (tc)->ngvars = 0,                                          \
232     (tc)->topStmt = (tc)->topScopeStmt = NULL,                               \
233     (tc)->blockChain = NULL,                                                 \
234     ATOM_LIST_INIT(&(tc)->decls),                                            \
235     (tc)->blockNode = NULL,                                                  \
236     (tc)->parseContext = (pc),                                               \
237     (tc)->u.scopeChain = NULL,                                               \
238     JS_SCOPE_DEPTH_METERING((tc)->scopeDepth = (tc)->maxScopeDepth = 0))
239
240/*
241 * For functions TREE_CONTEXT_FINISH is called the second time to finish the
242 * extra tc created during code generation. We skip stats update in such
243 * cases.
244 */
245#define TREE_CONTEXT_FINISH(cx, tc)                                           \
246    JS_SCOPE_DEPTH_METERING(                                                  \
247        (tc)->maxScopeDepth == (uintN) -1 ||                                  \
248        JS_BASIC_STATS_ACCUM(&(cx)->runtime->lexicalScopeDepthStats,          \
249                             (tc)->maxScopeDepth))
250
251/*
252 * Span-dependent instructions are jumps whose span (from the jump bytecode to
253 * the jump target) may require 2 or 4 bytes of immediate operand.
254 */
255typedef struct JSSpanDep    JSSpanDep;
256typedef struct JSJumpTarget JSJumpTarget;
257
258struct JSSpanDep {
259    ptrdiff_t       top;        /* offset of first bytecode in an opcode */
260    ptrdiff_t       offset;     /* offset - 1 within opcode of jump operand */
261    ptrdiff_t       before;     /* original offset - 1 of jump operand */
262    JSJumpTarget    *target;    /* tagged target pointer or backpatch delta */
263};
264
265/*
266 * Jump targets are stored in an AVL tree, for O(log(n)) lookup with targets
267 * sorted by offset from left to right, so that targets after a span-dependent
268 * instruction whose jump offset operand must be extended can be found quickly
269 * and adjusted upward (toward higher offsets).
270 */
271struct JSJumpTarget {
272    ptrdiff_t       offset;     /* offset of span-dependent jump target */
273    int             balance;    /* AVL tree balance number */
274    JSJumpTarget    *kids[2];   /* left and right AVL tree child pointers */
275};
276
277#define JT_LEFT                 0
278#define JT_RIGHT                1
279#define JT_OTHER_DIR(dir)       (1 - (dir))
280#define JT_IMBALANCE(dir)       (((dir) << 1) - 1)
281#define JT_DIR(imbalance)       (((imbalance) + 1) >> 1)
282
283/*
284 * Backpatch deltas are encoded in JSSpanDep.target if JT_TAG_BIT is clear,
285 * so we can maintain backpatch chains when using span dependency records to
286 * hold jump offsets that overflow 16 bits.
287 */
288#define JT_TAG_BIT              ((jsword) 1)
289#define JT_UNTAG_SHIFT          1
290#define JT_SET_TAG(jt)          ((JSJumpTarget *)((jsword)(jt) | JT_TAG_BIT))
291#define JT_CLR_TAG(jt)          ((JSJumpTarget *)((jsword)(jt) & ~JT_TAG_BIT))
292#define JT_HAS_TAG(jt)          ((jsword)(jt) & JT_TAG_BIT)
293
294#define BITS_PER_PTRDIFF        (sizeof(ptrdiff_t) * JS_BITS_PER_BYTE)
295#define BITS_PER_BPDELTA        (BITS_PER_PTRDIFF - 1 - JT_UNTAG_SHIFT)
296#define BPDELTA_MAX             (((ptrdiff_t)1 << BITS_PER_BPDELTA) - 1)
297#define BPDELTA_TO_JT(bp)       ((JSJumpTarget *)((bp) << JT_UNTAG_SHIFT))
298#define JT_TO_BPDELTA(jt)       ((ptrdiff_t)((jsword)(jt) >> JT_UNTAG_SHIFT))
299
300#define SD_SET_TARGET(sd,jt)    ((sd)->target = JT_SET_TAG(jt))
301#define SD_GET_TARGET(sd)       (JS_ASSERT(JT_HAS_TAG((sd)->target)),         \
302                                 JT_CLR_TAG((sd)->target))
303#define SD_SET_BPDELTA(sd,bp)   ((sd)->target = BPDELTA_TO_JT(bp))
304#define SD_GET_BPDELTA(sd)      (JS_ASSERT(!JT_HAS_TAG((sd)->target)),        \
305                                 JT_TO_BPDELTA((sd)->target))
306
307/* Avoid asserting twice by expanding SD_GET_TARGET in the "then" clause. */
308#define SD_SPAN(sd,pivot)       (SD_GET_TARGET(sd)                            \
309                                 ? JT_CLR_TAG((sd)->target)->offset - (pivot) \
310                                 : 0)
311
312typedef struct JSTryNode JSTryNode;
313
314struct JSTryNode {
315    JSTryNote       note;
316    JSTryNode       *prev;
317};
318
319typedef struct JSEmittedObjectList {
320    uint32              length;     /* number of emitted so far objects */
321    JSParsedObjectBox   *lastPob;   /* last emitted object */
322} JSEmittedObjectList;
323
324extern void
325FinishParsedObjects(JSEmittedObjectList *emittedList, JSObjectArray *objectMap);
326
327struct JSCodeGenerator {
328    JSTreeContext   treeContext;    /* base state: statement info stack, etc. */
329
330    JSArenaPool     *codePool;      /* pointer to thread code arena pool */
331    JSArenaPool     *notePool;      /* pointer to thread srcnote arena pool */
332    void            *codeMark;      /* low watermark in cg->codePool */
333    void            *noteMark;      /* low watermark in cg->notePool */
334
335    struct {
336        jsbytecode  *base;          /* base of JS bytecode vector */
337        jsbytecode  *limit;         /* one byte beyond end of bytecode */
338        jsbytecode  *next;          /* pointer to next free bytecode */
339        jssrcnote   *notes;         /* source notes, see below */
340        uintN       noteCount;      /* number of source notes so far */
341        uintN       noteMask;       /* growth increment for notes */
342        ptrdiff_t   lastNoteOffset; /* code offset for last source note */
343        uintN       currentLine;    /* line number for tree-based srcnote gen */
344    } prolog, main, *current;
345
346    JSAtomList      atomList;       /* literals indexed for mapping */
347    uintN           firstLine;      /* first line, for js_NewScriptFromCG */
348
349    intN            stackDepth;     /* current stack depth in script frame */
350    uintN           maxStackDepth;  /* maximum stack depth so far */
351
352    uintN           ntrynotes;      /* number of allocated so far try notes */
353    JSTryNode       *lastTryNode;   /* the last allocated try node */
354
355    JSSpanDep       *spanDeps;      /* span dependent instruction records */
356    JSJumpTarget    *jumpTargets;   /* AVL tree of jump target offsets */
357    JSJumpTarget    *jtFreeList;    /* JT_LEFT-linked list of free structs */
358    uintN           numSpanDeps;    /* number of span dependencies */
359    uintN           numJumpTargets; /* number of jump targets */
360    ptrdiff_t       spanDepTodo;    /* offset from main.base of potentially
361                                       unoptimized spandeps */
362
363    uintN           arrayCompDepth; /* stack depth of array in comprehension */
364
365    uintN           emitLevel;      /* js_EmitTree recursion level */
366    JSAtomList      constList;      /* compile time constants */
367
368    JSEmittedObjectList objectList; /* list of emitted so far objects */
369    JSEmittedObjectList regexpList; /* list of emitted so far regexp
370                                       that will be cloned during execution */
371
372    uintN           staticDepth;    /* static frame chain depth */
373    JSAtomList      upvarList;      /* map of atoms to upvar indexes */
374    JSUpvarArray    upvarMap;       /* indexed upvar pairs (JS_realloc'ed) */
375    JSCodeGenerator *parent;        /* enclosing function or global context */
376};
377
378#define CG_TS(cg)               TS((cg)->treeContext.parseContext)
379
380#define CG_BASE(cg)             ((cg)->current->base)
381#define CG_LIMIT(cg)            ((cg)->current->limit)
382#define CG_NEXT(cg)             ((cg)->current->next)
383#define CG_CODE(cg,offset)      (CG_BASE(cg) + (offset))
384#define CG_OFFSET(cg)           PTRDIFF(CG_NEXT(cg), CG_BASE(cg), jsbytecode)
385
386#define CG_NOTES(cg)            ((cg)->current->notes)
387#define CG_NOTE_COUNT(cg)       ((cg)->current->noteCount)
388#define CG_NOTE_MASK(cg)        ((cg)->current->noteMask)
389#define CG_LAST_NOTE_OFFSET(cg) ((cg)->current->lastNoteOffset)
390#define CG_CURRENT_LINE(cg)     ((cg)->current->currentLine)
391
392#define CG_PROLOG_BASE(cg)      ((cg)->prolog.base)
393#define CG_PROLOG_LIMIT(cg)     ((cg)->prolog.limit)
394#define CG_PROLOG_NEXT(cg)      ((cg)->prolog.next)
395#define CG_PROLOG_CODE(cg,poff) (CG_PROLOG_BASE(cg) + (poff))
396#define CG_PROLOG_OFFSET(cg)    PTRDIFF(CG_PROLOG_NEXT(cg), CG_PROLOG_BASE(cg),\
397                                        jsbytecode)
398
399#define CG_SWITCH_TO_MAIN(cg)   ((cg)->current = &(cg)->main)
400#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog)
401
402/*
403 * Initialize cg to allocate bytecode space from codePool, source note space
404 * from notePool, and all other arena-allocated temporaries from cx->tempPool.
405 */
406extern JS_FRIEND_API(void)
407js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc,
408                     JSArenaPool *codePool, JSArenaPool *notePool,
409                     uintN lineno);
410
411/*
412 * Release cg->codePool, cg->notePool, and cx->tempPool to marks set by
413 * js_InitCodeGenerator. Note that cgs are magic: they own the arena pool
414 * "tops-of-stack" space above their codeMark, noteMark, and tempMark points.
415 * This means you cannot alloc from tempPool and save the pointer beyond the
416 * next JS_FinishCodeGenerator.
417 */
418extern JS_FRIEND_API(void)
419js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg);
420
421/*
422 * Emit one bytecode.
423 */
424extern ptrdiff_t
425js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op);
426
427/*
428 * Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1).
429 */
430extern ptrdiff_t
431js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1);
432
433/*
434 * Emit three bytecodes, an opcode with two bytes of immediate operands.
435 */
436extern ptrdiff_t
437js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1,
438         jsbytecode op2);
439
440/*
441 * Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
442 */
443extern ptrdiff_t
444js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra);
445
446/*
447 * Unsafe macro to call js_SetJumpOffset and return false if it does.
448 */
449#define CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,cg,pc,off,BAD_EXIT)               \
450    JS_BEGIN_MACRO                                                            \
451        if (!js_SetJumpOffset(cx, cg, pc, off)) {                             \
452            BAD_EXIT;                                                         \
453        }                                                                     \
454    JS_END_MACRO
455
456#define CHECK_AND_SET_JUMP_OFFSET(cx,cg,pc,off)                               \
457    CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx,cg,pc,off,return JS_FALSE)
458
459#define CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx,cg,off,BAD_EXIT)               \
460    CHECK_AND_SET_JUMP_OFFSET_CUSTOM(cx, cg, CG_CODE(cg,off),                 \
461                                     CG_OFFSET(cg) - (off), BAD_EXIT)
462
463#define CHECK_AND_SET_JUMP_OFFSET_AT(cx,cg,off)                               \
464    CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, off, return JS_FALSE)
465
466extern JSBool
467js_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc,
468                 ptrdiff_t off);
469
470/* Test whether we're in a statement of given type. */
471extern JSBool
472js_InStatement(JSTreeContext *tc, JSStmtType type);
473
474/* Test whether we're in a with statement. */
475#define js_InWithStatement(tc)      js_InStatement(tc, STMT_WITH)
476
477/*
478 * Push the C-stack-allocated struct at stmt onto the stmtInfo stack.
479 */
480extern void
481js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
482                 ptrdiff_t top);
483
484/*
485 * Push a block scope statement and link blockObj into tc->blockChain. To pop
486 * this statement info record, use js_PopStatement as usual, or if appropriate
487 * (if generating code), js_PopStatementCG.
488 */
489extern void
490js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj,
491                  ptrdiff_t top);
492
493/*
494 * Pop tc->topStmt. If the top JSStmtInfo struct is not stack-allocated, it
495 * is up to the caller to free it.
496 */
497extern void
498js_PopStatement(JSTreeContext *tc);
499
500/*
501 * Like js_PopStatement(&cg->treeContext), also patch breaks and continues
502 * unless the top statement info record represents a try-catch-finally suite.
503 * May fail if a jump offset overflows.
504 */
505extern JSBool
506js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg);
507
508/*
509 * Define and lookup a primitive jsval associated with the const named by atom.
510 * js_DefineCompileTimeConstant analyzes the constant-folded initializer at pn
511 * and saves the const's value in cg->constList, if it can be used at compile
512 * time. It returns true unless an error occurred.
513 *
514 * If the initializer's value could not be saved, js_DefineCompileTimeConstant
515 * calls will return the undefined value. js_DefineCompileTimeConstant tries
516 * to find a const value memorized for atom, returning true with *vp set to a
517 * value other than undefined if the constant was found, true with *vp set to
518 * JSVAL_VOID if not found, and false on error.
519 */
520extern JSBool
521js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
522                             JSParseNode *pn);
523
524/*
525 * Find a lexically scoped variable (one declared by let, catch, or an array
526 * comprehension) named by atom, looking in tc's compile-time scopes.
527 *
528 * If a WITH statement is reached along the scope stack, return its statement
529 * info record, so callers can tell that atom is ambiguous. If slotp is not
530 * null, then if atom is found, set *slotp to its stack slot, otherwise to -1.
531 * This means that if slotp is not null, all the block objects on the lexical
532 * scope chain must have had their depth slots computed by the code generator,
533 * so the caller must be under js_EmitTree.
534 *
535 * In any event, directly return the statement info record in which atom was
536 * found. Otherwise return null.
537 */
538extern JSStmtInfo *
539js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp);
540
541/*
542 * Emit code into cg for the tree rooted at pn.
543 */
544extern JSBool
545js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn);
546
547/*
548 * Emit function code using cg for the tree rooted at body.
549 */
550extern JSBool
551js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body);
552
553/*
554 * Source notes generated along with bytecode for decompiling and debugging.
555 * A source note is a uint8 with 5 bits of type and 3 of offset from the pc of
556 * the previous note. If 3 bits of offset aren't enough, extended delta notes
557 * (SRC_XDELTA) consisting of 2 set high order bits followed by 6 offset bits
558 * are emitted before the next note. Some notes have operand offsets encoded
559 * immediately after them, in note bytes or byte-triples.
560 *
561 *                 Source Note               Extended Delta
562 *              +7-6-5-4-3+2-1-0+           +7-6-5+4-3-2-1-0+
563 *              |note-type|delta|           |1 1| ext-delta |
564 *              +---------+-----+           +---+-----------+
565 *
566 * At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE,
567 * SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode.
568 *
569 * NB: the js_SrcNoteSpec array in jsemit.c is indexed by this enum, so its
570 * initializers need to match the order here.
571 *
572 * Note on adding new source notes: every pair of bytecodes (A, B) where A and
573 * B have disjoint sets of source notes that could apply to each bytecode may
574 * reuse the same note type value for two notes (snA, snB) that have the same
575 * arity, offsetBias, and isSpanDep initializers in js_SrcNoteSpec. This is
576 * why SRC_IF and SRC_INITPROP have the same value below. For bad historical
577 * reasons, some bytecodes below that could be overlayed have not been, but
578 * before using SRC_EXTENDED, consider compressing the existing note types.
579 *
580 * Don't forget to update JSXDR_BYTECODE_VERSION in jsxdrapi.h for all such
581 * incompatible source note or other bytecode changes.
582 */
583typedef enum JSSrcNoteType {
584    SRC_NULL        = 0,        /* terminates a note vector */
585    SRC_IF          = 1,        /* JSOP_IFEQ bytecode is from an if-then */
586    SRC_BREAK       = 1,        /* JSOP_GOTO is a break */
587    SRC_INITPROP    = 1,        /* disjoint meaning applied to JSOP_INITELEM or
588                                   to an index label in a regular (structuring)
589                                   or a destructuring object initialiser */
590    SRC_GENEXP      = 1,        /* JSOP_ANONFUNOBJ from generator expression */
591    SRC_IF_ELSE     = 2,        /* JSOP_IFEQ bytecode is from an if-then-else */
592    SRC_FOR_IN      = 2,        /* JSOP_GOTO to for-in loop condition from
593                                   before loop (same arity as SRC_IF_ELSE) */
594    SRC_FOR         = 3,        /* JSOP_NOP or JSOP_POP in for(;;) loop head */
595    SRC_WHILE       = 4,        /* JSOP_GOTO to for or while loop condition
596                                   from before loop, else JSOP_NOP at top of
597                                   do-while loop */
598    SRC_CONTINUE    = 5,        /* JSOP_GOTO is a continue, not a break;
599                                   also used on JSOP_ENDINIT if extra comma
600                                   at end of array literal: [1,2,,] */
601    SRC_DECL        = 6,        /* type of a declaration (var, const, let*) */
602    SRC_DESTRUCT    = 6,        /* JSOP_DUP starting a destructuring assignment
603                                   operation, with SRC_DECL_* offset operand */
604    SRC_PCDELTA     = 7,        /* distance forward from comma-operator to
605                                   next POP, or from CONDSWITCH to first CASE
606                                   opcode, etc. -- always a forward delta */
607    SRC_GROUPASSIGN = 7,        /* SRC_DESTRUCT variant for [a, b] = [c, d] */
608    SRC_ASSIGNOP    = 8,        /* += or another assign-op follows */
609    SRC_COND        = 9,        /* JSOP_IFEQ is from conditional ?: operator */
610    SRC_BRACE       = 10,       /* mandatory brace, for scope or to avoid
611                                   dangling else */
612    SRC_HIDDEN      = 11,       /* opcode shouldn't be decompiled */
613    SRC_PCBASE      = 12,       /* distance back from annotated getprop or
614                                   setprop op to left-most obj.prop.subprop
615                                   bytecode -- always a backward delta */
616    SRC_LABEL       = 13,       /* JSOP_NOP for label: with atomid immediate */
617    SRC_LABELBRACE  = 14,       /* JSOP_NOP for label: {...} begin brace */
618    SRC_ENDBRACE    = 15,       /* JSOP_NOP for label: {...} end brace */
619    SRC_BREAK2LABEL = 16,       /* JSOP_GOTO for 'break label' with atomid */
620    SRC_CONT2LABEL  = 17,       /* JSOP_GOTO for 'continue label' with atomid */
621    SRC_SWITCH      = 18,       /* JSOP_*SWITCH with offset to end of switch,
622                                   2nd off to first JSOP_CASE if condswitch */
623    SRC_FUNCDEF     = 19,       /* JSOP_NOP for function f() with atomid */
624    SRC_CATCH       = 20,       /* catch block has guard */
625    SRC_EXTENDED    = 21,       /* extended source note, 32-159, in next byte */
626    SRC_NEWLINE     = 22,       /* bytecode follows a source newline */
627    SRC_SETLINE     = 23,       /* a file-absolute source line number note */
628    SRC_XDELTA      = 24        /* 24-31 are for extended delta notes */
629} JSSrcNoteType;
630
631/*
632 * Constants for the SRC_DECL source note. Note that span-dependent bytecode
633 * selection means that any SRC_DECL offset greater than SRC_DECL_LET may need
634 * to be adjusted, but these "offsets" are too small to span a span-dependent
635 * instruction, so can be used to denote distinct declaration syntaxes to the
636 * decompiler.
637 *
638 * NB: the var_prefix array in jsopcode.c depends on these dense indexes from
639 * SRC_DECL_VAR through SRC_DECL_LET.
640 */
641#define SRC_DECL_VAR            0
642#define SRC_DECL_CONST          1
643#define SRC_DECL_LET            2
644#define SRC_DECL_NONE           3
645
646#define SN_TYPE_BITS            5
647#define SN_DELTA_BITS           3
648#define SN_XDELTA_BITS          6
649#define SN_TYPE_MASK            (JS_BITMASK(SN_TYPE_BITS) << SN_DELTA_BITS)
650#define SN_DELTA_MASK           ((ptrdiff_t)JS_BITMASK(SN_DELTA_BITS))
651#define SN_XDELTA_MASK          ((ptrdiff_t)JS_BITMASK(SN_XDELTA_BITS))
652
653#define SN_MAKE_NOTE(sn,t,d)    (*(sn) = (jssrcnote)                          \
654                                          (((t) << SN_DELTA_BITS)             \
655                                           | ((d) & SN_DELTA_MASK)))
656#define SN_MAKE_XDELTA(sn,d)    (*(sn) = (jssrcnote)                          \
657                                          ((SRC_XDELTA << SN_DELTA_BITS)      \
658                                           | ((d) & SN_XDELTA_MASK)))
659
660#define SN_IS_XDELTA(sn)        ((*(sn) >> SN_DELTA_BITS) >= SRC_XDELTA)
661#define SN_TYPE(sn)             ((JSSrcNoteType)(SN_IS_XDELTA(sn)             \
662                                                 ? SRC_XDELTA                 \
663                                                 : *(sn) >> SN_DELTA_BITS))
664#define SN_SET_TYPE(sn,type)    SN_MAKE_NOTE(sn, type, SN_DELTA(sn))
665#define SN_IS_GETTABLE(sn)      (SN_TYPE(sn) < SRC_NEWLINE)
666
667#define SN_DELTA(sn)            ((ptrdiff_t)(SN_IS_XDELTA(sn)                 \
668                                             ? *(sn) & SN_XDELTA_MASK         \
669                                             : *(sn) & SN_DELTA_MASK))
670#define SN_SET_DELTA(sn,delta)  (SN_IS_XDELTA(sn)                             \
671                                 ? SN_MAKE_XDELTA(sn, delta)                  \
672                                 : SN_MAKE_NOTE(sn, SN_TYPE(sn), delta))
673
674#define SN_DELTA_LIMIT          ((ptrdiff_t)JS_BIT(SN_DELTA_BITS))
675#define SN_XDELTA_LIMIT         ((ptrdiff_t)JS_BIT(SN_XDELTA_BITS))
676
677/*
678 * Offset fields follow certain notes and are frequency-encoded: an offset in
679 * [0,0x7f] consumes one byte, an offset in [0x80,0x7fffff] takes three, and
680 * the high bit of the first byte is set.
681 */
682#define SN_3BYTE_OFFSET_FLAG    0x80
683#define SN_3BYTE_OFFSET_MASK    0x7f
684
685typedef struct JSSrcNoteSpec {
686    const char      *name;      /* name for disassembly/debugging output */
687    int8            arity;      /* number of offset operands */
688    uint8           offsetBias; /* bias of offset(s) from annotated pc */
689    int8            isSpanDep;  /* 1 or -1 if offsets could span extended ops,
690                                   0 otherwise; sign tells span direction */
691} JSSrcNoteSpec;
692
693extern JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[];
694extern JS_FRIEND_API(uintN)          js_SrcNoteLength(jssrcnote *sn);
695
696#define SN_LENGTH(sn)           ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \
697                                 : js_SrcNoteLength(sn))
698#define SN_NEXT(sn)             ((sn) + SN_LENGTH(sn))
699
700/* A source note array is terminated by an all-zero element. */
701#define SN_MAKE_TERMINATOR(sn)  (*(sn) = SRC_NULL)
702#define SN_IS_TERMINATOR(sn)    (*(sn) == SRC_NULL)
703
704/*
705 * Append a new source note of the given type (and therefore size) to cg's
706 * notes dynamic array, updating cg->noteCount. Return the new note's index
707 * within the array pointed at by cg->current->notes. Return -1 if out of
708 * memory.
709 */
710extern intN
711js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type);
712
713extern intN
714js_NewSrcNote2(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
715               ptrdiff_t offset);
716
717extern intN
718js_NewSrcNote3(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type,
719               ptrdiff_t offset1, ptrdiff_t offset2);
720
721/*
722 * NB: this function can add at most one extra extended delta note.
723 */
724extern jssrcnote *
725js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn,
726                     ptrdiff_t delta);
727
728/*
729 * Get and set the offset operand identified by which (0 for the first, etc.).
730 */
731extern JS_FRIEND_API(ptrdiff_t)
732js_GetSrcNoteOffset(jssrcnote *sn, uintN which);
733
734extern JSBool
735js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
736                    uintN which, ptrdiff_t offset);
737
738/*
739 * Finish taking source notes in cx's notePool, copying final notes to the new
740 * stable store allocated by the caller and passed in via notes. Return false
741 * on malloc failure, which means this function reported an error.
742 *
743 * To compute the number of jssrcnotes to allocate and pass in via notes, use
744 * the CG_COUNT_FINAL_SRCNOTES macro. This macro knows a lot about details of
745 * js_FinishTakingSrcNotes, SO DON'T CHANGE jsemit.c's js_FinishTakingSrcNotes
746 * FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES!
747 */
748#define CG_COUNT_FINAL_SRCNOTES(cg, cnt)                                      \
749    JS_BEGIN_MACRO                                                            \
750        ptrdiff_t diff_ = CG_PROLOG_OFFSET(cg) - (cg)->prolog.lastNoteOffset; \
751        cnt = (cg)->prolog.noteCount + (cg)->main.noteCount + 1;              \
752        if ((cg)->prolog.noteCount &&                                         \
753            (cg)->prolog.currentLine != (cg)->firstLine) {                    \
754            if (diff_ > SN_DELTA_MASK)                                        \
755                cnt += JS_HOWMANY(diff_ - SN_DELTA_MASK, SN_XDELTA_MASK);     \
756            cnt += 2 + (((cg)->firstLine > SN_3BYTE_OFFSET_MASK) << 1);       \
757        } else if (diff_ > 0) {                                               \
758            if (cg->main.noteCount) {                                         \
759                jssrcnote *sn_ = (cg)->main.notes;                            \
760                diff_ -= SN_IS_XDELTA(sn_)                                    \
761                         ? SN_XDELTA_MASK - (*sn_ & SN_XDELTA_MASK)           \
762                         : SN_DELTA_MASK - (*sn_ & SN_DELTA_MASK);            \
763            }                                                                 \
764            if (diff_ > 0)                                                    \
765                cnt += JS_HOWMANY(diff_, SN_XDELTA_MASK);                     \
766        }                                                                     \
767    JS_END_MACRO
768
769extern JSBool
770js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes);
771
772extern void
773js_FinishTakingTryNotes(JSCodeGenerator *cg, JSTryNoteArray *array);
774
775JS_END_EXTERN_C
776
777#endif /* jsemit_h___ */