1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=99:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla Communicator client code, released
18 : * March 31, 1998.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Netscape Communications Corporation.
22 : * Portions created by the Initial Developer are Copyright (C) 1998-2011
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 the GNU General Public License Version 2 or later (the "GPL"), or
29 : * 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 ParseNode_h__
42 : #define ParseNode_h__
43 :
44 : #include "mozilla/Attributes.h"
45 :
46 : #include "jsscript.h"
47 :
48 : #include "frontend/ParseMaps.h"
49 : #include "frontend/TokenStream.h"
50 :
51 : namespace js {
52 :
53 : /*
54 : * Parsing builds a tree of nodes that directs code generation. This tree is
55 : * not a concrete syntax tree in all respects (for example, || and && are left
56 : * associative, but (A && B && C) translates into the right-associated tree
57 : * <A && <B && C>> so that code generation can emit a left-associative branch
58 : * around <B && C> when A is false). Nodes are labeled by kind, with a
59 : * secondary JSOp label when needed.
60 : *
61 : * The long comment after this enum block describes the kinds in detail.
62 : */
63 : enum ParseNodeKind {
64 : PNK_SEMI,
65 : PNK_COMMA,
66 : PNK_CONDITIONAL,
67 : PNK_COLON,
68 : PNK_OR,
69 : PNK_AND,
70 : PNK_BITOR,
71 : PNK_BITXOR,
72 : PNK_BITAND,
73 : PNK_POS,
74 : PNK_NEG,
75 : PNK_ADD,
76 : PNK_SUB,
77 : PNK_STAR,
78 : PNK_DIV,
79 : PNK_MOD,
80 : PNK_PREINCREMENT,
81 : PNK_POSTINCREMENT,
82 : PNK_PREDECREMENT,
83 : PNK_POSTDECREMENT,
84 : PNK_DOT,
85 : PNK_LB,
86 : PNK_RB,
87 : PNK_STATEMENTLIST,
88 : PNK_XMLCURLYEXPR,
89 : PNK_RC,
90 : PNK_LP,
91 : PNK_RP,
92 : PNK_NAME,
93 : PNK_NUMBER,
94 : PNK_STRING,
95 : PNK_REGEXP,
96 : PNK_TRUE,
97 : PNK_FALSE,
98 : PNK_NULL,
99 : PNK_THIS,
100 : PNK_FUNCTION,
101 : PNK_IF,
102 : PNK_ELSE,
103 : PNK_SWITCH,
104 : PNK_CASE,
105 : PNK_DEFAULT,
106 : PNK_WHILE,
107 : PNK_DOWHILE,
108 : PNK_FOR,
109 : PNK_BREAK,
110 : PNK_CONTINUE,
111 : PNK_IN,
112 : PNK_VAR,
113 : PNK_CONST,
114 : PNK_WITH,
115 : PNK_RETURN,
116 : PNK_NEW,
117 : PNK_DELETE,
118 : PNK_TRY,
119 : PNK_CATCH,
120 : PNK_CATCHLIST,
121 : PNK_FINALLY,
122 : PNK_THROW,
123 : PNK_INSTANCEOF,
124 : PNK_DEBUGGER,
125 : PNK_DEFXMLNS,
126 : PNK_XMLSTAGO,
127 : PNK_XMLETAGO,
128 : PNK_XMLPTAGC,
129 : PNK_XMLTAGC,
130 : PNK_XMLNAME,
131 : PNK_XMLATTR,
132 : PNK_XMLSPACE,
133 : PNK_XMLTEXT,
134 : PNK_XMLCOMMENT,
135 : PNK_XMLCDATA,
136 : PNK_XMLPI,
137 : PNK_XMLUNARY,
138 : PNK_AT,
139 : PNK_DBLCOLON,
140 : PNK_ANYNAME,
141 : PNK_DBLDOT,
142 : PNK_FILTER,
143 : PNK_XMLELEM,
144 : PNK_XMLLIST,
145 : PNK_YIELD,
146 : PNK_ARRAYCOMP,
147 : PNK_ARRAYPUSH,
148 : PNK_LEXICALSCOPE,
149 : PNK_LET,
150 : PNK_SEQ,
151 : PNK_FORIN,
152 : PNK_FORHEAD,
153 : PNK_ARGSBODY,
154 : PNK_UPVARS,
155 :
156 : /*
157 : * The following parse node kinds occupy contiguous ranges to enable easy
158 : * range-testing.
159 : */
160 :
161 : /* Equality operators. */
162 : PNK_STRICTEQ,
163 : PNK_EQ,
164 : PNK_STRICTNE,
165 : PNK_NE,
166 :
167 : /* Unary operators. */
168 : PNK_TYPEOF,
169 : PNK_VOID,
170 : PNK_NOT,
171 : PNK_BITNOT,
172 :
173 : /* Relational operators (< <= > >=). */
174 : PNK_LT,
175 : PNK_LE,
176 : PNK_GT,
177 : PNK_GE,
178 :
179 : /* Shift operators (<< >> >>>). */
180 : PNK_LSH,
181 : PNK_RSH,
182 : PNK_URSH,
183 :
184 : /* Assignment operators (= += -= etc.). */
185 : PNK_ASSIGN,
186 : PNK_ASSIGNMENT_START = PNK_ASSIGN,
187 : PNK_ADDASSIGN,
188 : PNK_SUBASSIGN,
189 : PNK_BITORASSIGN,
190 : PNK_BITXORASSIGN,
191 : PNK_BITANDASSIGN,
192 : PNK_LSHASSIGN,
193 : PNK_RSHASSIGN,
194 : PNK_URSHASSIGN,
195 : PNK_MULASSIGN,
196 : PNK_DIVASSIGN,
197 : PNK_MODASSIGN,
198 : PNK_ASSIGNMENT_LAST = PNK_MODASSIGN,
199 :
200 : PNK_LIMIT /* domain size */
201 : };
202 :
203 : /*
204 : * Label Variant Members
205 : * ----- ------- -------
206 : * <Definitions>
207 : * PNK_FUNCTION name pn_funbox: ptr to js::FunctionBox holding function
208 : * object containing arg and var properties. We
209 : * create the function object at parse (not emit)
210 : * time to specialize arg and var bytecodes early.
211 : * pn_body: PNK_UPVARS if the function's source body
212 : * depends on outer names,
213 : * PNK_ARGSBODY if formal parameters,
214 : * PNK_STATEMENTLIST node for function body
215 : * statements,
216 : * PNK_RETURN for expression closure, or
217 : * PNK_SEQ for expression closure with
218 : * destructured formal parameters
219 : * pn_cookie: static level and var index for function
220 : * pn_dflags: PND_* definition/use flags (see below)
221 : * pn_blockid: block id number
222 : * PNK_ARGSBODY list list of formal parameters followed by
223 : * PNK_STATEMENTLIST node for function body
224 : * statements as final element
225 : * pn_count: 1 + number of formal parameters
226 : * PNK_UPVARS nameset pn_names: lexical dependencies (js::Definitions)
227 : * defined in enclosing scopes, or ultimately not
228 : * defined (free variables, either global property
229 : * references or reference errors).
230 : * pn_tree: PNK_ARGSBODY or PNK_STATEMENTLIST node
231 : *
232 : * <Statements>
233 : * PNK_STATEMENTLIST list pn_head: list of pn_count statements
234 : * PNK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null.
235 : * In body of a comprehension or desugared generator
236 : * expression, pn_kid2 is PNK_YIELD, PNK_ARRAYPUSH,
237 : * or (if the push was optimized away) empty
238 : * PNK_STATEMENTLIST.
239 : * PNK_SWITCH binary pn_left: discriminant
240 : * pn_right: list of PNK_CASE nodes, with at most one
241 : * PNK_DEFAULT node, or if there are let bindings
242 : * in the top level of the switch body's cases, a
243 : * PNK_LEXICALSCOPE node that contains the list of
244 : * PNK_CASE nodes.
245 : * PNK_CASE, binary pn_left: case expr
246 : * pn_right: PNK_STATEMENTLIST node for this case's
247 : * statements
248 : * PNK_DEFAULT binary pn_left: null
249 : * pn_right: PNK_STATEMENTLIST node for this default's
250 : * statements
251 : * pn_val: constant value if lookup or table switch
252 : * PNK_WHILE binary pn_left: cond, pn_right: body
253 : * PNK_DOWHILE binary pn_left: body, pn_right: cond
254 : * PNK_FOR binary pn_left: either PNK_FORIN (for-in statement) or
255 : * PNK_FORHEAD (for(;;) statement)
256 : * pn_right: body
257 : * PNK_FORIN ternary pn_kid1: PNK_VAR to left of 'in', or NULL
258 : * its pn_xflags may have PNX_POPVAR
259 : * and PNX_FORINVAR bits set
260 : * pn_kid2: PNK_NAME or destructuring expr
261 : * to left of 'in'; if pn_kid1, then this
262 : * is a clone of pn_kid1->pn_head
263 : * pn_kid3: object expr to right of 'in'
264 : * PNK_FORHEAD ternary pn_kid1: init expr before first ';' or NULL
265 : * pn_kid2: cond expr before second ';' or NULL
266 : * pn_kid3: update expr after second ';' or NULL
267 : * PNK_THROW unary pn_op: JSOP_THROW, pn_kid: exception
268 : * PNK_TRY ternary pn_kid1: try block
269 : * pn_kid2: null or PNK_CATCHLIST list of
270 : * PNK_LEXICALSCOPE nodes, each with pn_expr pointing
271 : * to a PNK_CATCH node
272 : * pn_kid3: null or finally block
273 : * PNK_CATCH ternary pn_kid1: PNK_NAME, PNK_RB, or PNK_RC catch var node
274 : * (PNK_RB or PNK_RC if destructuring)
275 : * pn_kid2: null or the catch guard expression
276 : * pn_kid3: catch block statements
277 : * PNK_BREAK name pn_atom: label or null
278 : * PNK_CONTINUE name pn_atom: label or null
279 : * PNK_WITH binary pn_left: head expr, pn_right: body
280 : * PNK_VAR, list pn_head: list of PNK_NAME or PNK_ASSIGN nodes
281 : * PNK_CONST each name node has either
282 : * pn_used: false
283 : * pn_atom: variable name
284 : * pn_expr: initializer or null
285 : * or
286 : * pn_used: true
287 : * pn_atom: variable name
288 : * pn_lexdef: def node
289 : * each assignment node has
290 : * pn_left: PNK_NAME with pn_used true and
291 : * pn_lexdef (NOT pn_expr) set
292 : * pn_right: initializer
293 : * PNK_RETURN unary pn_kid: return expr or null
294 : * PNK_SEMI unary pn_kid: expr or null statement
295 : * pn_prologue: true if Directive Prologue member
296 : * in original source, not introduced via
297 : * constant folding or other tree rewriting
298 : * PNK_COLON name pn_atom: label, pn_expr: labeled statement
299 : *
300 : * <Expressions>
301 : * All left-associated binary trees of the same type are optimized into lists
302 : * to avoid recursion when processing expression chains.
303 : * PNK_COMMA list pn_head: list of pn_count comma-separated exprs
304 : * PNK_ASSIGN binary pn_left: lvalue, pn_right: rvalue
305 : * PNK_ADDASSIGN, binary pn_left: lvalue, pn_right: rvalue
306 : * PNK_SUBASSIGN, pn_op: JSOP_ADD for +=, etc.
307 : * PNK_BITORASSIGN,
308 : * PNK_BITXORASSIGN,
309 : * PNK_BITANDASSIGN,
310 : * PNK_LSHASSIGN,
311 : * PNK_RSHASSIGN,
312 : * PNK_URSHASSIGN,
313 : * PNK_MULASSIGN,
314 : * PNK_DIVASSIGN,
315 : * PNK_MODASSIGN
316 : * PNK_CONDITIONAL ternary (cond ? trueExpr : falseExpr)
317 : * pn_kid1: cond, pn_kid2: then, pn_kid3: else
318 : * PNK_OR binary pn_left: first in || chain, pn_right: rest of chain
319 : * PNK_AND binary pn_left: first in && chain, pn_right: rest of chain
320 : * PNK_BITOR binary pn_left: left-assoc | expr, pn_right: ^ expr
321 : * PNK_BITXOR binary pn_left: left-assoc ^ expr, pn_right: & expr
322 : * PNK_BITAND binary pn_left: left-assoc & expr, pn_right: EQ expr
323 : *
324 : * PNK_EQ, binary pn_left: left-assoc EQ expr, pn_right: REL expr
325 : * PNK_NE,
326 : * PNK_STRICTEQ,
327 : * PNK_STRICTNE
328 : * PNK_LT, binary pn_left: left-assoc REL expr, pn_right: SH expr
329 : * PNK_LE,
330 : * PNK_GT,
331 : * PNK_GE
332 : * PNK_LSH, binary pn_left: left-assoc SH expr, pn_right: ADD expr
333 : * PNK_RSH,
334 : * PNK_URSH
335 : * PNK_ADD binary pn_left: left-assoc ADD expr, pn_right: MUL expr
336 : * pn_xflags: if a left-associated binary PNK_ADD
337 : * tree has been flattened into a list (see above
338 : * under <Expressions>), pn_xflags will contain
339 : * PNX_STRCAT if at least one list element is a
340 : * string literal (PNK_STRING); if such a list has
341 : * any non-string, non-number term, pn_xflags will
342 : * contain PNX_CANTFOLD.
343 : * PNK_SUB binary pn_left: left-assoc SH expr, pn_right: ADD expr
344 : * PNK_STAR, binary pn_left: left-assoc MUL expr, pn_right: UNARY expr
345 : * PNK_DIV, pn_op: JSOP_MUL, JSOP_DIV, JSOP_MOD
346 : * PNK_MOD
347 : * PNK_POS, unary pn_kid: UNARY expr
348 : * PNK_NEG
349 : * PNK_TYPEOF, unary pn_kid: UNARY expr
350 : * PNK_VOID,
351 : * PNK_NOT,
352 : * PNK_BITNOT
353 : * PNK_PREINCREMENT, unary pn_kid: MEMBER expr
354 : * PNK_POSTINCREMENT,
355 : * PNK_PREDECREMENT,
356 : * PNK_POSTDECREMENT
357 : * PNK_NEW list pn_head: list of ctor, arg1, arg2, ... argN
358 : * pn_count: 1 + N (where N is number of args)
359 : * ctor is a MEMBER expr
360 : * PNK_DELETE unary pn_kid: MEMBER expr
361 : * PNK_DOT, name pn_expr: MEMBER expr to left of .
362 : * PNK_DBLDOT pn_atom: name to right of .
363 : * PNK_LB binary pn_left: MEMBER expr to left of [
364 : * pn_right: expr between [ and ]
365 : * PNK_LP list pn_head: list of call, arg1, arg2, ... argN
366 : * pn_count: 1 + N (where N is number of args)
367 : * call is a MEMBER expr naming a callable object
368 : * PNK_RB list pn_head: list of pn_count array element exprs
369 : * [,,] holes are represented by PNK_COMMA nodes
370 : * pn_xflags: PN_ENDCOMMA if extra comma at end
371 : * PNK_RC list pn_head: list of pn_count binary PNK_COLON nodes
372 : * PNK_COLON binary key-value pair in object initializer or
373 : * destructuring lhs
374 : * pn_left: property id, pn_right: value
375 : * var {x} = object destructuring shorthand shares
376 : * PN_NAME node for x on left and right of PNK_COLON
377 : * node in PNK_RC's list, has PNX_DESTRUCT flag
378 : * PNK_NAME, name pn_atom: name, string, or object atom
379 : * PNK_STRING, pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT, or
380 : * JSOP_REGEXP
381 : * PNK_REGEXP If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR
382 : * with pn_cookie telling (staticLevel, slot) (see
383 : * jsscript.h's UPVAR macros) and pn_dflags telling
384 : * const-ness and static analysis results
385 : * PNK_NAME name If pn_used, PNK_NAME uses the lexdef member instead
386 : * of the expr member it overlays
387 : * PNK_NUMBER dval pn_dval: double value of numeric literal
388 : * PNK_TRUE, nullary pn_op: JSOp bytecode
389 : * PNK_FALSE,
390 : * PNK_NULL,
391 : * PNK_THIS
392 : *
393 : * <E4X node descriptions>
394 : * PNK_XMLUNARY unary pn_kid: PNK_AT, PNK_ANYNAME, or PNK_DBLCOLON node
395 : * pn_op: JSOP_XMLNAME, JSOP_BINDXMLNAME, or
396 : * JSOP_SETXMLNAME
397 : * PNK_DEFXMLNS name pn_kid: namespace expr
398 : * PNK_FILTER binary pn_left: container expr, pn_right: filter expr
399 : * PNK_DBLDOT binary pn_left: container expr, pn_right: selector expr
400 : * PNK_ANYNAME nullary pn_op: JSOP_ANYNAME
401 : * pn_atom: cx->runtime->atomState.starAtom
402 : * PNK_AT unary pn_op: JSOP_TOATTRNAME; pn_kid attribute id/expr
403 : * PNK_DBLCOLON binary pn_op: JSOP_QNAME
404 : * pn_left: PNK_ANYNAME or PNK_NAME node
405 : * pn_right: PNK_STRING "*" node, or expr within []
406 : * name pn_op: JSOP_QNAMECONST
407 : * pn_expr: PNK_ANYNAME or PNK_NAME left operand
408 : * pn_atom: name on right of ::
409 : * PNK_XMLELEM list XML element node
410 : * pn_head: start tag, content1, ... contentN, end tag
411 : * pn_count: 2 + N where N is number of content nodes
412 : * N may be > x.length() if {expr} embedded
413 : * After constant folding, these contents may be
414 : * concatenated into string nodes.
415 : * PNK_XMLLIST list XML list node
416 : * pn_head: content1, ... contentN
417 : * PNK_XMLSTAGO, list XML start, end, and point tag contents
418 : * PNK_XMLETAGO, pn_head: tag name or {expr}, ... XML attrs ...
419 : * PNK_XMLPTAGC
420 : * PNK_XMLNAME nullary pn_atom: XML name, with no {expr} embedded
421 : * PNK_XMLNAME list pn_head: tag name or {expr}, ... name or {expr}
422 : * PNK_XMLATTR, nullary pn_atom: attribute value string; pn_op: JSOP_STRING
423 : * PNK_XMLCDATA,
424 : * PNK_XMLCOMMENT
425 : * PNK_XMLPI nullary pn_pitarget: XML processing instruction target
426 : * pn_pidata: XML PI data, or null if no data
427 : * PNK_XMLTEXT nullary pn_atom: marked-up text, or null if empty string
428 : * PNK_XMLCURLYEXPR unary {expr} in XML tag or content; pn_kid is expr
429 : *
430 : * So an XML tag with no {expr} and three attributes is a list with the form:
431 : *
432 : * (tagname attrname1 attrvalue1 attrname2 attrvalue2 attrname2 attrvalue3)
433 : *
434 : * An XML tag with embedded expressions like so:
435 : *
436 : * <name1{expr1} name2{expr2}name3={expr3}>
437 : *
438 : * would have the form:
439 : *
440 : * ((name1 {expr1}) (name2 {expr2} name3) {expr3})
441 : *
442 : * where () bracket a list with elements separated by spaces, and {expr} is a
443 : * PNK_XMLCURLYEXPR unary node with expr as its kid.
444 : *
445 : * Thus, the attribute name/value pairs occupy successive odd and even list
446 : * locations, where pn_head is the PNK_XMLNAME node at list location 0. The
447 : * parser builds the same sort of structures for elements:
448 : *
449 : * <a x={x}>Hi there!<b y={y}>How are you?</b><answer>{x + y}</answer></a>
450 : *
451 : * translates to:
452 : *
453 : * ((a x {x}) 'Hi there!' ((b y {y}) 'How are you?') ((answer) {x + y}))
454 : *
455 : * <Non-E4X node descriptions, continued>
456 : *
457 : * Label Variant Members
458 : * ----- ------- -------
459 : * PNK_LEXICALSCOPE name pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR
460 : * pn_objbox: block object in ObjectBox holder
461 : * pn_expr: block body
462 : * PNK_ARRAYCOMP list pn_count: 1
463 : * pn_head: list of 1 element, which is block
464 : * enclosing for loop(s) and optionally
465 : * if-guarded PNK_ARRAYPUSH
466 : * PNK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
467 : * pn_kid: array comprehension expression
468 : */
469 : enum ParseNodeArity {
470 : PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */
471 : PN_UNARY, /* one kid, plus a couple of scalars */
472 : PN_BINARY, /* two kids, plus a couple of scalars */
473 : PN_TERNARY, /* three kids */
474 : PN_FUNC, /* function definition node */
475 : PN_LIST, /* generic singly linked list */
476 : PN_NAME, /* name use or definition node */
477 : PN_NAMESET /* AtomDefnMapPtr + ParseNode ptr */
478 : };
479 :
480 : struct Definition;
481 :
482 : class LoopControlStatement;
483 : class BreakStatement;
484 : class ContinueStatement;
485 : class XMLProcessingInstruction;
486 : class ConditionalExpression;
487 : class PropertyAccess;
488 :
489 : struct ParseNode {
490 : private:
491 : uint32_t pn_type : 16, /* PNK_* type */
492 : pn_op : 8, /* see JSOp enum and jsopcode.tbl */
493 : pn_arity : 5, /* see ParseNodeArity enum */
494 : pn_parens : 1, /* this expr was enclosed in parens */
495 : pn_used : 1, /* name node is on a use-chain */
496 : pn_defn : 1; /* this node is a Definition */
497 :
498 : ParseNode(const ParseNode &other) MOZ_DELETE;
499 : void operator=(const ParseNode &other) MOZ_DELETE;
500 :
501 : public:
502 : ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity)
503 : : pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
504 : pn_offset(0), pn_next(NULL), pn_link(NULL)
505 : {
506 : JS_ASSERT(kind < PNK_LIMIT);
507 : pn_pos.begin.index = 0;
508 : pn_pos.begin.lineno = 0;
509 : pn_pos.end.index = 0;
510 : pn_pos.end.lineno = 0;
511 : memset(&pn_u, 0, sizeof pn_u);
512 : }
513 :
514 80620402 : ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity, const TokenPos &pos)
515 : : pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
516 80620402 : pn_pos(pos), pn_offset(0), pn_next(NULL), pn_link(NULL)
517 : {
518 80620402 : JS_ASSERT(kind < PNK_LIMIT);
519 80620402 : memset(&pn_u, 0, sizeof pn_u);
520 80620402 : }
521 :
522 234425073 : JSOp getOp() const { return JSOp(pn_op); }
523 58894620 : void setOp(JSOp op) { pn_op = op; }
524 154255710 : bool isOp(JSOp op) const { return getOp() == op; }
525 :
526 500237061 : ParseNodeKind getKind() const {
527 500237061 : JS_ASSERT(pn_type < PNK_LIMIT);
528 500237061 : return ParseNodeKind(pn_type);
529 : }
530 181115 : void setKind(ParseNodeKind kind) {
531 181115 : JS_ASSERT(kind < PNK_LIMIT);
532 181115 : pn_type = kind;
533 181115 : }
534 258435765 : bool isKind(ParseNodeKind kind) const { return getKind() == kind; }
535 :
536 184906693 : ParseNodeArity getArity() const { return ParseNodeArity(pn_arity); }
537 58665886 : bool isArity(ParseNodeArity a) const { return getArity() == a; }
538 382378 : void setArity(ParseNodeArity a) { pn_arity = a; }
539 :
540 34192731 : bool isXMLNameOp() const {
541 34192731 : ParseNodeKind kind = getKind();
542 34192731 : return kind == PNK_ANYNAME || kind == PNK_AT || kind == PNK_DBLCOLON;
543 : }
544 9366769 : bool isAssignment() const {
545 9366769 : ParseNodeKind kind = getKind();
546 9366769 : return PNK_ASSIGNMENT_START <= kind && kind <= PNK_ASSIGNMENT_LAST;
547 : }
548 :
549 0 : bool isXMLPropertyIdentifier() const {
550 0 : ParseNodeKind kind = getKind();
551 0 : return kind == PNK_ANYNAME || kind == PNK_AT || kind == PNK_DBLCOLON;
552 : }
553 :
554 342151 : bool isXMLItem() const {
555 342151 : ParseNodeKind kind = getKind();
556 : return kind == PNK_XMLCOMMENT || kind == PNK_XMLCDATA || kind == PNK_XMLPI ||
557 342151 : kind == PNK_XMLELEM || kind == PNK_XMLLIST;
558 : }
559 :
560 : /* Boolean attributes. */
561 3397148 : bool isInParens() const { return pn_parens; }
562 442827 : void setInParens(bool enabled) { pn_parens = enabled; }
563 122152901 : bool isUsed() const { return pn_used; }
564 16387099 : void setUsed(bool enabled) { pn_used = enabled; }
565 129806665 : bool isDefn() const { return pn_defn; }
566 8678543 : void setDefn(bool enabled) { pn_defn = enabled; }
567 :
568 : TokenPos pn_pos; /* two 16-bit pairs here, for 64 bits */
569 : int32_t pn_offset; /* first generated bytecode offset */
570 : ParseNode *pn_next; /* intrinsic link in parent PN_LIST */
571 : ParseNode *pn_link; /* def/use link (alignment freebie);
572 : also links FunctionBox::methods
573 : lists of would-be |this| methods */
574 :
575 : union {
576 : struct { /* list of next-linked nodes */
577 : ParseNode *head; /* first node in list */
578 : ParseNode **tail; /* ptr to ptr to last node in list */
579 : uint32_t count; /* number of nodes in list */
580 : uint32_t xflags:12, /* extra flags, see below */
581 : blockid:20; /* see name variant below */
582 : } list;
583 : struct { /* ternary: if, for(;;), ?: */
584 : ParseNode *kid1; /* condition, discriminant, etc. */
585 : ParseNode *kid2; /* then-part, case list, etc. */
586 : ParseNode *kid3; /* else-part, default case, etc. */
587 : } ternary;
588 : struct { /* two kids if binary */
589 : ParseNode *left;
590 : ParseNode *right;
591 : Value *pval; /* switch case value */
592 : unsigned iflags; /* JSITER_* flags for PNK_FOR node */
593 : } binary;
594 : struct { /* one kid if unary */
595 : ParseNode *kid;
596 : JSBool hidden; /* hidden genexp-induced JSOP_YIELD
597 : or directive prologue member (as
598 : pn_prologue) */
599 : } unary;
600 : struct { /* name, labeled statement, etc. */
601 : union {
602 : JSAtom *atom; /* lexical name or label atom */
603 : FunctionBox *funbox; /* function object */
604 : ObjectBox *objbox; /* block or regexp object */
605 : };
606 : union {
607 : ParseNode *expr; /* function body, var initializer, or
608 : base object of PNK_DOT */
609 : Definition *lexdef; /* lexical definition for this use */
610 : };
611 : UpvarCookie cookie; /* upvar cookie with absolute frame
612 : level (not relative skip), possibly
613 : in current frame */
614 : uint32_t dflags:12, /* definition/use flags, see below */
615 : blockid:20; /* block number, for subset dominance
616 : computation */
617 : } name;
618 : struct { /* lexical dependencies + sub-tree */
619 : AtomDefnMapPtr defnMap;
620 : ParseNode *tree; /* sub-tree containing name uses */
621 : } nameset;
622 : double dval; /* aligned numeric literal value */
623 : class {
624 : friend class LoopControlStatement;
625 : PropertyName *label; /* target of break/continue statement */
626 : } loopControl;
627 : class { /* E4X <?target data?> XML PI */
628 : friend class XMLProcessingInstruction;
629 : PropertyName *target; /* non-empty */
630 : JSAtom *data; /* may be empty, never null */
631 : } xmlpi;
632 : } pn_u;
633 :
634 : #define pn_funbox pn_u.name.funbox
635 : #define pn_body pn_u.name.expr
636 : #define pn_cookie pn_u.name.cookie
637 : #define pn_dflags pn_u.name.dflags
638 : #define pn_blockid pn_u.name.blockid
639 : #define pn_index pn_u.name.blockid /* reuse as object table index */
640 : #define pn_head pn_u.list.head
641 : #define pn_tail pn_u.list.tail
642 : #define pn_count pn_u.list.count
643 : #define pn_xflags pn_u.list.xflags
644 : #define pn_kid1 pn_u.ternary.kid1
645 : #define pn_kid2 pn_u.ternary.kid2
646 : #define pn_kid3 pn_u.ternary.kid3
647 : #define pn_left pn_u.binary.left
648 : #define pn_right pn_u.binary.right
649 : #define pn_pval pn_u.binary.pval
650 : #define pn_iflags pn_u.binary.iflags
651 : #define pn_kid pn_u.unary.kid
652 : #define pn_hidden pn_u.unary.hidden
653 : #define pn_prologue pn_u.unary.hidden
654 : #define pn_atom pn_u.name.atom
655 : #define pn_objbox pn_u.name.objbox
656 : #define pn_expr pn_u.name.expr
657 : #define pn_lexdef pn_u.name.lexdef
658 : #define pn_names pn_u.nameset.defnMap
659 : #define pn_tree pn_u.nameset.tree
660 : #define pn_dval pn_u.dval
661 :
662 : protected:
663 : void init(TokenKind type, JSOp op, ParseNodeArity arity) {
664 : pn_type = type;
665 : pn_op = op;
666 : pn_arity = arity;
667 : pn_parens = false;
668 : JS_ASSERT(!pn_used);
669 : JS_ASSERT(!pn_defn);
670 : pn_names.init();
671 : pn_next = pn_link = NULL;
672 : }
673 :
674 : static ParseNode *create(ParseNodeKind kind, ParseNodeArity arity, TreeContext *tc);
675 :
676 : public:
677 : /*
678 : * Append right to left, forming a list node. |left| must have the given
679 : * kind and op, and op must be left-associative.
680 : */
681 : static ParseNode *
682 : append(ParseNodeKind tt, JSOp op, ParseNode *left, ParseNode *right);
683 :
684 : /*
685 : * Either append right to left, if left meets the conditions necessary to
686 : * append (see append), or form a binary node whose children are right and
687 : * left.
688 : */
689 : static ParseNode *
690 : newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
691 : TreeContext *tc);
692 :
693 : /*
694 : * The pn_expr and lexdef members are arms of an unsafe union. Unless you
695 : * know exactly what you're doing, use only the following methods to access
696 : * them. For less overhead and assertions for protection, use pn->expr()
697 : * and pn->lexdef(). Otherwise, use pn->maybeExpr() and pn->maybeLexDef().
698 : */
699 13813061 : ParseNode *expr() const {
700 13813061 : JS_ASSERT(!pn_used);
701 13813061 : JS_ASSERT(pn_arity == PN_NAME || pn_arity == PN_FUNC);
702 13813061 : return pn_expr;
703 : }
704 :
705 6931324 : Definition *lexdef() const {
706 6931324 : JS_ASSERT(pn_used || isDeoptimized());
707 6931324 : JS_ASSERT(pn_arity == PN_NAME);
708 6931324 : return pn_lexdef;
709 : }
710 :
711 14693936 : ParseNode *maybeExpr() { return pn_used ? NULL : expr(); }
712 : Definition *maybeLexDef() { return pn_used ? lexdef() : NULL; }
713 :
714 : /* PN_FUNC and PN_NAME pn_dflags bits. */
715 : #define PND_LET 0x01 /* let (block-scoped) binding */
716 : #define PND_CONST 0x02 /* const binding (orthogonal to let) */
717 : #define PND_INITIALIZED 0x04 /* initialized declaration */
718 : #define PND_ASSIGNED 0x08 /* set if ever LHS of assignment */
719 : #define PND_TOPLEVEL 0x10 /* see isTopLevel() below */
720 : #define PND_BLOCKCHILD 0x20 /* use or def is direct block child */
721 : #define PND_GVAR 0x40 /* gvar binding, can't close over
722 : because it could be deleted */
723 : #define PND_PLACEHOLDER 0x80 /* placeholder definition for lexdep */
724 : #define PND_FUNARG 0x100 /* downward or upward funarg usage */
725 : #define PND_BOUND 0x200 /* bound to a stack or global slot */
726 : #define PND_DEOPTIMIZED 0x400 /* former pn_used name node, pn_lexdef
727 : still valid, but this use no longer
728 : optimizable via an upvar opcode */
729 : #define PND_CLOSED 0x800 /* variable is closed over */
730 :
731 : /* Flags to propagate from uses to definition. */
732 : #define PND_USE2DEF_FLAGS (PND_ASSIGNED | PND_FUNARG | PND_CLOSED)
733 :
734 : /* PN_LIST pn_xflags bits. */
735 : #define PNX_STRCAT 0x01 /* PNK_ADD list has string term */
736 : #define PNX_CANTFOLD 0x02 /* PNK_ADD list has unfoldable term */
737 : #define PNX_POPVAR 0x04 /* PNK_VAR or PNK_CONST last result
738 : needs popping */
739 : #define PNX_FORINVAR 0x08 /* PNK_VAR is left kid of PNK_FORIN node
740 : which is left kid of PNK_FOR */
741 : #define PNX_ENDCOMMA 0x10 /* array literal has comma at end */
742 : #define PNX_XMLROOT 0x20 /* top-most node in XML literal tree */
743 : #define PNX_GROUPINIT 0x40 /* var [a, b] = [c, d]; unit list */
744 : #define PNX_NEEDBRACES 0x80 /* braces necessary due to closure */
745 : #define PNX_FUNCDEFS 0x100 /* contains top-level function statements */
746 : #define PNX_SETCALL 0x100 /* call expression in lvalue context */
747 : #define PNX_DESTRUCT 0x200 /* destructuring special cases:
748 : 1. shorthand syntax used, at present
749 : object destructuring ({x,y}) only;
750 : 2. code evaluating destructuring
751 : arguments occurs before function
752 : body */
753 : #define PNX_HOLEY 0x400 /* array initialiser has holes */
754 : #define PNX_NONCONST 0x800 /* initialiser has non-constants */
755 :
756 1492306 : unsigned frameLevel() const {
757 1492306 : JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
758 1492306 : return pn_cookie.level();
759 : }
760 :
761 1496802 : unsigned frameSlot() const {
762 1496802 : JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
763 1496802 : return pn_cookie.slot();
764 : }
765 :
766 : inline bool test(unsigned flag) const;
767 :
768 4995124 : bool isLet() const { return test(PND_LET); }
769 10241846 : bool isConst() const { return test(PND_CONST); }
770 143902 : bool isInitialized() const { return test(PND_INITIALIZED); }
771 148772 : bool isBlockChild() const { return test(PND_BLOCKCHILD); }
772 2576378 : bool isPlaceholder() const { return test(PND_PLACEHOLDER); }
773 19767494 : bool isDeoptimized() const { return test(PND_DEOPTIMIZED); }
774 3342287 : bool isAssigned() const { return test(PND_ASSIGNED); }
775 2182299 : bool isFunArg() const { return test(PND_FUNARG); }
776 2097427 : bool isClosed() const { return test(PND_CLOSED); }
777 :
778 : /*
779 : * True iff this definition creates a top-level binding in the overall
780 : * script being compiled -- that is, it affects the whole program's
781 : * bindings, not bindings for a specific function (unless this definition
782 : * is in the outermost scope in eval code, executed within a function) or
783 : * the properties of a specific object (through the with statement).
784 : *
785 : * NB: Function sub-statements found in overall program code and not nested
786 : * within other functions are not currently top level, even though (if
787 : * executed) they do create top-level bindings; there is no particular
788 : * rationale for this behavior.
789 : */
790 9 : bool isTopLevel() const { return test(PND_TOPLEVEL); }
791 :
792 : /* Defined below, see after struct Definition. */
793 : void setFunArg();
794 :
795 : void become(ParseNode *pn2);
796 : void clear();
797 :
798 : /* True if pn is a parsenode representing a literal constant. */
799 : bool isLiteral() const {
800 : return isKind(PNK_NUMBER) ||
801 : isKind(PNK_STRING) ||
802 : isKind(PNK_TRUE) ||
803 : isKind(PNK_FALSE) ||
804 : isKind(PNK_NULL);
805 : }
806 :
807 : /*
808 : * True if this statement node could be a member of a Directive Prologue: an
809 : * expression statement consisting of a single string literal.
810 : *
811 : * This considers only the node and its children, not its context. After
812 : * parsing, check the node's pn_prologue flag to see if it is indeed part of
813 : * a directive prologue.
814 : *
815 : * Note that a Directive Prologue can contain statements that cannot
816 : * themselves be directives (string literals that include escape sequences
817 : * or escaped newlines, say). This member function returns true for such
818 : * nodes; we use it to determine the extent of the prologue.
819 : * isEscapeFreeStringLiteral, below, checks whether the node itself could be
820 : * a directive.
821 : */
822 1025473 : bool isStringExprStatement() const {
823 1025473 : if (getKind() == PNK_SEMI) {
824 499070 : JS_ASSERT(pn_arity == PN_UNARY);
825 499070 : ParseNode *kid = pn_kid;
826 499070 : return kid && kid->getKind() == PNK_STRING && !kid->pn_parens;
827 : }
828 526403 : return false;
829 : }
830 :
831 : /*
832 : * Return true if this node, known to be an unparenthesized string literal,
833 : * could be the string of a directive in a Directive Prologue. Directive
834 : * strings never contain escape sequences or line continuations.
835 : */
836 3098 : bool isEscapeFreeStringLiteral() const {
837 3098 : JS_ASSERT(isKind(PNK_STRING) && !pn_parens);
838 :
839 : /*
840 : * If the string's length in the source code is its length as a value,
841 : * accounting for the quotes, then it must not contain any escape
842 : * sequences or line continuations.
843 : */
844 3098 : JSString *str = pn_atom;
845 : return (pn_pos.begin.lineno == pn_pos.end.lineno &&
846 3098 : pn_pos.begin.index + str->length() + 2 == pn_pos.end.index);
847 : }
848 :
849 : /* Return true if this node appears in a Directive Prologue. */
850 3462 : bool isDirectivePrologueMember() const { return pn_prologue; }
851 :
852 : #ifdef JS_HAS_DESTRUCTURING
853 : /* Return true if this represents a hole in an array literal. */
854 36289 : bool isArrayHole() const { return isKind(PNK_COMMA) && isArity(PN_NULLARY); }
855 : #endif
856 :
857 : #ifdef JS_HAS_GENERATOR_EXPRS
858 : /*
859 : * True if this node is a desugared generator expression.
860 : */
861 810 : bool isGeneratorExpr() const {
862 810 : if (getKind() == PNK_LP) {
863 810 : ParseNode *callee = this->pn_head;
864 810 : if (callee->getKind() == PNK_FUNCTION) {
865 108 : ParseNode *body = (callee->pn_body->getKind() == PNK_UPVARS)
866 : ? callee->pn_body->pn_tree
867 108 : : callee->pn_body;
868 108 : if (body->getKind() == PNK_LEXICALSCOPE)
869 72 : return true;
870 : }
871 : }
872 738 : return false;
873 : }
874 :
875 36 : ParseNode *generatorExpr() const {
876 36 : JS_ASSERT(isGeneratorExpr());
877 36 : ParseNode *callee = this->pn_head;
878 36 : ParseNode *body = callee->pn_body->getKind() == PNK_UPVARS
879 : ? callee->pn_body->pn_tree
880 36 : : callee->pn_body;
881 36 : JS_ASSERT(body->getKind() == PNK_LEXICALSCOPE);
882 36 : return body->pn_expr;
883 : }
884 : #endif
885 :
886 : /*
887 : * Compute a pointer to the last element in a singly-linked list. NB: list
888 : * must be non-empty for correct PN_LAST usage -- this is asserted!
889 : */
890 2228830 : ParseNode *last() const {
891 2228830 : JS_ASSERT(pn_arity == PN_LIST);
892 2228830 : JS_ASSERT(pn_count != 0);
893 2228830 : return (ParseNode *)(uintptr_t(pn_tail) - offsetof(ParseNode, pn_next));
894 : }
895 :
896 5100349 : void makeEmpty() {
897 5100349 : JS_ASSERT(pn_arity == PN_LIST);
898 5100349 : pn_head = NULL;
899 5100349 : pn_tail = &pn_head;
900 5100349 : pn_count = 0;
901 5100349 : pn_xflags = 0;
902 5100349 : pn_blockid = 0;
903 5100349 : }
904 :
905 3555989 : void initList(ParseNode *pn) {
906 3555989 : JS_ASSERT(pn_arity == PN_LIST);
907 3555989 : pn_head = pn;
908 3555989 : pn_tail = &pn->pn_next;
909 3555989 : pn_count = 1;
910 3555989 : pn_xflags = 0;
911 3555989 : pn_blockid = 0;
912 3555989 : }
913 :
914 25479883 : void append(ParseNode *pn) {
915 25479883 : JS_ASSERT(pn_arity == PN_LIST);
916 25479883 : *pn_tail = pn;
917 25479883 : pn_tail = &pn->pn_next;
918 25479883 : pn_count++;
919 25479883 : }
920 :
921 : bool getConstantValue(JSContext *cx, bool strictChecks, Value *vp);
922 : inline bool isConstant();
923 :
924 : /* Casting operations. */
925 : inline BreakStatement &asBreakStatement();
926 : inline ContinueStatement &asContinueStatement();
927 : #if JS_HAS_XML_SUPPORT
928 : inline XMLProcessingInstruction &asXMLProcessingInstruction();
929 : #endif
930 : inline ConditionalExpression &asConditionalExpression();
931 : inline PropertyAccess &asPropertyAccess();
932 :
933 : #ifdef DEBUG
934 : inline void dump(int indent);
935 : #endif
936 : };
937 :
938 : struct NullaryNode : public ParseNode {
939 17236871 : static inline NullaryNode *create(ParseNodeKind kind, TreeContext *tc) {
940 17236871 : return (NullaryNode *)ParseNode::create(kind, PN_NULLARY, tc);
941 : }
942 :
943 : #ifdef DEBUG
944 : inline void dump();
945 : #endif
946 : };
947 :
948 : struct UnaryNode : public ParseNode {
949 490906 : UnaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *kid)
950 490906 : : ParseNode(kind, op, PN_UNARY, pos)
951 : {
952 490906 : pn_kid = kid;
953 490906 : }
954 :
955 9055827 : static inline UnaryNode *create(ParseNodeKind kind, TreeContext *tc) {
956 9055827 : return (UnaryNode *)ParseNode::create(kind, PN_UNARY, tc);
957 : }
958 :
959 : #ifdef DEBUG
960 : inline void dump(int indent);
961 : #endif
962 : };
963 :
964 : struct BinaryNode : public ParseNode {
965 909682 : BinaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *left, ParseNode *right)
966 909682 : : ParseNode(kind, op, PN_BINARY, pos)
967 : {
968 909682 : pn_left = left;
969 909682 : pn_right = right;
970 909682 : }
971 :
972 4416556 : BinaryNode(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right)
973 4416556 : : ParseNode(kind, op, PN_BINARY, TokenPos::box(left->pn_pos, right->pn_pos))
974 : {
975 4416556 : pn_left = left;
976 4416556 : pn_right = right;
977 4416556 : }
978 :
979 292888 : static inline BinaryNode *create(ParseNodeKind kind, TreeContext *tc) {
980 292888 : return (BinaryNode *)ParseNode::create(kind, PN_BINARY, tc);
981 : }
982 :
983 : #ifdef DEBUG
984 : inline void dump(int indent);
985 : #endif
986 : };
987 :
988 : struct TernaryNode : public ParseNode {
989 12963 : TernaryNode(ParseNodeKind kind, JSOp op, ParseNode *kid1, ParseNode *kid2, ParseNode *kid3)
990 : : ParseNode(kind, op, PN_TERNARY,
991 : TokenPos::make((kid1 ? kid1 : kid2 ? kid2 : kid3)->pn_pos.begin,
992 12963 : (kid3 ? kid3 : kid2 ? kid2 : kid1)->pn_pos.end))
993 : {
994 12963 : pn_kid1 = kid1;
995 12963 : pn_kid2 = kid2;
996 12963 : pn_kid3 = kid3;
997 12963 : }
998 :
999 1526151 : static inline TernaryNode *create(ParseNodeKind kind, TreeContext *tc) {
1000 1526151 : return (TernaryNode *)ParseNode::create(kind, PN_TERNARY, tc);
1001 : }
1002 :
1003 : #ifdef DEBUG
1004 : inline void dump(int indent);
1005 : #endif
1006 : };
1007 :
1008 : struct ListNode : public ParseNode {
1009 8436946 : static inline ListNode *create(ParseNodeKind kind, TreeContext *tc) {
1010 8436946 : return (ListNode *)ParseNode::create(kind, PN_LIST, tc);
1011 : }
1012 :
1013 : #ifdef DEBUG
1014 : inline void dump(int indent);
1015 : #endif
1016 : };
1017 :
1018 : struct FunctionNode : public ParseNode {
1019 991296 : static inline FunctionNode *create(ParseNodeKind kind, TreeContext *tc) {
1020 991296 : return (FunctionNode *)ParseNode::create(kind, PN_FUNC, tc);
1021 : }
1022 :
1023 : #ifdef DEBUG
1024 : inline void dump(int indent);
1025 : #endif
1026 : };
1027 :
1028 : struct NameNode : public ParseNode {
1029 : static NameNode *create(ParseNodeKind kind, JSAtom *atom, TreeContext *tc);
1030 :
1031 : inline void initCommon(TreeContext *tc);
1032 :
1033 : #ifdef DEBUG
1034 : inline void dump(int indent);
1035 : #endif
1036 : };
1037 :
1038 : struct NameSetNode : public ParseNode {
1039 811750 : static inline NameSetNode *create(ParseNodeKind kind, TreeContext *tc) {
1040 811750 : return (NameSetNode *)ParseNode::create(kind, PN_NAMESET, tc);
1041 : }
1042 : };
1043 :
1044 : struct LexicalScopeNode : public ParseNode {
1045 449094 : static inline LexicalScopeNode *create(ParseNodeKind kind, TreeContext *tc) {
1046 449094 : return (LexicalScopeNode *)ParseNode::create(kind, PN_NAME, tc);
1047 : }
1048 : };
1049 :
1050 : class LoopControlStatement : public ParseNode {
1051 : protected:
1052 91703 : LoopControlStatement(ParseNodeKind kind, PropertyName *label,
1053 : const TokenPtr &begin, const TokenPtr &end)
1054 91703 : : ParseNode(kind, JSOP_NOP, PN_NULLARY, TokenPos::make(begin, end))
1055 : {
1056 91703 : JS_ASSERT(kind == PNK_BREAK || kind == PNK_CONTINUE);
1057 91703 : pn_u.loopControl.label = label;
1058 91703 : }
1059 :
1060 : public:
1061 : /* Label associated with this break/continue statement, if any. */
1062 91631 : PropertyName *label() const {
1063 91631 : return pn_u.loopControl.label;
1064 : }
1065 : };
1066 :
1067 : class BreakStatement : public LoopControlStatement {
1068 : public:
1069 53082 : BreakStatement(PropertyName *label, const TokenPtr &begin, const TokenPtr &end)
1070 53082 : : LoopControlStatement(PNK_BREAK, label, begin, end)
1071 53082 : { }
1072 : };
1073 :
1074 : inline BreakStatement &
1075 53010 : ParseNode::asBreakStatement()
1076 : {
1077 53010 : JS_ASSERT(isKind(PNK_BREAK));
1078 53010 : JS_ASSERT(isOp(JSOP_NOP));
1079 53010 : JS_ASSERT(pn_arity == PN_NULLARY);
1080 53010 : return *static_cast<BreakStatement *>(this);
1081 : }
1082 :
1083 : class ContinueStatement : public LoopControlStatement {
1084 : public:
1085 38621 : ContinueStatement(PropertyName *label, TokenPtr &begin, TokenPtr &end)
1086 38621 : : LoopControlStatement(PNK_CONTINUE, label, begin, end)
1087 38621 : { }
1088 : };
1089 :
1090 : inline ContinueStatement &
1091 38621 : ParseNode::asContinueStatement()
1092 : {
1093 38621 : JS_ASSERT(isKind(PNK_CONTINUE));
1094 38621 : JS_ASSERT(isOp(JSOP_NOP));
1095 38621 : JS_ASSERT(pn_arity == PN_NULLARY);
1096 38621 : return *static_cast<ContinueStatement *>(this);
1097 : }
1098 :
1099 : class DebuggerStatement : public ParseNode {
1100 : public:
1101 4397 : DebuggerStatement(const TokenPos &pos)
1102 4397 : : ParseNode(PNK_DEBUGGER, JSOP_NOP, PN_NULLARY, pos)
1103 4397 : { }
1104 : };
1105 :
1106 : #if JS_HAS_XML_SUPPORT
1107 : class XMLProcessingInstruction : public ParseNode {
1108 : public:
1109 0 : XMLProcessingInstruction(PropertyName *target, JSAtom *data, const TokenPos &pos)
1110 0 : : ParseNode(PNK_XMLPI, JSOP_NOP, PN_NULLARY, pos)
1111 : {
1112 0 : pn_u.xmlpi.target = target;
1113 0 : pn_u.xmlpi.data = data;
1114 0 : }
1115 :
1116 0 : PropertyName *target() const {
1117 0 : return pn_u.xmlpi.target;
1118 : }
1119 :
1120 0 : JSAtom *data() const {
1121 0 : return pn_u.xmlpi.data;
1122 : }
1123 : };
1124 :
1125 : inline XMLProcessingInstruction &
1126 0 : ParseNode::asXMLProcessingInstruction()
1127 : {
1128 0 : JS_ASSERT(isKind(PNK_XMLPI));
1129 0 : JS_ASSERT(isOp(JSOP_NOP));
1130 0 : JS_ASSERT(pn_arity == PN_NULLARY);
1131 0 : return *static_cast<XMLProcessingInstruction *>(this);
1132 : }
1133 : #endif
1134 :
1135 : class ConditionalExpression : public ParseNode {
1136 : public:
1137 68371 : ConditionalExpression(ParseNode *condition, ParseNode *thenExpr, ParseNode *elseExpr)
1138 : : ParseNode(PNK_CONDITIONAL, JSOP_NOP, PN_TERNARY,
1139 68371 : TokenPos::make(condition->pn_pos.begin, elseExpr->pn_pos.end))
1140 : {
1141 68371 : JS_ASSERT(condition);
1142 68371 : JS_ASSERT(thenExpr);
1143 68371 : JS_ASSERT(elseExpr);
1144 68371 : pn_u.ternary.kid1 = condition;
1145 68371 : pn_u.ternary.kid2 = thenExpr;
1146 68371 : pn_u.ternary.kid3 = elseExpr;
1147 68371 : }
1148 :
1149 68371 : ParseNode &condition() const {
1150 68371 : return *pn_u.ternary.kid1;
1151 : }
1152 :
1153 68371 : ParseNode &thenExpression() const {
1154 68371 : return *pn_u.ternary.kid2;
1155 : }
1156 :
1157 68371 : ParseNode &elseExpression() const {
1158 68371 : return *pn_u.ternary.kid3;
1159 : }
1160 : };
1161 :
1162 : inline ConditionalExpression &
1163 68371 : ParseNode::asConditionalExpression()
1164 : {
1165 68371 : JS_ASSERT(isKind(PNK_CONDITIONAL));
1166 68371 : JS_ASSERT(isOp(JSOP_NOP));
1167 68371 : JS_ASSERT(pn_arity == PN_TERNARY);
1168 68371 : return *static_cast<ConditionalExpression *>(this);
1169 : }
1170 :
1171 : class ThisLiteral : public ParseNode {
1172 : public:
1173 1673696 : ThisLiteral(const TokenPos &pos) : ParseNode(PNK_THIS, JSOP_THIS, PN_NULLARY, pos) { }
1174 : };
1175 :
1176 : class NullLiteral : public ParseNode {
1177 : public:
1178 324714 : NullLiteral(const TokenPos &pos) : ParseNode(PNK_NULL, JSOP_NULL, PN_NULLARY, pos) { }
1179 : };
1180 :
1181 : class BooleanLiteral : public ParseNode {
1182 : public:
1183 389603 : BooleanLiteral(bool b, const TokenPos &pos)
1184 389603 : : ParseNode(b ? PNK_TRUE : PNK_FALSE, b ? JSOP_TRUE : JSOP_FALSE, PN_NULLARY, pos)
1185 389603 : { }
1186 : };
1187 :
1188 : class XMLDoubleColonProperty : public ParseNode {
1189 : public:
1190 9 : XMLDoubleColonProperty(ParseNode *lhs, ParseNode *rhs,
1191 : const TokenPtr &begin, const TokenPtr &end)
1192 9 : : ParseNode(PNK_LB, JSOP_GETELEM, PN_BINARY, TokenPos::make(begin, end))
1193 : {
1194 9 : JS_ASSERT(rhs->isKind(PNK_DBLCOLON));
1195 9 : pn_u.binary.left = lhs;
1196 9 : pn_u.binary.right = rhs;
1197 9 : }
1198 :
1199 : ParseNode &left() const {
1200 : return *pn_u.binary.left;
1201 : }
1202 :
1203 : ParseNode &right() const {
1204 : return *pn_u.binary.right;
1205 : }
1206 : };
1207 :
1208 : class XMLFilterExpression : public ParseNode {
1209 : public:
1210 63 : XMLFilterExpression(ParseNode *lhs, ParseNode *filterExpr,
1211 : const TokenPtr &begin, const TokenPtr &end)
1212 63 : : ParseNode(PNK_FILTER, JSOP_FILTER, PN_BINARY, TokenPos::make(begin, end))
1213 : {
1214 63 : pn_u.binary.left = lhs;
1215 63 : pn_u.binary.right = filterExpr;
1216 63 : }
1217 :
1218 : ParseNode &left() const {
1219 : return *pn_u.binary.left;
1220 : }
1221 :
1222 : ParseNode &filter() const {
1223 : return *pn_u.binary.right;
1224 : }
1225 : };
1226 :
1227 : class XMLProperty : public ParseNode {
1228 : public:
1229 0 : XMLProperty(ParseNode *lhs, ParseNode *propertyId,
1230 : const TokenPtr &begin, const TokenPtr &end)
1231 0 : : ParseNode(PNK_LB, JSOP_GETELEM, PN_BINARY, TokenPos::make(begin, end))
1232 : {
1233 0 : pn_u.binary.left = lhs;
1234 0 : pn_u.binary.right = propertyId;
1235 0 : }
1236 :
1237 : ParseNode &left() const {
1238 : return *pn_u.binary.left;
1239 : }
1240 :
1241 : ParseNode &right() const {
1242 : return *pn_u.binary.right;
1243 : }
1244 : };
1245 :
1246 : class PropertyAccess : public ParseNode {
1247 : public:
1248 9922115 : PropertyAccess(ParseNode *lhs, PropertyName *name,
1249 : const TokenPtr &begin, const TokenPtr &end)
1250 9922115 : : ParseNode(PNK_DOT, JSOP_GETPROP, PN_NAME, TokenPos::make(begin, end))
1251 : {
1252 9922115 : JS_ASSERT(lhs != NULL);
1253 9922115 : JS_ASSERT(name != NULL);
1254 9922115 : pn_u.name.expr = lhs;
1255 9922115 : pn_u.name.atom = name;
1256 9922115 : }
1257 :
1258 : ParseNode &expression() const {
1259 : return *pn_u.name.expr;
1260 : }
1261 :
1262 : PropertyName &name() const {
1263 : return *pn_u.name.atom->asPropertyName();
1264 : }
1265 : };
1266 :
1267 : inline PropertyAccess &
1268 : ParseNode::asPropertyAccess()
1269 : {
1270 : JS_ASSERT(isKind(PNK_DOT));
1271 : JS_ASSERT(pn_arity == PN_NAME);
1272 : return *static_cast<PropertyAccess *>(this);
1273 : }
1274 :
1275 : class PropertyByValue : public ParseNode {
1276 : public:
1277 3641198 : PropertyByValue(ParseNode *lhs, ParseNode *propExpr,
1278 : const TokenPtr &begin, const TokenPtr &end)
1279 3641198 : : ParseNode(PNK_LB, JSOP_GETELEM, PN_BINARY, TokenPos::make(begin, end))
1280 : {
1281 3641198 : pn_u.binary.left = lhs;
1282 3641198 : pn_u.binary.right = propExpr;
1283 3641198 : }
1284 : };
1285 :
1286 : ParseNode *
1287 : CloneLeftHandSide(ParseNode *opn, TreeContext *tc);
1288 :
1289 : #ifdef DEBUG
1290 : void DumpParseTree(ParseNode *pn, int indent = 0);
1291 : #endif
1292 :
1293 : /*
1294 : * js::Definition is a degenerate subtype of the PN_FUNC and PN_NAME variants
1295 : * of js::ParseNode, allocated only for function, var, const, and let
1296 : * declarations that define truly lexical bindings. This means that a child of
1297 : * a PNK_VAR list may be a Definition as well as a ParseNode. The pn_defn bit
1298 : * is set for all Definitions, clear otherwise.
1299 : *
1300 : * In an upvars list, defn->resolve() is the outermost definition the
1301 : * name may reference. If a with block or a function that calls eval encloses
1302 : * the use, the name may end up referring to something else at runtime.
1303 : *
1304 : * Note that not all var declarations are definitions: JS allows multiple var
1305 : * declarations in a function or script, but only the first creates the hoisted
1306 : * binding. JS programmers do redeclare variables for good refactoring reasons,
1307 : * for example:
1308 : *
1309 : * function foo() {
1310 : * ...
1311 : * for (var i ...) ...;
1312 : * ...
1313 : * for (var i ...) ...;
1314 : * ...
1315 : * }
1316 : *
1317 : * Not all definitions bind lexical variables, alas. In global and eval code
1318 : * var may re-declare a pre-existing property having any attributes, with or
1319 : * without JSPROP_PERMANENT. In eval code, indeed, ECMA-262 Editions 1 through
1320 : * 3 require function and var to bind deletable bindings. Global vars thus are
1321 : * properties of the global object, so they can be aliased even if they can't
1322 : * be deleted.
1323 : *
1324 : * Only bindings within function code may be treated as lexical, of course with
1325 : * the caveat that hoisting means use before initialization is allowed. We deal
1326 : * with use before declaration in one pass as follows (error checking elided):
1327 : *
1328 : * for (each use of unqualified name x in parse order) {
1329 : * if (this use of x is a declaration) {
1330 : * if (x in tc->decls) { // redeclaring
1331 : * pn = allocate a PN_NAME ParseNode;
1332 : * } else { // defining
1333 : * dn = lookup x in tc->lexdeps;
1334 : * if (dn) // use before def
1335 : * remove x from tc->lexdeps;
1336 : * else // def before use
1337 : * dn = allocate a PN_NAME Definition;
1338 : * map x to dn via tc->decls;
1339 : * pn = dn;
1340 : * }
1341 : * insert pn into its parent PNK_VAR/PNK_CONST list;
1342 : * } else {
1343 : * pn = allocate a ParseNode for this reference to x;
1344 : * dn = lookup x in tc's lexical scope chain;
1345 : * if (!dn) {
1346 : * dn = lookup x in tc->lexdeps;
1347 : * if (!dn) {
1348 : * dn = pre-allocate a Definition for x;
1349 : * map x to dn in tc->lexdeps;
1350 : * }
1351 : * }
1352 : * append pn to dn's use chain;
1353 : * }
1354 : * }
1355 : *
1356 : * See frontend/BytecodeEmitter.h for js::TreeContext and its top*Stmt,
1357 : * decls, and lexdeps members.
1358 : *
1359 : * Notes:
1360 : *
1361 : * 0. To avoid bloating ParseNode, we steal a bit from pn_arity for pn_defn
1362 : * and set it on a ParseNode instead of allocating a Definition.
1363 : *
1364 : * 1. Due to hoisting, a definition cannot be eliminated even if its "Variable
1365 : * statement" (ECMA-262 12.2) can be proven to be dead code. RecycleTree in
1366 : * ParseNode.cpp will not recycle a node whose pn_defn bit is set.
1367 : *
1368 : * 2. "lookup x in tc's lexical scope chain" gives up on def/use chaining if a
1369 : * with statement is found along the the scope chain, which includes tc,
1370 : * tc->parent, etc. Thus we eagerly connect an inner function's use of an
1371 : * outer's var x if the var x was parsed before the inner function.
1372 : *
1373 : * 3. A use may be eliminated as dead by the constant folder, which therefore
1374 : * must remove the dead name node from its singly-linked use chain, which
1375 : * would mean hashing to find the definition node and searching to update
1376 : * the pn_link pointing at the use to be removed. This is costly, so as for
1377 : * dead definitions, we do not recycle dead pn_used nodes.
1378 : *
1379 : * At the end of parsing a function body or global or eval program, tc->lexdeps
1380 : * holds the lexical dependencies of the parsed unit. The name to def/use chain
1381 : * mappings are then merged into the parent tc->lexdeps.
1382 : *
1383 : * Thus if a later var x is parsed in the outer function satisfying an earlier
1384 : * inner function's use of x, we will remove dn from tc->lexdeps and re-use it
1385 : * as the new definition node in the outer function's parse tree.
1386 : *
1387 : * When the compiler unwinds from the outermost tc, tc->lexdeps contains the
1388 : * definition nodes with use chains for all free variables. These are either
1389 : * global variables or reference errors.
1390 : *
1391 : * We analyze whether a binding is initialized, whether the bound names is ever
1392 : * assigned apart from its initializer, and if the bound name definition or use
1393 : * is in a direct child of a block. These PND_* flags allow a subset dominance
1394 : * computation telling whether an initialized var dominates its uses. An inner
1395 : * function using only such outer vars (and formal parameters) can be optimized
1396 : * into a flat closure. See JSOP_{GET,CALL}DSLOT.
1397 : *
1398 : * Another important subset dominance relation: ... { var x = ...; ... x ... }
1399 : * where x is not assigned after initialization and not used outside the block.
1400 : * This style is common in the absence of 'let'. Even though the var x is not
1401 : * at top level, we can tell its initialization dominates all uses cheaply,
1402 : * because the above one-pass algorithm sees the definition before any uses,
1403 : * and because all uses are contained in the same block as the definition.
1404 : *
1405 : * We also analyze function uses to flag upward/downward funargs. If a lambda
1406 : * post-dominates each of its upvars' sole, inevitable (i.e. not hidden behind
1407 : * conditions or within loops or the like) initialization or assignment; then
1408 : * we can optimize the lambda as a flat closure (after Chez Scheme's display
1409 : * closures).
1410 : */
1411 : #define dn_uses pn_link
1412 :
1413 : struct Definition : public ParseNode
1414 : {
1415 : /*
1416 : * We store definition pointers in PN_NAMESET AtomDefnMapPtrs in the AST,
1417 : * but due to redefinition these nodes may become uses of other
1418 : * definitions. This is unusual, so we simply chase the pn_lexdef link to
1419 : * find the final definition node. See functions called from
1420 : * js::frontend::AnalyzeFunctions.
1421 : *
1422 : * FIXME: MakeAssignment mutates for want of a parent link...
1423 : */
1424 6932013 : Definition *resolve() {
1425 6932013 : ParseNode *pn = this;
1426 20795139 : while (!pn->isDefn()) {
1427 6931113 : if (pn->isAssignment()) {
1428 0 : pn = pn->pn_left;
1429 0 : continue;
1430 : }
1431 6931113 : pn = pn->lexdef();
1432 : }
1433 6932013 : return (Definition *) pn;
1434 : }
1435 :
1436 6931113 : bool isFreeVar() const {
1437 6931113 : JS_ASSERT(isDefn());
1438 6931113 : return pn_cookie.isFree() || test(PND_GVAR);
1439 : }
1440 :
1441 18377192 : bool isGlobal() const {
1442 18377192 : JS_ASSERT(isDefn());
1443 18377192 : return test(PND_GVAR);
1444 : }
1445 :
1446 : enum Kind { VAR, CONST, LET, FUNCTION, ARG, UNKNOWN };
1447 :
1448 11814 : bool isBindingForm() { return int(kind()) <= int(LET); }
1449 :
1450 : static const char *kindString(Kind kind);
1451 :
1452 19009269 : Kind kind() {
1453 19009269 : if (getKind() == PNK_FUNCTION)
1454 614273 : return FUNCTION;
1455 18394996 : JS_ASSERT(getKind() == PNK_NAME);
1456 18394996 : if (isOp(JSOP_NOP))
1457 9798628 : return UNKNOWN;
1458 8596368 : if (isOp(JSOP_GETARG))
1459 2909793 : return ARG;
1460 5686575 : if (isConst())
1461 768156 : return CONST;
1462 4918419 : if (isLet())
1463 1041566 : return LET;
1464 3876853 : return VAR;
1465 : }
1466 : };
1467 :
1468 : class ParseNodeAllocator {
1469 : public:
1470 134271 : explicit ParseNodeAllocator(JSContext *cx) : cx(cx), freelist(NULL) {}
1471 :
1472 : void *allocNode();
1473 : void freeNode(ParseNode *pn);
1474 : ParseNode *freeTree(ParseNode *pn);
1475 : void prepareNodeForMutation(ParseNode *pn);
1476 :
1477 : private:
1478 : JSContext *cx;
1479 : ParseNode *freelist;
1480 : };
1481 :
1482 : inline bool
1483 65096734 : ParseNode::test(unsigned flag) const
1484 : {
1485 65096734 : JS_ASSERT(pn_defn || pn_arity == PN_FUNC || pn_arity == PN_NAME);
1486 : #ifdef DEBUG
1487 65096734 : if ((flag & (PND_ASSIGNED | PND_FUNARG)) && pn_defn && !(pn_dflags & flag)) {
1488 12059565 : for (ParseNode *pn = ((Definition *) this)->dn_uses; pn; pn = pn->pn_link) {
1489 9165963 : JS_ASSERT(!pn->pn_defn);
1490 9165963 : JS_ASSERT(!(pn->pn_dflags & flag));
1491 : }
1492 : }
1493 : #endif
1494 65096734 : return !!(pn_dflags & flag);
1495 : }
1496 :
1497 : inline void
1498 101574 : ParseNode::setFunArg()
1499 : {
1500 : /*
1501 : * pn_defn NAND pn_used must be true, per this chart:
1502 : *
1503 : * pn_defn pn_used
1504 : * 0 0 anonymous function used implicitly, e.g. by
1505 : * hidden yield in a genexp
1506 : * 0 1 a use of a definition or placeholder
1507 : * 1 0 a definition or placeholder
1508 : * 1 1 error: this case must not be possible
1509 : */
1510 101574 : JS_ASSERT(!(pn_defn & pn_used));
1511 101574 : if (pn_used)
1512 0 : pn_lexdef->pn_dflags |= PND_FUNARG;
1513 101574 : pn_dflags |= PND_FUNARG;
1514 101574 : }
1515 :
1516 : inline void
1517 13897191 : LinkUseToDef(ParseNode *pn, Definition *dn, TreeContext *tc)
1518 : {
1519 13897191 : JS_ASSERT(!pn->isUsed());
1520 13897191 : JS_ASSERT(!pn->isDefn());
1521 13897191 : JS_ASSERT(pn != dn->dn_uses);
1522 13897191 : pn->pn_link = dn->dn_uses;
1523 13897191 : dn->dn_uses = pn;
1524 13897191 : dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS;
1525 13897191 : pn->setUsed(true);
1526 13897191 : pn->pn_lexdef = dn;
1527 13897191 : }
1528 :
1529 : struct ObjectBox {
1530 : ObjectBox *traceLink;
1531 : ObjectBox *emitLink;
1532 : JSObject *object;
1533 : bool isFunctionBox;
1534 : };
1535 :
1536 : #define JSFB_LEVEL_BITS 14
1537 :
1538 : struct FunctionBox : public ObjectBox
1539 : {
1540 : ParseNode *node;
1541 : FunctionBox *siblings;
1542 : FunctionBox *kids;
1543 : FunctionBox *parent;
1544 : ParseNode *methods; /* would-be methods set on this;
1545 : these nodes are linked via
1546 : pn_link, since lambdas are
1547 : neither definitions nor uses
1548 : of a binding */
1549 : Bindings bindings; /* bindings for this function */
1550 : uint32_t queued:1,
1551 : inLoop:1, /* in a loop in parent function */
1552 : level:JSFB_LEVEL_BITS;
1553 : uint32_t tcflags;
1554 :
1555 3150908 : JSFunction *function() const { return (JSFunction *) object; }
1556 :
1557 : bool joinable() const;
1558 :
1559 : /*
1560 : * True if this function is inside the scope of a with-statement, an E4X
1561 : * filter-expression, or a function that uses direct eval.
1562 : */
1563 : bool inAnyDynamicScope() const;
1564 :
1565 : /*
1566 : * Must this function's descendants be marked as having an extensible
1567 : * ancestor?
1568 : */
1569 : bool scopeIsExtensible() const;
1570 : };
1571 :
1572 : struct FunctionBoxQueue {
1573 : FunctionBox **vector;
1574 : size_t head, tail;
1575 : size_t lengthMask;
1576 :
1577 796706 : size_t count() { return head - tail; }
1578 1121546 : size_t length() { return lengthMask + 1; }
1579 :
1580 324840 : FunctionBoxQueue()
1581 324840 : : vector(NULL), head(0), tail(0), lengthMask(0) { }
1582 :
1583 324840 : bool init(uint32_t count) {
1584 324840 : lengthMask = JS_BITMASK(JS_CEILING_LOG2W(count));
1585 324840 : vector = (FunctionBox **) OffTheBooks::malloc_(sizeof(FunctionBox) * length());
1586 324840 : return !!vector;
1587 : }
1588 :
1589 324840 : ~FunctionBoxQueue() { UnwantedForeground::free_(vector); }
1590 :
1591 803605 : void push(FunctionBox *funbox) {
1592 803605 : if (!funbox->queued) {
1593 796706 : JS_ASSERT(count() < length());
1594 796706 : vector[head++ & lengthMask] = funbox;
1595 796706 : funbox->queued = true;
1596 : }
1597 803605 : }
1598 :
1599 1121546 : FunctionBox *pull() {
1600 1121546 : if (tail == head)
1601 324840 : return NULL;
1602 796706 : JS_ASSERT(tail < head);
1603 796706 : FunctionBox *funbox = vector[tail++ & lengthMask];
1604 796706 : funbox->queued = false;
1605 796706 : return funbox;
1606 : }
1607 : };
1608 :
1609 : } /* namespace js */
1610 :
1611 : #endif /* ParseNode_h__ */
|