js/src/frontend/ParseNode.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/frontend/ParseNode.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1508 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef frontend_ParseNode_h
    1.11 +#define frontend_ParseNode_h
    1.12 +
    1.13 +#include "mozilla/Attributes.h"
    1.14 +
    1.15 +#include "frontend/TokenStream.h"
    1.16 +
    1.17 +namespace js {
    1.18 +namespace frontend {
    1.19 +
    1.20 +template <typename ParseHandler>
    1.21 +struct ParseContext;
    1.22 +
    1.23 +class FullParseHandler;
    1.24 +class FunctionBox;
    1.25 +class ObjectBox;
    1.26 +
    1.27 +/*
    1.28 + * Indicates a location in the stack that an upvar value can be retrieved from
    1.29 + * as a two tuple of (level, slot).
    1.30 + *
    1.31 + * Some existing client code uses the level value as a delta, or level "skip"
    1.32 + * quantity. We could probably document that through use of more types at some
    1.33 + * point in the future.
    1.34 + */
    1.35 +class UpvarCookie
    1.36 +{
    1.37 +    uint32_t level_ : SCOPECOORD_HOPS_BITS;
    1.38 +    uint32_t slot_ : SCOPECOORD_SLOT_BITS;
    1.39 +
    1.40 +    void checkInvariants() {
    1.41 +        static_assert(sizeof(UpvarCookie) == sizeof(uint32_t),
    1.42 +                      "Not necessary for correctness, but good for ParseNode memory use");
    1.43 +    }
    1.44 +
    1.45 +  public:
    1.46 +    // Steal one value to represent the sentinel value for UpvarCookie.
    1.47 +    static const uint32_t FREE_LEVEL = SCOPECOORD_HOPS_LIMIT - 1;
    1.48 +    bool isFree() const { return level_ == FREE_LEVEL; }
    1.49 +
    1.50 +    uint32_t level() const { JS_ASSERT(!isFree()); return level_; }
    1.51 +    uint32_t slot()  const { JS_ASSERT(!isFree()); return slot_; }
    1.52 +
    1.53 +    // This fails and issues an error message if newLevel or newSlot are too large.
    1.54 +    bool set(TokenStream &ts, unsigned newLevel, uint32_t newSlot) {
    1.55 +        if (newLevel >= FREE_LEVEL)
    1.56 +            return ts.reportError(JSMSG_TOO_DEEP, js_function_str);
    1.57 +
    1.58 +        if (newSlot >= SCOPECOORD_SLOT_LIMIT)
    1.59 +            return ts.reportError(JSMSG_TOO_MANY_LOCALS);
    1.60 +
    1.61 +        level_ = newLevel;
    1.62 +        slot_ = newSlot;
    1.63 +        return true;
    1.64 +    }
    1.65 +
    1.66 +    void makeFree() {
    1.67 +        level_ = FREE_LEVEL;
    1.68 +        slot_ = 0;      // value doesn't matter, won't be used
    1.69 +        JS_ASSERT(isFree());
    1.70 +    }
    1.71 +};
    1.72 +
    1.73 +#define FOR_EACH_PARSE_NODE_KIND(F) \
    1.74 +    F(NOP) \
    1.75 +    F(SEMI) \
    1.76 +    F(COMMA) \
    1.77 +    F(CONDITIONAL) \
    1.78 +    F(COLON) \
    1.79 +    F(POS) \
    1.80 +    F(NEG) \
    1.81 +    F(PREINCREMENT) \
    1.82 +    F(POSTINCREMENT) \
    1.83 +    F(PREDECREMENT) \
    1.84 +    F(POSTDECREMENT) \
    1.85 +    F(DOT) \
    1.86 +    F(ELEM) \
    1.87 +    F(ARRAY) \
    1.88 +    F(ELISION) \
    1.89 +    F(STATEMENTLIST) \
    1.90 +    F(LABEL) \
    1.91 +    F(OBJECT) \
    1.92 +    F(CALL) \
    1.93 +    F(NAME) \
    1.94 +    F(NUMBER) \
    1.95 +    F(STRING) \
    1.96 +    F(REGEXP) \
    1.97 +    F(TRUE) \
    1.98 +    F(FALSE) \
    1.99 +    F(NULL) \
   1.100 +    F(THIS) \
   1.101 +    F(FUNCTION) \
   1.102 +    F(IF) \
   1.103 +    F(ELSE) \
   1.104 +    F(SWITCH) \
   1.105 +    F(CASE) \
   1.106 +    F(DEFAULT) \
   1.107 +    F(WHILE) \
   1.108 +    F(DOWHILE) \
   1.109 +    F(FOR) \
   1.110 +    F(BREAK) \
   1.111 +    F(CONTINUE) \
   1.112 +    F(VAR) \
   1.113 +    F(CONST) \
   1.114 +    F(WITH) \
   1.115 +    F(RETURN) \
   1.116 +    F(NEW) \
   1.117 +    F(DELETE) \
   1.118 +    F(TRY) \
   1.119 +    F(CATCH) \
   1.120 +    F(CATCHLIST) \
   1.121 +    F(FINALLY) \
   1.122 +    F(THROW) \
   1.123 +    F(DEBUGGER) \
   1.124 +    F(YIELD) \
   1.125 +    F(YIELD_STAR) \
   1.126 +    F(GENEXP) \
   1.127 +    F(ARRAYCOMP) \
   1.128 +    F(ARRAYPUSH) \
   1.129 +    F(LEXICALSCOPE) \
   1.130 +    F(LET) \
   1.131 +    F(IMPORT) \
   1.132 +    F(IMPORT_SPEC_LIST) \
   1.133 +    F(IMPORT_SPEC) \
   1.134 +    F(EXPORT) \
   1.135 +    F(EXPORT_FROM) \
   1.136 +    F(EXPORT_SPEC_LIST) \
   1.137 +    F(EXPORT_SPEC) \
   1.138 +    F(EXPORT_BATCH_SPEC) \
   1.139 +    F(SEQ) \
   1.140 +    F(FORIN) \
   1.141 +    F(FOROF) \
   1.142 +    F(FORHEAD) \
   1.143 +    F(ARGSBODY) \
   1.144 +    F(SPREAD) \
   1.145 +    \
   1.146 +    /* Unary operators. */ \
   1.147 +    F(TYPEOF) \
   1.148 +    F(VOID) \
   1.149 +    F(NOT) \
   1.150 +    F(BITNOT) \
   1.151 +    \
   1.152 +    /* \
   1.153 +     * Binary operators. \
   1.154 +     * These must be in the same order as TOK_OR and friends in TokenStream.h. \
   1.155 +     */ \
   1.156 +    F(OR) \
   1.157 +    F(AND) \
   1.158 +    F(BITOR) \
   1.159 +    F(BITXOR) \
   1.160 +    F(BITAND) \
   1.161 +    F(STRICTEQ) \
   1.162 +    F(EQ) \
   1.163 +    F(STRICTNE) \
   1.164 +    F(NE) \
   1.165 +    F(LT) \
   1.166 +    F(LE) \
   1.167 +    F(GT) \
   1.168 +    F(GE) \
   1.169 +    F(INSTANCEOF) \
   1.170 +    F(IN) \
   1.171 +    F(LSH) \
   1.172 +    F(RSH) \
   1.173 +    F(URSH) \
   1.174 +    F(ADD) \
   1.175 +    F(SUB) \
   1.176 +    F(STAR) \
   1.177 +    F(DIV) \
   1.178 +    F(MOD) \
   1.179 +    \
   1.180 +    /* Assignment operators (= += -= etc.). */ \
   1.181 +    /* ParseNode::isAssignment assumes all these are consecutive. */ \
   1.182 +    F(ASSIGN) \
   1.183 +    F(ADDASSIGN) \
   1.184 +    F(SUBASSIGN) \
   1.185 +    F(BITORASSIGN) \
   1.186 +    F(BITXORASSIGN) \
   1.187 +    F(BITANDASSIGN) \
   1.188 +    F(LSHASSIGN) \
   1.189 +    F(RSHASSIGN) \
   1.190 +    F(URSHASSIGN) \
   1.191 +    F(MULASSIGN) \
   1.192 +    F(DIVASSIGN) \
   1.193 +    F(MODASSIGN)
   1.194 +
   1.195 +/*
   1.196 + * Parsing builds a tree of nodes that directs code generation.  This tree is
   1.197 + * not a concrete syntax tree in all respects (for example, || and && are left
   1.198 + * associative, but (A && B && C) translates into the right-associated tree
   1.199 + * <A && <B && C>> so that code generation can emit a left-associative branch
   1.200 + * around <B && C> when A is false).  Nodes are labeled by kind, with a
   1.201 + * secondary JSOp label when needed.
   1.202 + *
   1.203 + * The long comment after this enum block describes the kinds in detail.
   1.204 + */
   1.205 +enum ParseNodeKind
   1.206 +{
   1.207 +#define EMIT_ENUM(name) PNK_##name,
   1.208 +    FOR_EACH_PARSE_NODE_KIND(EMIT_ENUM)
   1.209 +#undef EMIT_ENUM
   1.210 +    PNK_LIMIT, /* domain size */
   1.211 +    PNK_BINOP_FIRST = PNK_OR,
   1.212 +    PNK_BINOP_LAST = PNK_MOD,
   1.213 +    PNK_ASSIGNMENT_START = PNK_ASSIGN,
   1.214 +    PNK_ASSIGNMENT_LAST = PNK_MODASSIGN
   1.215 +};
   1.216 +
   1.217 +/*
   1.218 + * Label        Variant     Members
   1.219 + * -----        -------     -------
   1.220 + * <Definitions>
   1.221 + * PNK_FUNCTION name        pn_funbox: ptr to js::FunctionBox holding function
   1.222 + *                            object containing arg and var properties.  We
   1.223 + *                            create the function object at parse (not emit)
   1.224 + *                            time to specialize arg and var bytecodes early.
   1.225 + *                          pn_body: PNK_ARGSBODY, ordinarily;
   1.226 + *                            PNK_LEXICALSCOPE for implicit function in genexpr
   1.227 + *                          pn_cookie: static level and var index for function
   1.228 + *                          pn_dflags: PND_* definition/use flags (see below)
   1.229 + *                          pn_blockid: block id number
   1.230 + * PNK_ARGSBODY list        list of formal parameters followed by:
   1.231 + *                              PNK_STATEMENTLIST node for function body
   1.232 + *                                statements,
   1.233 + *                              PNK_RETURN for expression closure, or
   1.234 + *                              PNK_SEQ for expression closure with
   1.235 + *                                destructured formal parameters
   1.236 + *                          pn_count: 1 + number of formal parameters
   1.237 + *                          pn_tree: PNK_ARGSBODY or PNK_STATEMENTLIST node
   1.238 + * PNK_SPREAD   unary       pn_kid: expression being spread
   1.239 + *
   1.240 + * <Statements>
   1.241 + * PNK_STATEMENTLIST list   pn_head: list of pn_count statements
   1.242 + * PNK_IF       ternary     pn_kid1: cond, pn_kid2: then, pn_kid3: else or null.
   1.243 + *                            In body of a comprehension or desugared generator
   1.244 + *                            expression, pn_kid2 is PNK_YIELD, PNK_ARRAYPUSH,
   1.245 + *                            or (if the push was optimized away) empty
   1.246 + *                            PNK_STATEMENTLIST.
   1.247 + * PNK_SWITCH   binary      pn_left: discriminant
   1.248 + *                          pn_right: list of PNK_CASE nodes, with at most one
   1.249 + *                            PNK_DEFAULT node, or if there are let bindings
   1.250 + *                            in the top level of the switch body's cases, a
   1.251 + *                            PNK_LEXICALSCOPE node that contains the list of
   1.252 + *                            PNK_CASE nodes.
   1.253 + * PNK_CASE,    binary      pn_left: case expr
   1.254 + *                          pn_right: PNK_STATEMENTLIST node for this case's
   1.255 + *                            statements
   1.256 + * PNK_DEFAULT  binary      pn_left: null
   1.257 + *                          pn_right: PNK_STATEMENTLIST node for this default's
   1.258 + *                            statements
   1.259 + *                          pn_val: constant value if lookup or table switch
   1.260 + * PNK_WHILE    binary      pn_left: cond, pn_right: body
   1.261 + * PNK_DOWHILE  binary      pn_left: body, pn_right: cond
   1.262 + * PNK_FOR      binary      pn_left: either PNK_FORIN (for-in statement),
   1.263 + *                            PNK_FOROF (for-of) or PNK_FORHEAD (for(;;))
   1.264 + *                          pn_right: body
   1.265 + * PNK_FORIN    ternary     pn_kid1:  PNK_VAR to left of 'in', or nullptr
   1.266 + *                            its pn_xflags may have PNX_POPVAR
   1.267 + *                            bit set
   1.268 + *                          pn_kid2: PNK_NAME or destructuring expr
   1.269 + *                            to left of 'in'; if pn_kid1, then this
   1.270 + *                            is a clone of pn_kid1->pn_head
   1.271 + *                          pn_kid3: object expr to right of 'in'
   1.272 + * PNK_FOROF    ternary     pn_kid1:  PNK_VAR to left of 'of', or nullptr
   1.273 + *                            its pn_xflags may have PNX_POPVAR
   1.274 + *                            bit set
   1.275 + *                          pn_kid2: PNK_NAME or destructuring expr
   1.276 + *                            to left of 'of'; if pn_kid1, then this
   1.277 + *                            is a clone of pn_kid1->pn_head
   1.278 + *                          pn_kid3: expr to right of 'of'
   1.279 + * PNK_FORHEAD  ternary     pn_kid1:  init expr before first ';' or nullptr
   1.280 + *                          pn_kid2:  cond expr before second ';' or nullptr
   1.281 + *                          pn_kid3:  update expr after second ';' or nullptr
   1.282 + * PNK_THROW    unary       pn_op: JSOP_THROW, pn_kid: exception
   1.283 + * PNK_TRY      ternary     pn_kid1: try block
   1.284 + *                          pn_kid2: null or PNK_CATCHLIST list of
   1.285 + *                          PNK_LEXICALSCOPE nodes, each with pn_expr pointing
   1.286 + *                          to a PNK_CATCH node
   1.287 + *                          pn_kid3: null or finally block
   1.288 + * PNK_CATCH    ternary     pn_kid1: PNK_NAME, PNK_ARRAY, or PNK_OBJECT catch var node
   1.289 + *                                   (PNK_ARRAY or PNK_OBJECT if destructuring)
   1.290 + *                          pn_kid2: null or the catch guard expression
   1.291 + *                          pn_kid3: catch block statements
   1.292 + * PNK_BREAK    name        pn_atom: label or null
   1.293 + * PNK_CONTINUE name        pn_atom: label or null
   1.294 + * PNK_WITH     binary-obj  pn_left: head expr; pn_right: body; pn_binary_obj: StaticWithObject
   1.295 + * PNK_VAR,     list        pn_head: list of PNK_NAME or PNK_ASSIGN nodes
   1.296 + * PNK_CONST                         each name node has either
   1.297 + *                                     pn_used: false
   1.298 + *                                     pn_atom: variable name
   1.299 + *                                     pn_expr: initializer or null
   1.300 + *                                   or
   1.301 + *                                     pn_used: true
   1.302 + *                                     pn_atom: variable name
   1.303 + *                                     pn_lexdef: def node
   1.304 + *                                   each assignment node has
   1.305 + *                                     pn_left: PNK_NAME with pn_used true and
   1.306 + *                                              pn_lexdef (NOT pn_expr) set
   1.307 + *                                     pn_right: initializer
   1.308 + * PNK_RETURN   unary       pn_kid: return expr or null
   1.309 + * PNK_SEMI     unary       pn_kid: expr or null statement
   1.310 + *                          pn_prologue: true if Directive Prologue member
   1.311 + *                              in original source, not introduced via
   1.312 + *                              constant folding or other tree rewriting
   1.313 + * PNK_LABEL    name        pn_atom: label, pn_expr: labeled statement
   1.314 + *
   1.315 + * <Expressions>
   1.316 + * All left-associated binary trees of the same type are optimized into lists
   1.317 + * to avoid recursion when processing expression chains.
   1.318 + * PNK_COMMA    list        pn_head: list of pn_count comma-separated exprs
   1.319 + * PNK_ASSIGN   binary      pn_left: lvalue, pn_right: rvalue
   1.320 + * PNK_ADDASSIGN,   binary  pn_left: lvalue, pn_right: rvalue
   1.321 + * PNK_SUBASSIGN,           pn_op: JSOP_ADD for +=, etc.
   1.322 + * PNK_BITORASSIGN,
   1.323 + * PNK_BITXORASSIGN,
   1.324 + * PNK_BITANDASSIGN,
   1.325 + * PNK_LSHASSIGN,
   1.326 + * PNK_RSHASSIGN,
   1.327 + * PNK_URSHASSIGN,
   1.328 + * PNK_MULASSIGN,
   1.329 + * PNK_DIVASSIGN,
   1.330 + * PNK_MODASSIGN
   1.331 + * PNK_CONDITIONAL ternary  (cond ? trueExpr : falseExpr)
   1.332 + *                          pn_kid1: cond, pn_kid2: then, pn_kid3: else
   1.333 + * PNK_OR       binary      pn_left: first in || chain, pn_right: rest of chain
   1.334 + * PNK_AND      binary      pn_left: first in && chain, pn_right: rest of chain
   1.335 + * PNK_BITOR    binary      pn_left: left-assoc | expr, pn_right: ^ expr
   1.336 + * PNK_BITXOR   binary      pn_left: left-assoc ^ expr, pn_right: & expr
   1.337 + * PNK_BITAND   binary      pn_left: left-assoc & expr, pn_right: EQ expr
   1.338 + *
   1.339 + * PNK_EQ,      binary      pn_left: left-assoc EQ expr, pn_right: REL expr
   1.340 + * PNK_NE,
   1.341 + * PNK_STRICTEQ,
   1.342 + * PNK_STRICTNE
   1.343 + * PNK_LT,      binary      pn_left: left-assoc REL expr, pn_right: SH expr
   1.344 + * PNK_LE,
   1.345 + * PNK_GT,
   1.346 + * PNK_GE
   1.347 + * PNK_LSH,     binary      pn_left: left-assoc SH expr, pn_right: ADD expr
   1.348 + * PNK_RSH,
   1.349 + * PNK_URSH
   1.350 + * PNK_ADD      binary      pn_left: left-assoc ADD expr, pn_right: MUL expr
   1.351 + *                          pn_xflags: if a left-associated binary PNK_ADD
   1.352 + *                            tree has been flattened into a list (see above
   1.353 + *                            under <Expressions>), pn_xflags will contain
   1.354 + *                            PNX_STRCAT if at least one list element is a
   1.355 + *                            string literal (PNK_STRING); if such a list has
   1.356 + *                            any non-string, non-number term, pn_xflags will
   1.357 + *                            contain PNX_CANTFOLD.
   1.358 + * PNK_SUB      binary      pn_left: left-assoc SH expr, pn_right: ADD expr
   1.359 + * PNK_STAR,    binary      pn_left: left-assoc MUL expr, pn_right: UNARY expr
   1.360 + * PNK_DIV,                 pn_op: JSOP_MUL, JSOP_DIV, JSOP_MOD
   1.361 + * PNK_MOD
   1.362 + * PNK_POS,     unary       pn_kid: UNARY expr
   1.363 + * PNK_NEG
   1.364 + * PNK_TYPEOF,  unary       pn_kid: UNARY expr
   1.365 + * PNK_VOID,
   1.366 + * PNK_NOT,
   1.367 + * PNK_BITNOT
   1.368 + * PNK_PREINCREMENT, unary  pn_kid: MEMBER expr
   1.369 + * PNK_POSTINCREMENT,
   1.370 + * PNK_PREDECREMENT,
   1.371 + * PNK_POSTDECREMENT
   1.372 + * PNK_NEW      list        pn_head: list of ctor, arg1, arg2, ... argN
   1.373 + *                          pn_count: 1 + N (where N is number of args)
   1.374 + *                          ctor is a MEMBER expr
   1.375 + * PNK_DELETE   unary       pn_kid: MEMBER expr
   1.376 + * PNK_DOT      name        pn_expr: MEMBER expr to left of .
   1.377 + *                          pn_atom: name to right of .
   1.378 + * PNK_ELEM     binary      pn_left: MEMBER expr to left of [
   1.379 + *                          pn_right: expr between [ and ]
   1.380 + * PNK_CALL     list        pn_head: list of call, arg1, arg2, ... argN
   1.381 + *                          pn_count: 1 + N (where N is number of args)
   1.382 + *                          call is a MEMBER expr naming a callable object
   1.383 + * PNK_GENEXP   list        Exactly like PNK_CALL, used for the implicit call
   1.384 + *                          in the desugaring of a generator-expression.
   1.385 + * PNK_ARRAY    list        pn_head: list of pn_count array element exprs
   1.386 + *                          [,,] holes are represented by PNK_ELISION nodes
   1.387 + *                          pn_xflags: PN_ENDCOMMA if extra comma at end
   1.388 + * PNK_OBJECT   list        pn_head: list of pn_count binary PNK_COLON nodes
   1.389 + * PNK_COLON    binary      key-value pair in object initializer or
   1.390 + *                          destructuring lhs
   1.391 + *                          pn_left: property id, pn_right: value
   1.392 + *                          var {x} = object destructuring shorthand shares
   1.393 + *                          PN_NAME node for x on left and right of PNK_COLON
   1.394 + *                          node in PNK_OBJECT's list, has PNX_DESTRUCT flag
   1.395 + * PNK_NAME,    name        pn_atom: name, string, or object atom
   1.396 + * PNK_STRING               pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT
   1.397 + *                          If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR
   1.398 + *                          with pn_cookie telling (staticLevel, slot) (see
   1.399 + *                          jsscript.h's UPVAR macros) and pn_dflags telling
   1.400 + *                          const-ness and static analysis results
   1.401 + * PNK_REGEXP   nullary     pn_objbox: RegExp model object
   1.402 + * PNK_NAME     name        If pn_used, PNK_NAME uses the lexdef member instead
   1.403 + *                          of the expr member it overlays
   1.404 + * PNK_NUMBER   dval        pn_dval: double value of numeric literal
   1.405 + * PNK_TRUE,    nullary     pn_op: JSOp bytecode
   1.406 + * PNK_FALSE,
   1.407 + * PNK_NULL,
   1.408 + * PNK_THIS
   1.409 + *
   1.410 + * PNK_LEXICALSCOPE name    pn_objbox: block object in ObjectBox holder
   1.411 + *                          pn_expr: block body
   1.412 + * PNK_ARRAYCOMP    list    pn_count: 1
   1.413 + *                          pn_head: list of 1 element, which is block
   1.414 + *                          enclosing for loop(s) and optionally
   1.415 + *                          if-guarded PNK_ARRAYPUSH
   1.416 + * PNK_ARRAYPUSH    unary   pn_op: JSOP_ARRAYCOMP
   1.417 + *                          pn_kid: array comprehension expression
   1.418 + * PNK_NOP          nullary
   1.419 + */
   1.420 +enum ParseNodeArity
   1.421 +{
   1.422 +    PN_NULLARY,                         /* 0 kids, only pn_atom/pn_dval/etc. */
   1.423 +    PN_UNARY,                           /* one kid, plus a couple of scalars */
   1.424 +    PN_BINARY,                          /* two kids, plus a couple of scalars */
   1.425 +    PN_BINARY_OBJ,                      /* two kids, plus an objbox */
   1.426 +    PN_TERNARY,                         /* three kids */
   1.427 +    PN_CODE,                            /* module or function definition node */
   1.428 +    PN_LIST,                            /* generic singly linked list */
   1.429 +    PN_NAME                             /* name use or definition node */
   1.430 +};
   1.431 +
   1.432 +struct Definition;
   1.433 +
   1.434 +class LabeledStatement;
   1.435 +class LoopControlStatement;
   1.436 +class BreakStatement;
   1.437 +class ContinueStatement;
   1.438 +class ConditionalExpression;
   1.439 +class PropertyAccess;
   1.440 +
   1.441 +class ParseNode
   1.442 +{
   1.443 +    uint32_t            pn_type   : 16, /* PNK_* type */
   1.444 +                        pn_op     : 8,  /* see JSOp enum and jsopcode.tbl */
   1.445 +                        pn_arity  : 5,  /* see ParseNodeArity enum */
   1.446 +                        pn_parens : 1,  /* this expr was enclosed in parens */
   1.447 +                        pn_used   : 1,  /* name node is on a use-chain */
   1.448 +                        pn_defn   : 1;  /* this node is a Definition */
   1.449 +
   1.450 +    ParseNode(const ParseNode &other) MOZ_DELETE;
   1.451 +    void operator=(const ParseNode &other) MOZ_DELETE;
   1.452 +
   1.453 +  public:
   1.454 +    ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity)
   1.455 +      : pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
   1.456 +        pn_pos(0, 0), pn_offset(0), pn_next(nullptr), pn_link(nullptr)
   1.457 +    {
   1.458 +        JS_ASSERT(kind < PNK_LIMIT);
   1.459 +        memset(&pn_u, 0, sizeof pn_u);
   1.460 +    }
   1.461 +
   1.462 +    ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity, const TokenPos &pos)
   1.463 +      : pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
   1.464 +        pn_pos(pos), pn_offset(0), pn_next(nullptr), pn_link(nullptr)
   1.465 +    {
   1.466 +        JS_ASSERT(kind < PNK_LIMIT);
   1.467 +        memset(&pn_u, 0, sizeof pn_u);
   1.468 +    }
   1.469 +
   1.470 +    JSOp getOp() const                     { return JSOp(pn_op); }
   1.471 +    void setOp(JSOp op)                    { pn_op = op; }
   1.472 +    bool isOp(JSOp op) const               { return getOp() == op; }
   1.473 +
   1.474 +    ParseNodeKind getKind() const {
   1.475 +        JS_ASSERT(pn_type < PNK_LIMIT);
   1.476 +        return ParseNodeKind(pn_type);
   1.477 +    }
   1.478 +    void setKind(ParseNodeKind kind) {
   1.479 +        JS_ASSERT(kind < PNK_LIMIT);
   1.480 +        pn_type = kind;
   1.481 +    }
   1.482 +    bool isKind(ParseNodeKind kind) const  { return getKind() == kind; }
   1.483 +
   1.484 +    ParseNodeArity getArity() const        { return ParseNodeArity(pn_arity); }
   1.485 +    bool isArity(ParseNodeArity a) const   { return getArity() == a; }
   1.486 +    void setArity(ParseNodeArity a)        { pn_arity = a; }
   1.487 +
   1.488 +    bool isAssignment() const {
   1.489 +        ParseNodeKind kind = getKind();
   1.490 +        return PNK_ASSIGNMENT_START <= kind && kind <= PNK_ASSIGNMENT_LAST;
   1.491 +    }
   1.492 +
   1.493 +    /* Boolean attributes. */
   1.494 +    bool isInParens() const                { return pn_parens; }
   1.495 +    void setInParens(bool enabled)         { pn_parens = enabled; }
   1.496 +    bool isUsed() const                    { return pn_used; }
   1.497 +    void setUsed(bool enabled)             { pn_used = enabled; }
   1.498 +    bool isDefn() const                    { return pn_defn; }
   1.499 +    void setDefn(bool enabled)             { pn_defn = enabled; }
   1.500 +
   1.501 +    static const unsigned NumDefinitionFlagBits = 10;
   1.502 +    static const unsigned NumListFlagBits = 10;
   1.503 +    static const unsigned NumBlockIdBits = 22;
   1.504 +    static_assert(NumDefinitionFlagBits == NumListFlagBits,
   1.505 +                  "Assumed below to achieve consistent blockid offset");
   1.506 +    static_assert(NumDefinitionFlagBits + NumBlockIdBits <= 32,
   1.507 +                  "This is supposed to fit in a single uint32_t");
   1.508 +
   1.509 +    TokenPos            pn_pos;         /* two 16-bit pairs here, for 64 bits */
   1.510 +    int32_t             pn_offset;      /* first generated bytecode offset */
   1.511 +    ParseNode           *pn_next;       /* intrinsic link in parent PN_LIST */
   1.512 +    ParseNode           *pn_link;       /* def/use link (alignment freebie) */
   1.513 +
   1.514 +    union {
   1.515 +        struct {                        /* list of next-linked nodes */
   1.516 +            ParseNode   *head;          /* first node in list */
   1.517 +            ParseNode   **tail;         /* ptr to ptr to last node in list */
   1.518 +            uint32_t    count;          /* number of nodes in list */
   1.519 +            uint32_t    xflags:NumListFlagBits, /* see PNX_* below */
   1.520 +                        blockid:NumBlockIdBits; /* see name variant below */
   1.521 +        } list;
   1.522 +        struct {                        /* ternary: if, for(;;), ?: */
   1.523 +            ParseNode   *kid1;          /* condition, discriminant, etc. */
   1.524 +            ParseNode   *kid2;          /* then-part, case list, etc. */
   1.525 +            ParseNode   *kid3;          /* else-part, default case, etc. */
   1.526 +        } ternary;
   1.527 +        struct {                        /* two kids if binary */
   1.528 +            ParseNode   *left;
   1.529 +            ParseNode   *right;
   1.530 +            union {
   1.531 +                unsigned iflags;        /* JSITER_* flags for PNK_FOR node */
   1.532 +                ObjectBox *objbox;      /* Only for PN_BINARY_OBJ */
   1.533 +            };
   1.534 +        } binary;
   1.535 +        struct {                        /* one kid if unary */
   1.536 +            ParseNode   *kid;
   1.537 +            bool        prologue;       /* directive prologue member (as
   1.538 +                                           pn_prologue) */
   1.539 +        } unary;
   1.540 +        struct {                        /* name, labeled statement, etc. */
   1.541 +            union {
   1.542 +                JSAtom      *atom;      /* lexical name or label atom */
   1.543 +                ObjectBox   *objbox;    /* block or regexp object */
   1.544 +                FunctionBox *funbox;    /* function object */
   1.545 +            };
   1.546 +            union {
   1.547 +                ParseNode   *expr;      /* module or function body, var
   1.548 +                                           initializer, argument default, or
   1.549 +                                           base object of PNK_DOT */
   1.550 +                Definition  *lexdef;    /* lexical definition for this use */
   1.551 +            };
   1.552 +            UpvarCookie cookie;         /* upvar cookie with absolute frame
   1.553 +                                           level (not relative skip), possibly
   1.554 +                                           in current frame */
   1.555 +            uint32_t    dflags:NumDefinitionFlagBits, /* see PND_* below */
   1.556 +                        blockid:NumBlockIdBits;  /* block number, for subset dominance
   1.557 +                                                    computation */
   1.558 +        } name;
   1.559 +        struct {
   1.560 +            double      value;          /* aligned numeric literal value */
   1.561 +            DecimalPoint decimalPoint;  /* Whether the number has a decimal point */
   1.562 +        } number;
   1.563 +        class {
   1.564 +            friend class LoopControlStatement;
   1.565 +            PropertyName     *label;    /* target of break/continue statement */
   1.566 +        } loopControl;
   1.567 +    } pn_u;
   1.568 +
   1.569 +#define pn_modulebox    pn_u.name.modulebox
   1.570 +#define pn_funbox       pn_u.name.funbox
   1.571 +#define pn_body         pn_u.name.expr
   1.572 +#define pn_cookie       pn_u.name.cookie
   1.573 +#define pn_dflags       pn_u.name.dflags
   1.574 +#define pn_blockid      pn_u.name.blockid
   1.575 +#define pn_index        pn_u.name.blockid /* reuse as object table index */
   1.576 +#define pn_head         pn_u.list.head
   1.577 +#define pn_tail         pn_u.list.tail
   1.578 +#define pn_count        pn_u.list.count
   1.579 +#define pn_xflags       pn_u.list.xflags
   1.580 +#define pn_kid1         pn_u.ternary.kid1
   1.581 +#define pn_kid2         pn_u.ternary.kid2
   1.582 +#define pn_kid3         pn_u.ternary.kid3
   1.583 +#define pn_left         pn_u.binary.left
   1.584 +#define pn_right        pn_u.binary.right
   1.585 +#define pn_pval         pn_u.binary.pval
   1.586 +#define pn_iflags       pn_u.binary.iflags
   1.587 +#define pn_binary_obj   pn_u.binary.objbox
   1.588 +#define pn_kid          pn_u.unary.kid
   1.589 +#define pn_prologue     pn_u.unary.prologue
   1.590 +#define pn_atom         pn_u.name.atom
   1.591 +#define pn_objbox       pn_u.name.objbox
   1.592 +#define pn_expr         pn_u.name.expr
   1.593 +#define pn_lexdef       pn_u.name.lexdef
   1.594 +#define pn_dval         pn_u.number.value
   1.595 +
   1.596 +  protected:
   1.597 +    void init(TokenKind type, JSOp op, ParseNodeArity arity) {
   1.598 +        pn_type = type;
   1.599 +        pn_op = op;
   1.600 +        pn_arity = arity;
   1.601 +        pn_parens = false;
   1.602 +        JS_ASSERT(!pn_used);
   1.603 +        JS_ASSERT(!pn_defn);
   1.604 +        pn_next = pn_link = nullptr;
   1.605 +    }
   1.606 +
   1.607 +    static ParseNode *create(ParseNodeKind kind, ParseNodeArity arity, FullParseHandler *handler);
   1.608 +
   1.609 +  public:
   1.610 +    /*
   1.611 +     * Append right to left, forming a list node.  |left| must have the given
   1.612 +     * kind and op, and op must be left-associative.
   1.613 +     */
   1.614 +    static ParseNode *
   1.615 +    append(ParseNodeKind tt, JSOp op, ParseNode *left, ParseNode *right, FullParseHandler *handler);
   1.616 +
   1.617 +    /*
   1.618 +     * Either append right to left, if left meets the conditions necessary to
   1.619 +     * append (see append), or form a binary node whose children are right and
   1.620 +     * left.
   1.621 +     */
   1.622 +    static ParseNode *
   1.623 +    newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
   1.624 +                      FullParseHandler *handler, ParseContext<FullParseHandler> *pc,
   1.625 +                      bool foldConstants);
   1.626 +
   1.627 +    inline PropertyName *name() const;
   1.628 +    inline JSAtom *atom() const;
   1.629 +
   1.630 +    /*
   1.631 +     * The pn_expr and lexdef members are arms of an unsafe union. Unless you
   1.632 +     * know exactly what you're doing, use only the following methods to access
   1.633 +     * them. For less overhead and assertions for protection, use pn->expr()
   1.634 +     * and pn->lexdef(). Otherwise, use pn->maybeExpr() and pn->maybeLexDef().
   1.635 +     */
   1.636 +    ParseNode *expr() const {
   1.637 +        JS_ASSERT(!pn_used);
   1.638 +        JS_ASSERT(pn_arity == PN_NAME || pn_arity == PN_CODE);
   1.639 +        return pn_expr;
   1.640 +    }
   1.641 +
   1.642 +    Definition *lexdef() const {
   1.643 +        JS_ASSERT(pn_used || isDeoptimized());
   1.644 +        JS_ASSERT(pn_arity == PN_NAME);
   1.645 +        return pn_lexdef;
   1.646 +    }
   1.647 +
   1.648 +    ParseNode  *maybeExpr()   { return pn_used ? nullptr : expr(); }
   1.649 +    Definition *maybeLexDef() { return pn_used ? lexdef() : nullptr; }
   1.650 +
   1.651 +    Definition *resolve();
   1.652 +
   1.653 +/* PN_CODE and PN_NAME pn_dflags bits. */
   1.654 +#define PND_LET                 0x01    /* let (block-scoped) binding */
   1.655 +#define PND_CONST               0x02    /* const binding (orthogonal to let) */
   1.656 +#define PND_ASSIGNED            0x04    /* set if ever LHS of assignment */
   1.657 +#define PND_PLACEHOLDER         0x08    /* placeholder definition for lexdep */
   1.658 +#define PND_BOUND               0x10    /* bound to a stack or global slot */
   1.659 +#define PND_DEOPTIMIZED         0x20    /* former pn_used name node, pn_lexdef
   1.660 +                                           still valid, but this use no longer
   1.661 +                                           optimizable via an upvar opcode */
   1.662 +#define PND_CLOSED              0x40    /* variable is closed over */
   1.663 +#define PND_DEFAULT             0x80    /* definition is an arg with a default */
   1.664 +#define PND_IMPLICITARGUMENTS  0x100    /* the definition is a placeholder for
   1.665 +                                           'arguments' that has been converted
   1.666 +                                           into a definition after the function
   1.667 +                                           body has been parsed. */
   1.668 +#define PND_EMITTEDFUNCTION    0x200    /* hoisted function that was emitted */
   1.669 +
   1.670 +    static_assert(PND_EMITTEDFUNCTION < (1 << NumDefinitionFlagBits), "Not enough bits");
   1.671 +
   1.672 +/* Flags to propagate from uses to definition. */
   1.673 +#define PND_USE2DEF_FLAGS (PND_ASSIGNED | PND_CLOSED)
   1.674 +
   1.675 +/* PN_LIST pn_xflags bits. */
   1.676 +#define PNX_POPVAR      0x01            /* PNK_VAR or PNK_CONST last result
   1.677 +                                           needs popping */
   1.678 +#define PNX_GROUPINIT   0x02            /* var [a, b] = [c, d]; unit list */
   1.679 +#define PNX_FUNCDEFS    0x04            /* contains top-level function statements */
   1.680 +#define PNX_SETCALL     0x08            /* call expression in lvalue context */
   1.681 +#define PNX_DESTRUCT    0x10            /* destructuring special cases:
   1.682 +                                           1. shorthand syntax used, at present
   1.683 +                                              object destructuring ({x,y}) only;
   1.684 +                                           2. code evaluating destructuring
   1.685 +                                              arguments occurs before function
   1.686 +                                              body */
   1.687 +#define PNX_SPECIALARRAYINIT 0x20       /* one or more of
   1.688 +                                           1. array initialiser has holes
   1.689 +                                           2. array initializer has spread node */
   1.690 +#define PNX_NONCONST    0x40            /* initialiser has non-constants */
   1.691 +
   1.692 +    static_assert(PNX_NONCONST < (1 << NumListFlagBits), "Not enough bits");
   1.693 +
   1.694 +    unsigned frameLevel() const {
   1.695 +        JS_ASSERT(pn_arity == PN_CODE || pn_arity == PN_NAME);
   1.696 +        return pn_cookie.level();
   1.697 +    }
   1.698 +
   1.699 +    uint32_t frameSlot() const {
   1.700 +        JS_ASSERT(pn_arity == PN_CODE || pn_arity == PN_NAME);
   1.701 +        return pn_cookie.slot();
   1.702 +    }
   1.703 +
   1.704 +    bool functionIsHoisted() const {
   1.705 +        JS_ASSERT(pn_arity == PN_CODE && getKind() == PNK_FUNCTION);
   1.706 +        JS_ASSERT(isOp(JSOP_LAMBDA) ||        // lambda, genexpr
   1.707 +                  isOp(JSOP_LAMBDA_ARROW) ||  // arrow function
   1.708 +                  isOp(JSOP_DEFFUN) ||        // non-body-level function statement
   1.709 +                  isOp(JSOP_NOP) ||           // body-level function stmt in global code
   1.710 +                  isOp(JSOP_GETLOCAL) ||      // body-level function stmt in function code
   1.711 +                  isOp(JSOP_GETARG));         // body-level function redeclaring formal
   1.712 +        return !isOp(JSOP_LAMBDA) && !isOp(JSOP_LAMBDA_ARROW) && !isOp(JSOP_DEFFUN);
   1.713 +    }
   1.714 +
   1.715 +    /*
   1.716 +     * True if this statement node could be a member of a Directive Prologue: an
   1.717 +     * expression statement consisting of a single string literal.
   1.718 +     *
   1.719 +     * This considers only the node and its children, not its context. After
   1.720 +     * parsing, check the node's pn_prologue flag to see if it is indeed part of
   1.721 +     * a directive prologue.
   1.722 +     *
   1.723 +     * Note that a Directive Prologue can contain statements that cannot
   1.724 +     * themselves be directives (string literals that include escape sequences
   1.725 +     * or escaped newlines, say). This member function returns true for such
   1.726 +     * nodes; we use it to determine the extent of the prologue.
   1.727 +     */
   1.728 +    JSAtom *isStringExprStatement() const {
   1.729 +        if (getKind() == PNK_SEMI) {
   1.730 +            JS_ASSERT(pn_arity == PN_UNARY);
   1.731 +            ParseNode *kid = pn_kid;
   1.732 +            if (kid && kid->getKind() == PNK_STRING && !kid->pn_parens)
   1.733 +                return kid->pn_atom;
   1.734 +        }
   1.735 +        return nullptr;
   1.736 +    }
   1.737 +
   1.738 +    inline bool test(unsigned flag) const;
   1.739 +
   1.740 +    bool isLet() const          { return test(PND_LET); }
   1.741 +    bool isConst() const        { return test(PND_CONST); }
   1.742 +    bool isPlaceholder() const  { return test(PND_PLACEHOLDER); }
   1.743 +    bool isDeoptimized() const  { return test(PND_DEOPTIMIZED); }
   1.744 +    bool isAssigned() const     { return test(PND_ASSIGNED); }
   1.745 +    bool isClosed() const       { return test(PND_CLOSED); }
   1.746 +    bool isBound() const        { return test(PND_BOUND); }
   1.747 +    bool isImplicitArguments() const { return test(PND_IMPLICITARGUMENTS); }
   1.748 +
   1.749 +    /* True if pn is a parsenode representing a literal constant. */
   1.750 +    bool isLiteral() const {
   1.751 +        return isKind(PNK_NUMBER) ||
   1.752 +               isKind(PNK_STRING) ||
   1.753 +               isKind(PNK_TRUE) ||
   1.754 +               isKind(PNK_FALSE) ||
   1.755 +               isKind(PNK_NULL);
   1.756 +    }
   1.757 +
   1.758 +    /* Return true if this node appears in a Directive Prologue. */
   1.759 +    bool isDirectivePrologueMember() const { return pn_prologue; }
   1.760 +
   1.761 +#ifdef JS_HAS_GENERATOR_EXPRS
   1.762 +    ParseNode *generatorExpr() const {
   1.763 +        JS_ASSERT(isKind(PNK_GENEXP));
   1.764 +        ParseNode *callee = this->pn_head;
   1.765 +        ParseNode *body = callee->pn_body;
   1.766 +        JS_ASSERT(body->isKind(PNK_LEXICALSCOPE));
   1.767 +        return body->pn_expr;
   1.768 +    }
   1.769 +#endif
   1.770 +
   1.771 +    inline void markAsAssigned();
   1.772 +
   1.773 +    /*
   1.774 +     * Compute a pointer to the last element in a singly-linked list. NB: list
   1.775 +     * must be non-empty for correct PN_LAST usage -- this is asserted!
   1.776 +     */
   1.777 +    ParseNode *last() const {
   1.778 +        JS_ASSERT(pn_arity == PN_LIST);
   1.779 +        JS_ASSERT(pn_count != 0);
   1.780 +        return (ParseNode *)(uintptr_t(pn_tail) - offsetof(ParseNode, pn_next));
   1.781 +    }
   1.782 +
   1.783 +    void initNumber(double value, DecimalPoint decimalPoint) {
   1.784 +        JS_ASSERT(pn_arity == PN_NULLARY);
   1.785 +        JS_ASSERT(getKind() == PNK_NUMBER);
   1.786 +        pn_u.number.value = value;
   1.787 +        pn_u.number.decimalPoint = decimalPoint;
   1.788 +    }
   1.789 +
   1.790 +    void makeEmpty() {
   1.791 +        JS_ASSERT(pn_arity == PN_LIST);
   1.792 +        pn_head = nullptr;
   1.793 +        pn_tail = &pn_head;
   1.794 +        pn_count = 0;
   1.795 +        pn_xflags = 0;
   1.796 +        pn_blockid = 0;
   1.797 +    }
   1.798 +
   1.799 +    void initList(ParseNode *pn) {
   1.800 +        JS_ASSERT(pn_arity == PN_LIST);
   1.801 +        if (pn->pn_pos.begin < pn_pos.begin)
   1.802 +            pn_pos.begin = pn->pn_pos.begin;
   1.803 +        pn_pos.end = pn->pn_pos.end;
   1.804 +        pn_head = pn;
   1.805 +        pn_tail = &pn->pn_next;
   1.806 +        pn_count = 1;
   1.807 +        pn_xflags = 0;
   1.808 +        pn_blockid = 0;
   1.809 +    }
   1.810 +
   1.811 +    void append(ParseNode *pn) {
   1.812 +        JS_ASSERT(pn_arity == PN_LIST);
   1.813 +        JS_ASSERT(pn->pn_pos.begin >= pn_pos.begin);
   1.814 +        pn_pos.end = pn->pn_pos.end;
   1.815 +        *pn_tail = pn;
   1.816 +        pn_tail = &pn->pn_next;
   1.817 +        pn_count++;
   1.818 +    }
   1.819 +
   1.820 +    void checkListConsistency()
   1.821 +#ifndef DEBUG
   1.822 +    {}
   1.823 +#endif
   1.824 +    ;
   1.825 +
   1.826 +    bool getConstantValue(ExclusiveContext *cx, bool strictChecks, MutableHandleValue vp);
   1.827 +    inline bool isConstant();
   1.828 +
   1.829 +    template <class NodeType>
   1.830 +    inline bool is() const {
   1.831 +        return NodeType::test(*this);
   1.832 +    }
   1.833 +
   1.834 +    /* Casting operations. */
   1.835 +    template <class NodeType>
   1.836 +    inline NodeType &as() {
   1.837 +        JS_ASSERT(NodeType::test(*this));
   1.838 +        return *static_cast<NodeType *>(this);
   1.839 +    }
   1.840 +
   1.841 +    template <class NodeType>
   1.842 +    inline const NodeType &as() const {
   1.843 +        JS_ASSERT(NodeType::test(*this));
   1.844 +        return *static_cast<const NodeType *>(this);
   1.845 +    }
   1.846 +
   1.847 +#ifdef DEBUG
   1.848 +    void dump();
   1.849 +    void dump(int indent);
   1.850 +#endif
   1.851 +};
   1.852 +
   1.853 +struct NullaryNode : public ParseNode
   1.854 +{
   1.855 +    NullaryNode(ParseNodeKind kind, const TokenPos &pos)
   1.856 +      : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos) {}
   1.857 +    NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos)
   1.858 +      : ParseNode(kind, op, PN_NULLARY, pos) {}
   1.859 +
   1.860 +    // This constructor is for a few mad uses in the emitter. It populates
   1.861 +    // the pn_atom field even though that field belongs to a branch in pn_u
   1.862 +    // that nullary nodes shouldn't use -- bogus.
   1.863 +    NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, JSAtom *atom)
   1.864 +      : ParseNode(kind, op, PN_NULLARY, pos)
   1.865 +    {
   1.866 +        pn_atom = atom;
   1.867 +    }
   1.868 +
   1.869 +    static bool test(const ParseNode &node) {
   1.870 +        return node.isArity(PN_NULLARY);
   1.871 +    }
   1.872 +
   1.873 +#ifdef DEBUG
   1.874 +    void dump();
   1.875 +#endif
   1.876 +};
   1.877 +
   1.878 +struct UnaryNode : public ParseNode
   1.879 +{
   1.880 +    UnaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *kid)
   1.881 +      : ParseNode(kind, op, PN_UNARY, pos)
   1.882 +    {
   1.883 +        pn_kid = kid;
   1.884 +    }
   1.885 +
   1.886 +    static inline UnaryNode *create(ParseNodeKind kind, FullParseHandler *handler) {
   1.887 +        return (UnaryNode *) ParseNode::create(kind, PN_UNARY, handler);
   1.888 +    }
   1.889 +
   1.890 +    static bool test(const ParseNode &node) {
   1.891 +        return node.isArity(PN_UNARY);
   1.892 +    }
   1.893 +
   1.894 +#ifdef DEBUG
   1.895 +    void dump(int indent);
   1.896 +#endif
   1.897 +};
   1.898 +
   1.899 +struct BinaryNode : public ParseNode
   1.900 +{
   1.901 +    BinaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *left, ParseNode *right)
   1.902 +      : ParseNode(kind, op, PN_BINARY, pos)
   1.903 +    {
   1.904 +        pn_left = left;
   1.905 +        pn_right = right;
   1.906 +    }
   1.907 +
   1.908 +    BinaryNode(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right)
   1.909 +      : ParseNode(kind, op, PN_BINARY, TokenPos::box(left->pn_pos, right->pn_pos))
   1.910 +    {
   1.911 +        pn_left = left;
   1.912 +        pn_right = right;
   1.913 +    }
   1.914 +
   1.915 +    static inline BinaryNode *create(ParseNodeKind kind, FullParseHandler *handler) {
   1.916 +        return (BinaryNode *) ParseNode::create(kind, PN_BINARY, handler);
   1.917 +    }
   1.918 +
   1.919 +    static bool test(const ParseNode &node) {
   1.920 +        return node.isArity(PN_BINARY);
   1.921 +    }
   1.922 +
   1.923 +#ifdef DEBUG
   1.924 +    void dump(int indent);
   1.925 +#endif
   1.926 +};
   1.927 +
   1.928 +struct BinaryObjNode : public ParseNode
   1.929 +{
   1.930 +    BinaryObjNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *left, ParseNode *right,
   1.931 +                  ObjectBox *objbox)
   1.932 +      : ParseNode(kind, op, PN_BINARY_OBJ, pos)
   1.933 +    {
   1.934 +        pn_left = left;
   1.935 +        pn_right = right;
   1.936 +        pn_binary_obj = objbox;
   1.937 +    }
   1.938 +
   1.939 +    static inline BinaryObjNode *create(ParseNodeKind kind, FullParseHandler *handler) {
   1.940 +        return (BinaryObjNode *) ParseNode::create(kind, PN_BINARY_OBJ, handler);
   1.941 +    }
   1.942 +
   1.943 +    static bool test(const ParseNode &node) {
   1.944 +        return node.isArity(PN_BINARY_OBJ);
   1.945 +    }
   1.946 +
   1.947 +#ifdef DEBUG
   1.948 +    void dump(int indent);
   1.949 +#endif
   1.950 +};
   1.951 +
   1.952 +struct TernaryNode : public ParseNode
   1.953 +{
   1.954 +    TernaryNode(ParseNodeKind kind, JSOp op, ParseNode *kid1, ParseNode *kid2, ParseNode *kid3)
   1.955 +      : ParseNode(kind, op, PN_TERNARY,
   1.956 +                  TokenPos((kid1 ? kid1 : kid2 ? kid2 : kid3)->pn_pos.begin,
   1.957 +                           (kid3 ? kid3 : kid2 ? kid2 : kid1)->pn_pos.end))
   1.958 +    {
   1.959 +        pn_kid1 = kid1;
   1.960 +        pn_kid2 = kid2;
   1.961 +        pn_kid3 = kid3;
   1.962 +    }
   1.963 +
   1.964 +    TernaryNode(ParseNodeKind kind, JSOp op, ParseNode *kid1, ParseNode *kid2, ParseNode *kid3,
   1.965 +                const TokenPos &pos)
   1.966 +      : ParseNode(kind, op, PN_TERNARY, pos)
   1.967 +    {
   1.968 +        pn_kid1 = kid1;
   1.969 +        pn_kid2 = kid2;
   1.970 +        pn_kid3 = kid3;
   1.971 +    }
   1.972 +
   1.973 +    static inline TernaryNode *create(ParseNodeKind kind, FullParseHandler *handler) {
   1.974 +        return (TernaryNode *) ParseNode::create(kind, PN_TERNARY, handler);
   1.975 +    }
   1.976 +
   1.977 +    static bool test(const ParseNode &node) {
   1.978 +        return node.isArity(PN_TERNARY);
   1.979 +    }
   1.980 +
   1.981 +#ifdef DEBUG
   1.982 +    void dump(int indent);
   1.983 +#endif
   1.984 +};
   1.985 +
   1.986 +struct ListNode : public ParseNode
   1.987 +{
   1.988 +    ListNode(ParseNodeKind kind, const TokenPos &pos)
   1.989 +      : ParseNode(kind, JSOP_NOP, PN_LIST, pos)
   1.990 +    {
   1.991 +        makeEmpty();
   1.992 +    }
   1.993 +
   1.994 +    ListNode(ParseNodeKind kind, JSOp op, ParseNode *kid)
   1.995 +      : ParseNode(kind, op, PN_LIST, kid->pn_pos)
   1.996 +    {
   1.997 +        initList(kid);
   1.998 +    }
   1.999 +
  1.1000 +    static inline ListNode *create(ParseNodeKind kind, FullParseHandler *handler) {
  1.1001 +        return (ListNode *) ParseNode::create(kind, PN_LIST, handler);
  1.1002 +    }
  1.1003 +
  1.1004 +    static bool test(const ParseNode &node) {
  1.1005 +        return node.isArity(PN_LIST);
  1.1006 +    }
  1.1007 +
  1.1008 +#ifdef DEBUG
  1.1009 +    void dump(int indent);
  1.1010 +#endif
  1.1011 +};
  1.1012 +
  1.1013 +struct CodeNode : public ParseNode
  1.1014 +{
  1.1015 +    static inline CodeNode *create(ParseNodeKind kind, FullParseHandler *handler) {
  1.1016 +        return (CodeNode *) ParseNode::create(kind, PN_CODE, handler);
  1.1017 +    }
  1.1018 +
  1.1019 +    static bool test(const ParseNode &node) {
  1.1020 +        return node.isArity(PN_CODE);
  1.1021 +    }
  1.1022 +
  1.1023 +#ifdef DEBUG
  1.1024 +    void dump(int indent);
  1.1025 +#endif
  1.1026 +};
  1.1027 +
  1.1028 +struct NameNode : public ParseNode
  1.1029 +{
  1.1030 +    NameNode(ParseNodeKind kind, JSOp op, JSAtom *atom, uint32_t blockid,
  1.1031 +             const TokenPos &pos)
  1.1032 +      : ParseNode(kind, op, PN_NAME, pos)
  1.1033 +    {
  1.1034 +        pn_atom = atom;
  1.1035 +        pn_expr = nullptr;
  1.1036 +        pn_cookie.makeFree();
  1.1037 +        pn_dflags = 0;
  1.1038 +        pn_blockid = blockid;
  1.1039 +        JS_ASSERT(pn_blockid == blockid);  // check for bitfield overflow
  1.1040 +    }
  1.1041 +
  1.1042 +    static bool test(const ParseNode &node) {
  1.1043 +        return node.isArity(PN_NAME);
  1.1044 +    }
  1.1045 +
  1.1046 +#ifdef DEBUG
  1.1047 +    void dump(int indent);
  1.1048 +#endif
  1.1049 +};
  1.1050 +
  1.1051 +struct LexicalScopeNode : public ParseNode
  1.1052 +{
  1.1053 +    static inline LexicalScopeNode *create(ParseNodeKind kind, FullParseHandler *handler) {
  1.1054 +        return (LexicalScopeNode *) ParseNode::create(kind, PN_NAME, handler);
  1.1055 +    }
  1.1056 +};
  1.1057 +
  1.1058 +class LabeledStatement : public ParseNode
  1.1059 +{
  1.1060 +  public:
  1.1061 +    LabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin)
  1.1062 +      : ParseNode(PNK_LABEL, JSOP_NOP, PN_NAME, TokenPos(begin, stmt->pn_pos.end))
  1.1063 +    {
  1.1064 +        pn_atom = label;
  1.1065 +        pn_expr = stmt;
  1.1066 +    }
  1.1067 +
  1.1068 +    PropertyName *label() const {
  1.1069 +        return pn_atom->asPropertyName();
  1.1070 +    }
  1.1071 +
  1.1072 +    ParseNode *statement() const {
  1.1073 +        return pn_expr;
  1.1074 +    }
  1.1075 +
  1.1076 +    static bool test(const ParseNode &node) {
  1.1077 +        bool match = node.isKind(PNK_LABEL);
  1.1078 +        JS_ASSERT_IF(match, node.isArity(PN_NAME));
  1.1079 +        JS_ASSERT_IF(match, node.isOp(JSOP_NOP));
  1.1080 +        return match;
  1.1081 +    }
  1.1082 +};
  1.1083 +
  1.1084 +class LoopControlStatement : public ParseNode
  1.1085 +{
  1.1086 +  protected:
  1.1087 +    LoopControlStatement(ParseNodeKind kind, PropertyName *label, const TokenPos &pos)
  1.1088 +      : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos)
  1.1089 +    {
  1.1090 +        JS_ASSERT(kind == PNK_BREAK || kind == PNK_CONTINUE);
  1.1091 +        pn_u.loopControl.label = label;
  1.1092 +    }
  1.1093 +
  1.1094 +  public:
  1.1095 +    /* Label associated with this break/continue statement, if any. */
  1.1096 +    PropertyName *label() const {
  1.1097 +        return pn_u.loopControl.label;
  1.1098 +    }
  1.1099 +
  1.1100 +    static bool test(const ParseNode &node) {
  1.1101 +        bool match = node.isKind(PNK_BREAK) || node.isKind(PNK_CONTINUE);
  1.1102 +        JS_ASSERT_IF(match, node.isArity(PN_NULLARY));
  1.1103 +        JS_ASSERT_IF(match, node.isOp(JSOP_NOP));
  1.1104 +        return match;
  1.1105 +    }
  1.1106 +};
  1.1107 +
  1.1108 +class BreakStatement : public LoopControlStatement
  1.1109 +{
  1.1110 +  public:
  1.1111 +    BreakStatement(PropertyName *label, const TokenPos &pos)
  1.1112 +      : LoopControlStatement(PNK_BREAK, label, pos)
  1.1113 +    { }
  1.1114 +
  1.1115 +    static bool test(const ParseNode &node) {
  1.1116 +        bool match = node.isKind(PNK_BREAK);
  1.1117 +        JS_ASSERT_IF(match, node.isArity(PN_NULLARY));
  1.1118 +        JS_ASSERT_IF(match, node.isOp(JSOP_NOP));
  1.1119 +        return match;
  1.1120 +    }
  1.1121 +};
  1.1122 +
  1.1123 +class ContinueStatement : public LoopControlStatement
  1.1124 +{
  1.1125 +  public:
  1.1126 +    ContinueStatement(PropertyName *label, const TokenPos &pos)
  1.1127 +      : LoopControlStatement(PNK_CONTINUE, label, pos)
  1.1128 +    { }
  1.1129 +
  1.1130 +    static bool test(const ParseNode &node) {
  1.1131 +        bool match = node.isKind(PNK_CONTINUE);
  1.1132 +        JS_ASSERT_IF(match, node.isArity(PN_NULLARY));
  1.1133 +        JS_ASSERT_IF(match, node.isOp(JSOP_NOP));
  1.1134 +        return match;
  1.1135 +    }
  1.1136 +};
  1.1137 +
  1.1138 +class DebuggerStatement : public ParseNode
  1.1139 +{
  1.1140 +  public:
  1.1141 +    DebuggerStatement(const TokenPos &pos)
  1.1142 +      : ParseNode(PNK_DEBUGGER, JSOP_NOP, PN_NULLARY, pos)
  1.1143 +    { }
  1.1144 +};
  1.1145 +
  1.1146 +class ConditionalExpression : public ParseNode
  1.1147 +{
  1.1148 +  public:
  1.1149 +    ConditionalExpression(ParseNode *condition, ParseNode *thenExpr, ParseNode *elseExpr)
  1.1150 +      : ParseNode(PNK_CONDITIONAL, JSOP_NOP, PN_TERNARY,
  1.1151 +                  TokenPos(condition->pn_pos.begin, elseExpr->pn_pos.end))
  1.1152 +    {
  1.1153 +        JS_ASSERT(condition);
  1.1154 +        JS_ASSERT(thenExpr);
  1.1155 +        JS_ASSERT(elseExpr);
  1.1156 +        pn_u.ternary.kid1 = condition;
  1.1157 +        pn_u.ternary.kid2 = thenExpr;
  1.1158 +        pn_u.ternary.kid3 = elseExpr;
  1.1159 +    }
  1.1160 +
  1.1161 +    ParseNode &condition() const {
  1.1162 +        return *pn_u.ternary.kid1;
  1.1163 +    }
  1.1164 +
  1.1165 +    ParseNode &thenExpression() const {
  1.1166 +        return *pn_u.ternary.kid2;
  1.1167 +    }
  1.1168 +
  1.1169 +    ParseNode &elseExpression() const {
  1.1170 +        return *pn_u.ternary.kid3;
  1.1171 +    }
  1.1172 +
  1.1173 +    static bool test(const ParseNode &node) {
  1.1174 +        bool match = node.isKind(PNK_CONDITIONAL);
  1.1175 +        JS_ASSERT_IF(match, node.isArity(PN_TERNARY));
  1.1176 +        JS_ASSERT_IF(match, node.isOp(JSOP_NOP));
  1.1177 +        return match;
  1.1178 +    }
  1.1179 +};
  1.1180 +
  1.1181 +class ThisLiteral : public ParseNode
  1.1182 +{
  1.1183 +  public:
  1.1184 +    ThisLiteral(const TokenPos &pos) : ParseNode(PNK_THIS, JSOP_THIS, PN_NULLARY, pos) { }
  1.1185 +};
  1.1186 +
  1.1187 +class NullLiteral : public ParseNode
  1.1188 +{
  1.1189 +  public:
  1.1190 +    NullLiteral(const TokenPos &pos) : ParseNode(PNK_NULL, JSOP_NULL, PN_NULLARY, pos) { }
  1.1191 +};
  1.1192 +
  1.1193 +class BooleanLiteral : public ParseNode
  1.1194 +{
  1.1195 +  public:
  1.1196 +    BooleanLiteral(bool b, const TokenPos &pos)
  1.1197 +      : ParseNode(b ? PNK_TRUE : PNK_FALSE, b ? JSOP_TRUE : JSOP_FALSE, PN_NULLARY, pos)
  1.1198 +    { }
  1.1199 +};
  1.1200 +
  1.1201 +class RegExpLiteral : public NullaryNode
  1.1202 +{
  1.1203 +  public:
  1.1204 +    RegExpLiteral(ObjectBox *reobj, const TokenPos &pos)
  1.1205 +      : NullaryNode(PNK_REGEXP, JSOP_REGEXP, pos)
  1.1206 +    {
  1.1207 +        pn_objbox = reobj;
  1.1208 +    }
  1.1209 +
  1.1210 +    ObjectBox *objbox() const { return pn_objbox; }
  1.1211 +
  1.1212 +    static bool test(const ParseNode &node) {
  1.1213 +        bool match = node.isKind(PNK_REGEXP);
  1.1214 +        JS_ASSERT_IF(match, node.isArity(PN_NULLARY));
  1.1215 +        JS_ASSERT_IF(match, node.isOp(JSOP_REGEXP));
  1.1216 +        return match;
  1.1217 +    }
  1.1218 +};
  1.1219 +
  1.1220 +class PropertyAccess : public ParseNode
  1.1221 +{
  1.1222 +  public:
  1.1223 +    PropertyAccess(ParseNode *lhs, PropertyName *name, uint32_t begin, uint32_t end)
  1.1224 +      : ParseNode(PNK_DOT, JSOP_NOP, PN_NAME, TokenPos(begin, end))
  1.1225 +    {
  1.1226 +        JS_ASSERT(lhs != nullptr);
  1.1227 +        JS_ASSERT(name != nullptr);
  1.1228 +        pn_u.name.expr = lhs;
  1.1229 +        pn_u.name.atom = name;
  1.1230 +    }
  1.1231 +
  1.1232 +    static bool test(const ParseNode &node) {
  1.1233 +        bool match = node.isKind(PNK_DOT);
  1.1234 +        JS_ASSERT_IF(match, node.isArity(PN_NAME));
  1.1235 +        return match;
  1.1236 +    }
  1.1237 +
  1.1238 +    ParseNode &expression() const {
  1.1239 +        return *pn_u.name.expr;
  1.1240 +    }
  1.1241 +
  1.1242 +    PropertyName &name() const {
  1.1243 +        return *pn_u.name.atom->asPropertyName();
  1.1244 +    }
  1.1245 +};
  1.1246 +
  1.1247 +class PropertyByValue : public ParseNode
  1.1248 +{
  1.1249 +  public:
  1.1250 +    PropertyByValue(ParseNode *lhs, ParseNode *propExpr, uint32_t begin, uint32_t end)
  1.1251 +      : ParseNode(PNK_ELEM, JSOP_NOP, PN_BINARY, TokenPos(begin, end))
  1.1252 +    {
  1.1253 +        pn_u.binary.left = lhs;
  1.1254 +        pn_u.binary.right = propExpr;
  1.1255 +    }
  1.1256 +};
  1.1257 +
  1.1258 +#ifdef DEBUG
  1.1259 +void DumpParseTree(ParseNode *pn, int indent = 0);
  1.1260 +#endif
  1.1261 +
  1.1262 +/*
  1.1263 + * js::Definition is a degenerate subtype of the PN_FUNC and PN_NAME variants
  1.1264 + * of js::ParseNode, allocated only for function, var, const, and let
  1.1265 + * declarations that define truly lexical bindings. This means that a child of
  1.1266 + * a PNK_VAR list may be a Definition as well as a ParseNode. The pn_defn bit
  1.1267 + * is set for all Definitions, clear otherwise.
  1.1268 + *
  1.1269 + * In an upvars list, defn->resolve() is the outermost definition the
  1.1270 + * name may reference. If a with block or a function that calls eval encloses
  1.1271 + * the use, the name may end up referring to something else at runtime.
  1.1272 + *
  1.1273 + * Note that not all var declarations are definitions: JS allows multiple var
  1.1274 + * declarations in a function or script, but only the first creates the hoisted
  1.1275 + * binding. JS programmers do redeclare variables for good refactoring reasons,
  1.1276 + * for example:
  1.1277 + *
  1.1278 + *   function foo() {
  1.1279 + *       ...
  1.1280 + *       for (var i ...) ...;
  1.1281 + *       ...
  1.1282 + *       for (var i ...) ...;
  1.1283 + *       ...
  1.1284 + *   }
  1.1285 + *
  1.1286 + * Not all definitions bind lexical variables, alas. In global and eval code
  1.1287 + * var may re-declare a pre-existing property having any attributes, with or
  1.1288 + * without JSPROP_PERMANENT. In eval code, indeed, ECMA-262 Editions 1 through
  1.1289 + * 3 require function and var to bind deletable bindings. Global vars thus are
  1.1290 + * properties of the global object, so they can be aliased even if they can't
  1.1291 + * be deleted.
  1.1292 + *
  1.1293 + * Only bindings within function code may be treated as lexical, of course with
  1.1294 + * the caveat that hoisting means use before initialization is allowed. We deal
  1.1295 + * with use before declaration in one pass as follows (error checking elided):
  1.1296 + *
  1.1297 + *   for (each use of unqualified name x in parse order) {
  1.1298 + *       if (this use of x is a declaration) {
  1.1299 + *           if (x in pc->decls) {                          // redeclaring
  1.1300 + *               pn = allocate a PN_NAME ParseNode;
  1.1301 + *           } else {                                       // defining
  1.1302 + *               dn = lookup x in pc->lexdeps;
  1.1303 + *               if (dn)                                    // use before def
  1.1304 + *                   remove x from pc->lexdeps;
  1.1305 + *               else                                       // def before use
  1.1306 + *                   dn = allocate a PN_NAME Definition;
  1.1307 + *               map x to dn via pc->decls;
  1.1308 + *               pn = dn;
  1.1309 + *           }
  1.1310 + *           insert pn into its parent PNK_VAR/PNK_CONST list;
  1.1311 + *       } else {
  1.1312 + *           pn = allocate a ParseNode for this reference to x;
  1.1313 + *           dn = lookup x in pc's lexical scope chain;
  1.1314 + *           if (!dn) {
  1.1315 + *               dn = lookup x in pc->lexdeps;
  1.1316 + *               if (!dn) {
  1.1317 + *                   dn = pre-allocate a Definition for x;
  1.1318 + *                   map x to dn in pc->lexdeps;
  1.1319 + *               }
  1.1320 + *           }
  1.1321 + *           append pn to dn's use chain;
  1.1322 + *       }
  1.1323 + *   }
  1.1324 + *
  1.1325 + * See frontend/BytecodeEmitter.h for js::ParseContext and its top*Stmt,
  1.1326 + * decls, and lexdeps members.
  1.1327 + *
  1.1328 + * Notes:
  1.1329 + *
  1.1330 + *  0. To avoid bloating ParseNode, we steal a bit from pn_arity for pn_defn
  1.1331 + *     and set it on a ParseNode instead of allocating a Definition.
  1.1332 + *
  1.1333 + *  1. Due to hoisting, a definition cannot be eliminated even if its "Variable
  1.1334 + *     statement" (ECMA-262 12.2) can be proven to be dead code. RecycleTree in
  1.1335 + *     ParseNode.cpp will not recycle a node whose pn_defn bit is set.
  1.1336 + *
  1.1337 + *  2. "lookup x in pc's lexical scope chain" gives up on def/use chaining if a
  1.1338 + *     with statement is found along the the scope chain, which includes pc,
  1.1339 + *     pc->parent, etc. Thus we eagerly connect an inner function's use of an
  1.1340 + *     outer's var x if the var x was parsed before the inner function.
  1.1341 + *
  1.1342 + *  3. A use may be eliminated as dead by the constant folder, which therefore
  1.1343 + *     must remove the dead name node from its singly-linked use chain, which
  1.1344 + *     would mean hashing to find the definition node and searching to update
  1.1345 + *     the pn_link pointing at the use to be removed. This is costly, so as for
  1.1346 + *     dead definitions, we do not recycle dead pn_used nodes.
  1.1347 + *
  1.1348 + * At the end of parsing a function body or global or eval program, pc->lexdeps
  1.1349 + * holds the lexical dependencies of the parsed unit. The name to def/use chain
  1.1350 + * mappings are then merged into the parent pc->lexdeps.
  1.1351 + *
  1.1352 + * Thus if a later var x is parsed in the outer function satisfying an earlier
  1.1353 + * inner function's use of x, we will remove dn from pc->lexdeps and re-use it
  1.1354 + * as the new definition node in the outer function's parse tree.
  1.1355 + *
  1.1356 + * When the compiler unwinds from the outermost pc, pc->lexdeps contains the
  1.1357 + * definition nodes with use chains for all free variables. These are either
  1.1358 + * global variables or reference errors.
  1.1359 + */
  1.1360 +#define dn_uses         pn_link
  1.1361 +
  1.1362 +struct Definition : public ParseNode
  1.1363 +{
  1.1364 +    bool isFreeVar() const {
  1.1365 +        JS_ASSERT(isDefn());
  1.1366 +        return pn_cookie.isFree();
  1.1367 +    }
  1.1368 +
  1.1369 +    enum Kind { MISSING = 0, VAR, CONST, LET, ARG, NAMED_LAMBDA, PLACEHOLDER };
  1.1370 +
  1.1371 +    bool canHaveInitializer() { return int(kind()) <= int(ARG); }
  1.1372 +
  1.1373 +    static const char *kindString(Kind kind);
  1.1374 +
  1.1375 +    Kind kind() {
  1.1376 +        if (getKind() == PNK_FUNCTION) {
  1.1377 +            if (isOp(JSOP_GETARG))
  1.1378 +                return ARG;
  1.1379 +            return VAR;
  1.1380 +        }
  1.1381 +        JS_ASSERT(getKind() == PNK_NAME);
  1.1382 +        if (isOp(JSOP_CALLEE))
  1.1383 +            return NAMED_LAMBDA;
  1.1384 +        if (isPlaceholder())
  1.1385 +            return PLACEHOLDER;
  1.1386 +        if (isOp(JSOP_GETARG))
  1.1387 +            return ARG;
  1.1388 +        if (isConst())
  1.1389 +            return CONST;
  1.1390 +        if (isLet())
  1.1391 +            return LET;
  1.1392 +        return VAR;
  1.1393 +    }
  1.1394 +};
  1.1395 +
  1.1396 +class ParseNodeAllocator
  1.1397 +{
  1.1398 +  public:
  1.1399 +    explicit ParseNodeAllocator(ExclusiveContext *cx, LifoAlloc &alloc)
  1.1400 +      : cx(cx), alloc(alloc), freelist(nullptr)
  1.1401 +    {}
  1.1402 +
  1.1403 +    void *allocNode();
  1.1404 +    void freeNode(ParseNode *pn);
  1.1405 +    ParseNode *freeTree(ParseNode *pn);
  1.1406 +    void prepareNodeForMutation(ParseNode *pn);
  1.1407 +
  1.1408 +  private:
  1.1409 +    ExclusiveContext *cx;
  1.1410 +    LifoAlloc &alloc;
  1.1411 +    ParseNode *freelist;
  1.1412 +};
  1.1413 +
  1.1414 +inline bool
  1.1415 +ParseNode::test(unsigned flag) const
  1.1416 +{
  1.1417 +    JS_ASSERT(pn_defn || pn_arity == PN_CODE || pn_arity == PN_NAME);
  1.1418 +#ifdef DEBUG
  1.1419 +    if ((flag & PND_ASSIGNED) && pn_defn && !(pn_dflags & flag)) {
  1.1420 +        for (ParseNode *pn = ((Definition *) this)->dn_uses; pn; pn = pn->pn_link) {
  1.1421 +            JS_ASSERT(!pn->pn_defn);
  1.1422 +            JS_ASSERT(!(pn->pn_dflags & flag));
  1.1423 +        }
  1.1424 +    }
  1.1425 +#endif
  1.1426 +    return !!(pn_dflags & flag);
  1.1427 +}
  1.1428 +
  1.1429 +inline void
  1.1430 +ParseNode::markAsAssigned()
  1.1431 +{
  1.1432 +    JS_ASSERT(js_CodeSpec[pn_op].format & JOF_NAME);
  1.1433 +    if (isUsed())
  1.1434 +        pn_lexdef->pn_dflags |= PND_ASSIGNED;
  1.1435 +    pn_dflags |= PND_ASSIGNED;
  1.1436 +}
  1.1437 +
  1.1438 +inline Definition *
  1.1439 +ParseNode::resolve()
  1.1440 +{
  1.1441 +    if (isDefn())
  1.1442 +        return (Definition *)this;
  1.1443 +    JS_ASSERT(lexdef()->isDefn());
  1.1444 +    return (Definition *)lexdef();
  1.1445 +}
  1.1446 +
  1.1447 +inline bool
  1.1448 +ParseNode::isConstant()
  1.1449 +{
  1.1450 +    switch (pn_type) {
  1.1451 +      case PNK_NUMBER:
  1.1452 +      case PNK_STRING:
  1.1453 +      case PNK_NULL:
  1.1454 +      case PNK_FALSE:
  1.1455 +      case PNK_TRUE:
  1.1456 +        return true;
  1.1457 +      case PNK_ARRAY:
  1.1458 +      case PNK_OBJECT:
  1.1459 +        JS_ASSERT(isOp(JSOP_NEWINIT));
  1.1460 +        return !(pn_xflags & PNX_NONCONST);
  1.1461 +      default:
  1.1462 +        return false;
  1.1463 +    }
  1.1464 +}
  1.1465 +
  1.1466 +class ObjectBox
  1.1467 +{
  1.1468 +  public:
  1.1469 +    JSObject *object;
  1.1470 +
  1.1471 +    ObjectBox(JSObject *object, ObjectBox *traceLink);
  1.1472 +    bool isFunctionBox() { return object->is<JSFunction>(); }
  1.1473 +    FunctionBox *asFunctionBox();
  1.1474 +    void trace(JSTracer *trc);
  1.1475 +
  1.1476 +  protected:
  1.1477 +    friend struct CGObjectList;
  1.1478 +
  1.1479 +    ObjectBox *traceLink;
  1.1480 +    ObjectBox *emitLink;
  1.1481 +
  1.1482 +    ObjectBox(JSFunction *function, ObjectBox *traceLink);
  1.1483 +};
  1.1484 +
  1.1485 +enum ParseReportKind
  1.1486 +{
  1.1487 +    ParseError,
  1.1488 +    ParseWarning,
  1.1489 +    ParseExtraWarning,
  1.1490 +    ParseStrictError
  1.1491 +};
  1.1492 +
  1.1493 +enum FunctionSyntaxKind { Expression, Statement, Arrow };
  1.1494 +
  1.1495 +static inline ParseNode *
  1.1496 +FunctionArgsList(ParseNode *fn, unsigned *numFormals)
  1.1497 +{
  1.1498 +    JS_ASSERT(fn->isKind(PNK_FUNCTION));
  1.1499 +    ParseNode *argsBody = fn->pn_body;
  1.1500 +    JS_ASSERT(argsBody->isKind(PNK_ARGSBODY));
  1.1501 +    *numFormals = argsBody->pn_count;
  1.1502 +    if (*numFormals > 0 && argsBody->last()->isKind(PNK_STATEMENTLIST))
  1.1503 +        (*numFormals)--;
  1.1504 +    JS_ASSERT(argsBody->isArity(PN_LIST));
  1.1505 +    return argsBody->pn_head;
  1.1506 +}
  1.1507 +
  1.1508 +} /* namespace frontend */
  1.1509 +} /* namespace js */
  1.1510 +
  1.1511 +#endif /* frontend_ParseNode_h */

mercurial