/[jscoverage]/trunk/js/jsparse.h
ViewVC logotype

Diff of /trunk/js/jsparse.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 459 by siliconforks, Tue Dec 9 03:37:47 2008 UTC revision 460 by siliconforks, Sat Sep 26 23:15:22 2009 UTC
# Line 46  Line 46 
46  #include "jsversion.h"  #include "jsversion.h"
47  #include "jsprvtd.h"  #include "jsprvtd.h"
48  #include "jspubtd.h"  #include "jspubtd.h"
49    #include "jsatom.h"
50  #include "jsscan.h"  #include "jsscan.h"
51    
52  JS_BEGIN_EXTERN_C  JS_BEGIN_EXTERN_C
# Line 61  Line 62 
62   * Label        Variant     Members   * Label        Variant     Members
63   * -----        -------     -------   * -----        -------     -------
64   * <Definitions>   * <Definitions>
65   * TOK_FUNCTION func        pn_funpob: JSParsedObjectBox holding function   * TOK_FUNCTION name        pn_funbox: ptr to JSFunctionBox holding function
66   *                            object containing arg and var properties.  We   *                            object containing arg and var properties.  We
67   *                            create the function object at parse (not emit)   *                            create the function object at parse (not emit)
68   *                            time to specialize arg and var bytecodes early.   *                            time to specialize arg and var bytecodes early.
69   *                          pn_body: TOK_LC node for function body statements   *                          pn_body: TOK_UPVARS if the function's source body
70   *                          pn_flags: TCF_FUN_* flags (see jsemit.h) collected   *                                   depends on outer names, else TOK_ARGSBODY
71   *                            while parsing the function's body   *                                   if formal parameters, else TOK_LC node for
72     *                                   function body statements
73     *                          pn_cookie: static level and var index for function
74     *                          pn_dflags: PND_* definition/use flags (see below)
75     *                          pn_blockid: block id number
76     * TOK_ARGSBODY list        list of formal parameters followed by TOK_LC node
77     *                            for function body statements as final element
78     *                          pn_count: 1 + number of formal parameters
79     * TOK_UPVARS   nameset     pn_names: lexical dependencies (JSDefinitions)
80     *                            defined in enclosing scopes, or ultimately not
81     *                            defined (free variables, either global property
82     *                            references or reference errors).
83     *                          pn_argsbody: TOK_ARGSBODY or TOK_LC node
84   *   *
85   * <Statements>   * <Statements>
86   * TOK_LC       list        pn_head: list of pn_count statements   * TOK_LC       list        pn_head: list of pn_count statements
# Line 86  Line 99 
99   * TOK_FOR      binary      pn_left: either   * TOK_FOR      binary      pn_left: either
100   *                            for/in loop: a binary TOK_IN node with   *                            for/in loop: a binary TOK_IN node with
101   *                              pn_left:  TOK_VAR or TOK_NAME to left of 'in'   *                              pn_left:  TOK_VAR or TOK_NAME to left of 'in'
102   *                                if TOK_VAR, its pn_extra may have PNX_POPVAR   *                                if TOK_VAR, its pn_xflags may have PNX_POPVAR
103   *                                and PNX_FORINVAR bits set   *                                and PNX_FORINVAR bits set
104   *                              pn_right: object expr to right of 'in'   *                              pn_right: object expr to right of 'in'
105   *                            for(;;) loop: a ternary TOK_RESERVED node with   *                            for(;;) loop: a ternary TOK_RESERVED node with
# Line 108  Line 121 
121   * TOK_BREAK    name        pn_atom: label or null   * TOK_BREAK    name        pn_atom: label or null
122   * TOK_CONTINUE name        pn_atom: label or null   * TOK_CONTINUE name        pn_atom: label or null
123   * TOK_WITH     binary      pn_left: head expr, pn_right: body   * TOK_WITH     binary      pn_left: head expr, pn_right: body
124   * TOK_VAR      list        pn_head: list of pn_count TOK_NAME nodes   * TOK_VAR      list        pn_head: list of TOK_NAME or TOK_ASSIGN nodes
125   *                                   each name node has   *                                   each name node has
126     *                                     pn_used: false
127   *                                     pn_atom: variable name   *                                     pn_atom: variable name
128   *                                     pn_expr: initializer or null   *                                     pn_expr: initializer or null
129     *                                   each assignment node has
130     *                                     pn_left: TOK_NAME with pn_used true and
131    *                                               pn_lexdef (NOT pn_expr) set
132     *                                     pn_right: initializer
133   * TOK_RETURN   unary       pn_kid: return expr or null   * TOK_RETURN   unary       pn_kid: return expr or null
134   * TOK_SEMI     unary       pn_kid: expr or null statement   * TOK_SEMI     unary       pn_kid: expr or null statement
135   * TOK_COLON    name        pn_atom: label, pn_expr: labeled statement   * TOK_COLON    name        pn_atom: label, pn_expr: labeled statement
# Line 136  Line 154 
154   * TOK_SHOP     binary      pn_left: left-assoc SH expr, pn_right: ADD expr   * TOK_SHOP     binary      pn_left: left-assoc SH expr, pn_right: ADD expr
155   *                          pn_op: JSOP_LSH, JSOP_RSH, JSOP_URSH   *                          pn_op: JSOP_LSH, JSOP_RSH, JSOP_URSH
156   * TOK_PLUS,    binary      pn_left: left-assoc ADD expr, pn_right: MUL expr   * TOK_PLUS,    binary      pn_left: left-assoc ADD expr, pn_right: MUL expr
157   *                          pn_extra: if a left-associated binary TOK_PLUS   *                          pn_xflags: if a left-associated binary TOK_PLUS
158   *                            tree has been flattened into a list (see above   *                            tree has been flattened into a list (see above
159   *                            under <Expressions>), pn_extra will contain   *                            under <Expressions>), pn_xflags will contain
160   *                            PNX_STRCAT if at least one list element is a   *                            PNX_STRCAT if at least one list element is a
161   *                            string literal (TOK_STRING); if such a list has   *                            string literal (TOK_STRING); if such a list has
162   *                            any non-string, non-number term, pn_extra will   *                            any non-string, non-number term, pn_xflags will
163   *                            contain PNX_CANTFOLD.   *                            contain PNX_CANTFOLD.
164   *                          pn_   *                          pn_
165   * TOK_MINUS                pn_op: JSOP_ADD, JSOP_SUB   * TOK_MINUS                pn_op: JSOP_ADD, JSOP_SUB
# Line 164  Line 182 
182   *                          call is a MEMBER expr naming a callable object   *                          call is a MEMBER expr naming a callable object
183   * TOK_RB       list        pn_head: list of pn_count array element exprs   * TOK_RB       list        pn_head: list of pn_count array element exprs
184   *                          [,,] holes are represented by TOK_COMMA nodes   *                          [,,] holes are represented by TOK_COMMA nodes
185   *                          #n=[...] produces TOK_DEFSHARP at head of list   *                          pn_xflags: PN_ENDCOMMA if extra comma at end
186   *                          pn_extra: PN_ENDCOMMA if extra comma at end   * TOK_RC       list        pn_head: list of pn_count binary TOK_COLON nodes
187   * TOK_RC       list        pn_head: list of pn_count TOK_COLON nodes where   * TOK_COLON    binary      key-value pair in object initializer or
188   *                          each has pn_left: property id, pn_right: value   *                          destructuring lhs
189   *                          #n={...} produces TOK_DEFSHARP at head of list   *                          pn_left: property id, pn_right: value
190   *                          var {x} = object destructuring shorthand shares   *                          var {x} = object destructuring shorthand shares
191   *                          PN_NAME node for x on left and right of TOK_COLON   *                          PN_NAME node for x on left and right of TOK_COLON
192   *                          node in TOK_RC's list, has PNX_SHORTHAND flag   *                          node in TOK_RC's list, has PNX_DESTRUCT flag
193   * TOK_DEFSHARP unary       pn_num: jsint value of n in #n=   * TOK_DEFSHARP unary       pn_num: jsint value of n in #n=
194   *                          pn_kid: null for #n=[...] and #n={...}, primary   *                          pn_kid: primary function, paren, name, object or
195   *                          if #n=primary for function, paren, name, object   *                                  array literal expressions
  *                          literal expressions  
196   * TOK_USESHARP nullary     pn_num: jsint value of n in #n#   * TOK_USESHARP nullary     pn_num: jsint value of n in #n#
197   * TOK_RP       unary       pn_kid: parenthesized expression   * TOK_RP       unary       pn_kid: parenthesized expression
198   * TOK_NAME,    name        pn_atom: name, string, or object atom   * TOK_NAME,    name        pn_atom: name, string, or object atom
199   * TOK_STRING,              pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT, or   * TOK_STRING,              pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT, or
200   *                                 JSOP_REGEXP   *                                 JSOP_REGEXP
201   * TOK_REGEXP               If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR   * TOK_REGEXP               If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR
202   *                          with pn_slot >= 0 and pn_const telling const-ness   *                          with pn_cookie telling (staticLevel, slot) (see
203     *                          jsscript.h's UPVAR macros) and pn_dflags telling
204     *                          const-ness and static analysis results
205     * TOK_NAME     name        If pn_used, TOK_NAME uses the lexdef member instead
206     *                          of the expr member it overlays
207   * TOK_NUMBER   dval        pn_dval: double value of numeric literal   * TOK_NUMBER   dval        pn_dval: double value of numeric literal
208   * TOK_PRIMARY  nullary     pn_op: JSOp bytecode   * TOK_PRIMARY  nullary     pn_op: JSOp bytecode
209   *   *
# Line 245  Line 266 
266   * Label              Variant   Members   * Label              Variant   Members
267   * -----              -------   -------   * -----              -------   -------
268   * TOK_LEXICALSCOPE   name      pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR   * TOK_LEXICALSCOPE   name      pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR
269   *                              pn_pob: block object   *                              pn_objbox: block object in JSObjectBox holder
270   *                              pn_expr: block body   *                              pn_expr: block body
271   * TOK_ARRAYCOMP      list      pn_head: list of pn_count (1 or 2) elements   * TOK_ARRAYCOMP      list      pn_head: list of pn_count (1 or 2) elements
272   *                              if pn_count is 2, first element is #n=[...]   *                              if pn_count is 2, first element is #n=[...]
273   *                                last element is block enclosing for loop(s)   *                                last element is block enclosing for loop(s)
274   *                                and optionally if-guarded TOK_ARRAYPUSH   *                                and optionally if-guarded TOK_ARRAYPUSH
  *                              pn_extra: stack slot, used during code gen  
275   * TOK_ARRAYPUSH      unary     pn_op: JSOP_ARRAYCOMP   * TOK_ARRAYPUSH      unary     pn_op: JSOP_ARRAYCOMP
276   *                              pn_kid: array comprehension expression   *                              pn_kid: array comprehension expression
277   */   */
278  typedef enum JSParseNodeArity {  typedef enum JSParseNodeArity {
279      PN_FUNC     = -3,      PN_NULLARY,                         /* 0 kids, only pn_atom/pn_dval/etc. */
280      PN_LIST     = -2,      PN_UNARY,                           /* one kid, plus a couple of scalars */
281      PN_TERNARY  =  3,      PN_BINARY,                          /* two kids, plus a couple of scalars */
282      PN_BINARY   =  2,      PN_TERNARY,                         /* three kids */
283      PN_UNARY    =  1,      PN_FUNC,                            /* function definition node */
284      PN_NAME     = -1,      PN_LIST,                            /* generic singly linked list */
285      PN_NULLARY  =  0      PN_NAME,                            /* name use or definition node */
286        PN_NAMESET                          /* JSAtomList + JSParseNode ptr */
287  } JSParseNodeArity;  } JSParseNodeArity;
288    
289    struct JSDefinition;
290    
291  struct JSParseNode {  struct JSParseNode {
292      uint16              pn_type;      uint32              pn_type:16,     /* TOK_* type, see jsscan.h */
293      uint8               pn_op;                          pn_op:8,        /* see JSOp enum and jsopcode.tbl */
294      int8                pn_arity;                          pn_arity:6,     /* see JSParseNodeArity enum */
295      JSTokenPos          pn_pos;                          pn_used:1,      /* name node is on a use-chain */
296      ptrdiff_t           pn_offset;      /* first generated bytecode offset */                          pn_defn:1;      /* this node is a JSDefinition */
297    
298    #define PN_OP(pn)    ((JSOp)(pn)->pn_op)
299    #define PN_TYPE(pn)  ((JSTokenType)(pn)->pn_type)
300    
301        JSTokenPos          pn_pos;         /* two 16-bit pairs here, for 64 bits */
302        int32               pn_offset;      /* first generated bytecode offset */
303        JSParseNode         *pn_next;       /* intrinsic link in parent PN_LIST */
304        JSParseNode         *pn_link;       /* def/use link (alignment freebie) */
305      union {      union {
         struct {                        /* TOK_FUNCTION node */  
             JSParsedObjectBox *funpob;  /* function object */  
             JSParseNode *body;          /* TOK_LC list of statements */  
             uint16      flags;          /* accumulated tree context flags */  
             uint32      index;          /* emitter's index */  
         } func;  
306          struct {                        /* list of next-linked nodes */          struct {                        /* list of next-linked nodes */
307              JSParseNode *head;          /* first node in list */              JSParseNode *head;          /* first node in list */
308              JSParseNode **tail;         /* ptr to ptr to last node in list */              JSParseNode **tail;         /* ptr to ptr to last node in list */
309              uint32      count;          /* number of nodes in list */              uint32      count;          /* number of nodes in list */
310              uint32      extra;          /* extra flags, see below */              uint32      xflags:12,      /* extra flags, see below */
311                            blockid:20;     /* see name variant below */
312          } list;          } list;
313          struct {                        /* ternary: if, for(;;), ?: */          struct {                        /* ternary: if, for(;;), ?: */
314              JSParseNode *kid1;          /* condition, discriminant, etc. */              JSParseNode *kid1;          /* condition, discriminant, etc. */
# Line 301  Line 327 
327              JSBool      hidden;         /* hidden genexp-induced JSOP_YIELD */              JSBool      hidden;         /* hidden genexp-induced JSOP_YIELD */
328          } unary;          } unary;
329          struct {                        /* name, labeled statement, etc. */          struct {                        /* name, labeled statement, etc. */
330              JSAtom      *atom;          /* name or label atom, null if slot */              union {
331              JSParseNode *expr;          /* object or initializer */                  JSAtom        *atom;    /* lexical name or label atom */
332              jsint       slot;           /* -1 or arg or local var slot */                  JSFunctionBox *funbox;  /* function object */
333              JSBool      isconst;        /* true for const names */                  JSObjectBox   *objbox;  /* block or regexp object */
334                };
335                union {
336                    JSParseNode  *expr;     /* function body, var initializer, or
337                                               base object of TOK_DOT */
338                    JSDefinition *lexdef;   /* lexical definition for this use */
339                };
340                uint32      cookie;         /* upvar cookie with absolute frame
341                                               level (not relative skip), possibly
342                                               in current frame */
343                uint32      dflags:12,      /* definition/use flags, see below */
344                            blockid:20;     /* block number, for subset dominance
345                                               computation */
346    
347                JSFunctionBox *funbox2;
348                JSParseNode *expr2;
349          } name;          } name;
350          struct {                        /* lexical scope. */          struct {                        /* lexical dependencies + sub-tree */
351              JSParsedObjectBox *pob;     /* block object */              JSAtomSet   names;          /* set of names with JSDefinitions */
352              JSParseNode *expr;          /* object or initializer */              JSParseNode *tree;          /* sub-tree containing name uses */
353              jsint       slot;           /* -1 or arg or local var slot */          } nameset;
354          } lexical;          struct {                        /* PN_NULLARY variant for E4X */
         struct {  
355              JSAtom      *atom;          /* first atom in pair */              JSAtom      *atom;          /* first atom in pair */
356              JSAtom      *atom2;         /* second atom in pair or null */              JSAtom      *atom2;         /* second atom in pair or null */
357          } apair;          } apair;
         struct {                        /* object literal */  
             JSParsedObjectBox *pob;  
         } object;  
358          jsdouble        dval;           /* aligned numeric literal value */          jsdouble        dval;           /* aligned numeric literal value */
359      } pn_u;      } pn_u;
     JSParseNode         *pn_next;       /* to align dval and pn_u on RISCs */  
 };  
360    
361  #define pn_funpob       pn_u.func.funpob  #define pn_funbox       pn_u.name.funbox
362  #define pn_body         pn_u.func.body  #define pn_body         pn_u.name.expr
363  #define pn_flags        pn_u.func.flags  #define pn_cookie       pn_u.name.cookie
364  #define pn_index        pn_u.func.index  #define pn_dflags       pn_u.name.dflags
365    #define pn_blockid      pn_u.name.blockid
366    #define pn_index        pn_u.name.blockid /* reuse as object table index */
367  #define pn_head         pn_u.list.head  #define pn_head         pn_u.list.head
368  #define pn_tail         pn_u.list.tail  #define pn_tail         pn_u.list.tail
369  #define pn_count        pn_u.list.count  #define pn_count        pn_u.list.count
370  #define pn_extra        pn_u.list.extra  #define pn_xflags       pn_u.list.xflags
371  #define pn_kid1         pn_u.ternary.kid1  #define pn_kid1         pn_u.ternary.kid1
372  #define pn_kid2         pn_u.ternary.kid2  #define pn_kid2         pn_u.ternary.kid2
373  #define pn_kid3         pn_u.ternary.kid3  #define pn_kid3         pn_u.ternary.kid3
# Line 342  Line 379 
379  #define pn_num          pn_u.unary.num  #define pn_num          pn_u.unary.num
380  #define pn_hidden       pn_u.unary.hidden  #define pn_hidden       pn_u.unary.hidden
381  #define pn_atom         pn_u.name.atom  #define pn_atom         pn_u.name.atom
382    #define pn_objbox       pn_u.name.objbox
383  #define pn_expr         pn_u.name.expr  #define pn_expr         pn_u.name.expr
384  #define pn_slot         pn_u.name.slot  #define pn_lexdef       pn_u.name.lexdef
385  #define pn_const        pn_u.name.isconst  #define pn_names        pn_u.nameset.names
386    #define pn_tree         pn_u.nameset.tree
387  #define pn_dval         pn_u.dval  #define pn_dval         pn_u.dval
388  #define pn_atom2        pn_u.apair.atom2  #define pn_atom2        pn_u.apair.atom2
 #define pn_pob          pn_u.object.pob  
389    
390  /* PN_LIST pn_extra flags. */      /*
391         * The pn_expr and lexdef members are arms of an unsafe union. Unless you
392         * know exactly what you're doing, use only the following methods to access
393         * them. For less overhead and assertions for protection, use pn->expr()
394         * and pn->lexdef(). Otherwise, use pn->maybeExpr() and pn->maybeLexDef().
395         */
396        JSParseNode  *expr() const {
397            JS_ASSERT(!pn_used);
398            JS_ASSERT(pn_arity == PN_NAME || pn_arity == PN_FUNC);
399            return pn_expr;
400        }
401    
402        JSDefinition *lexdef() const {
403            JS_ASSERT(pn_used);
404            JS_ASSERT(pn_arity == PN_NAME);
405            return pn_lexdef;
406        }
407    
408        JSParseNode  *maybeExpr()   { return pn_used ? NULL : expr(); }
409        JSDefinition *maybeLexDef() { return pn_used ? lexdef() : NULL; }
410    
411    /* PN_FUNC and PN_NAME pn_dflags bits. */
412    #define PND_LET         0x01            /* let (block-scoped) binding */
413    #define PND_CONST       0x02            /* const binding (orthogonal to let) */
414    #define PND_INITIALIZED 0x04            /* initialized declaration */
415    #define PND_ASSIGNED    0x08            /* set if ever LHS of assignment */
416    #define PND_TOPLEVEL    0x10            /* function at top of body or prog */
417    #define PND_BLOCKCHILD  0x20            /* use or def is direct block child */
418    #define PND_GVAR        0x40            /* gvar binding, can't close over
419                                               because it could be deleted */
420    #define PND_PLACEHOLDER 0x80            /* placeholder definition for lexdep */
421    #define PND_FUNARG     0x100            /* downward or upward funarg usage */
422    #define PND_BOUND      0x200            /* bound to a stack or global slot */
423    
424    /* PN_LIST pn_xflags bits. */
425  #define PNX_STRCAT      0x01            /* TOK_PLUS list has string term */  #define PNX_STRCAT      0x01            /* TOK_PLUS list has string term */
426  #define PNX_CANTFOLD    0x02            /* TOK_PLUS list has unfoldable term */  #define PNX_CANTFOLD    0x02            /* TOK_PLUS list has unfoldable term */
427  #define PNX_POPVAR      0x04            /* TOK_VAR last result needs popping */  #define PNX_POPVAR      0x04            /* TOK_VAR last result needs popping */
# Line 361  Line 433 
433  #define PNX_NEEDBRACES  0x80            /* braces necessary due to closure */  #define PNX_NEEDBRACES  0x80            /* braces necessary due to closure */
434  #define PNX_FUNCDEFS   0x100            /* contains top-level function  #define PNX_FUNCDEFS   0x100            /* contains top-level function
435                                             statements */                                             statements */
436  #define PNX_SHORTHAND  0x200            /* shorthand syntax used, at present  #define PNX_DESTRUCT   0x200            /* destructuring special cases:
437                                             object destructuring ({x,y}) only */                                             1. shorthand syntax used, at present
438                                                  object destructuring ({x,y}) only;
439                                               2. the first child of function body
440                                                  is code evaluating destructuring
441                                                  arguments */
442    #define PNX_HOLEY      0x400            /* array initialiser has holes */
443    
444        uintN frameLevel() const {
445            JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
446            return UPVAR_FRAME_SKIP(pn_cookie);
447        }
448    
449        uintN frameSlot() const {
450            JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
451            return UPVAR_FRAME_SLOT(pn_cookie);
452        }
453    
454        bool test(uintN flag) const {
455            JS_ASSERT(pn_arity == PN_FUNC || pn_arity == PN_NAME);
456            return !!(pn_dflags & flag);
457        }
458    
459        bool isLet() const          { return test(PND_LET); }
460        bool isConst() const        { return test(PND_CONST); }
461        bool isInitialized() const  { return test(PND_INITIALIZED); }
462        bool isTopLevel() const     { return test(PND_TOPLEVEL); }
463        bool isBlockChild() const   { return test(PND_BLOCKCHILD); }
464        bool isPlaceholder() const  { return test(PND_PLACEHOLDER); }
465    
466        /* Defined below, see after struct JSDefinition. */
467        bool isAssigned() const;
468        bool isFunArg() const;
469        void setFunArg();
470    
471        void become(JSParseNode *pn2);
472        void clear();
473    
474        /* True if pn is a parsenode representing a literal constant. */
475        bool isLiteral() const {
476            return PN_TYPE(this) == TOK_NUMBER ||
477                   PN_TYPE(this) == TOK_STRING ||
478                   (PN_TYPE(this) == TOK_PRIMARY && PN_OP(this) != JSOP_THIS);
479        }
480    
481        /*
482         * Compute a pointer to the last element in a singly-linked list. NB: list
483         * must be non-empty for correct PN_LAST usage -- this is asserted!
484         */
485        JSParseNode *last() const {
486            JS_ASSERT(pn_arity == PN_LIST);
487            JS_ASSERT(pn_count != 0);
488            return (JSParseNode *)((char *)pn_tail - offsetof(JSParseNode, pn_next));
489        }
490    
491        void makeEmpty() {
492            JS_ASSERT(pn_arity == PN_LIST);
493            pn_head = NULL;
494            pn_tail = &pn_head;
495            pn_count = 0;
496            pn_xflags = 0;
497            pn_blockid = 0;
498        }
499    
500        void initList(JSParseNode *pn) {
501            JS_ASSERT(pn_arity == PN_LIST);
502            pn_head = pn;
503            pn_tail = &pn->pn_next;
504            pn_count = 1;
505            pn_xflags = 0;
506            pn_blockid = 0;
507        }
508    
509        void append(JSParseNode *pn) {
510            JS_ASSERT(pn_arity == PN_LIST);
511            *pn_tail = pn;
512            pn_tail = &pn->pn_next;
513            pn_count++;
514        }
515    };
516    
517  /*  /*
518   * Move pn2 into pn, preserving pn->pn_pos and pn->pn_offset and handing off   * JSDefinition is a degenerate subtype of the PN_FUNC and PN_NAME variants of
519   * any kids in pn2->pn_u, by clearing pn2.   * JSParseNode, allocated only for function, var, const, and let declarations
520     * that define truly lexical bindings. This means that a child of a TOK_VAR
521     * list may be a JSDefinition instead of a JSParseNode. The pn_defn bit is set
522     * for all JSDefinitions, clear otherwise.
523     *
524     * Note that not all var declarations are definitions: JS allows multiple var
525     * declarations in a function or script, but only the first creates the hoisted
526     * binding. JS programmers do redeclare variables for good refactoring reasons,
527     * for example:
528     *
529     *   function foo() {
530     *       ...
531     *       for (var i ...) ...;
532     *       ...
533     *       for (var i ...) ...;
534     *       ...
535     *   }
536     *
537     * Not all definitions bind lexical variables, alas. In global and eval code
538     * var may re-declare a pre-existing property having any attributes, with or
539     * without JSPROP_PERMANENT. In eval code, indeed, ECMA-262 Editions 1 through
540     * 3 require function and var to bind deletable bindings. Global vars thus are
541     * properties of the global object, so they can be aliased even if they can't
542     * be deleted.
543     *
544     * Only bindings within function code may be treated as lexical, of course with
545     * the caveat that hoisting means use before initialization is allowed. We deal
546     * with use before declaration in one pass as follows (error checking elided):
547     *
548     *   for (each use of unqualified name x in parse order) {
549     *       if (this use of x is a declaration) {
550     *           if (x in tc->decls) {                          // redeclaring
551     *               pn = allocate a PN_NAME JSParseNode;
552     *           } else {                                       // defining
553     *               dn = lookup x in tc->lexdeps;
554     *               if (dn) {                                  // use before def
555     *                   remove x from tc->lexdeps;
556     *               } else {                                   // def before use
557     *                   dn = allocate a PN_NAME JSDefinition;
558     *                   map x to dn via tc->decls;
559     *               }
560     *               pn = dn;
561     *           }
562     *           insert pn into its parent TOK_VAR list;
563     *       } else {
564     *           pn = allocate a JSParseNode for this reference to x;
565     *           dn = lookup x in tc's lexical scope chain;
566     *           if (!dn) {
567     *               dn = lookup x in tc->lexdeps;
568     *               if (!dn) {
569     *                   dn = pre-allocate a JSDefinition for x;
570     *                   map x to dn in tc->lexdeps;
571     *               }
572     *           }
573     *           append pn to dn's use chain;
574     *       }
575     *   }
576     *
577     * See jsemit.h for JSTreeContext and its top*Stmt, decls, and lexdeps members.
578     *
579     * Notes:
580     *
581     *  0. To avoid bloating JSParseNode, we steal a bit from pn_arity for pn_defn
582     *     and set it on a JSParseNode instead of allocating a JSDefinition.
583     *
584     *  1. Due to hoisting, a definition cannot be eliminated even if its "Variable
585     *     statement" (ECMA-262 12.2) can be proven to be dead code. RecycleTree in
586     *     jsparse.cpp will not recycle a node whose pn_defn bit is set.
587     *
588     *  2. "lookup x in tc's lexical scope chain" gives up on def/use chaining if a
589     *     with statement is found along the the scope chain, which includes tc,
590     *     tc->parent, etc. Thus we eagerly connect an inner function's use of an
591     *     outer's var x if the var x was parsed before the inner function.
592     *
593     *  3. A use may be eliminated as dead by the constant folder, which therefore
594     *     must remove the dead name node from its singly-linked use chain, which
595     *     would mean hashing to find the definition node and searching to update
596     *     the pn_link pointing at the use to be removed. This is costly, so as for
597     *     dead definitions, we do not recycle dead pn_used nodes.
598     *
599     * At the end of parsing a function body or global or eval program, tc->lexdeps
600     * holds the lexical dependencies of the parsed unit. The name to def/use chain
601     * mappings are then merged into the parent tc->lexdeps.
602     *
603     * Thus if a later var x is parsed in the outer function satisfying an earlier
604     * inner function's use of x, we will remove dn from tc->lexdeps and re-use it
605     * as the new definition node in the outer function's parse tree.
606     *
607     * When the compiler unwinds from the outermost tc, tc->lexdeps contains the
608     * definition nodes with use chains for all free variables. These are either
609     * global variables or reference errors.
610     *
611     * We analyze whether a binding is initialized, whether the bound names is ever
612     * assigned apart from its initializer, and if the bound name definition or use
613     * is in a direct child of a block. These PND_* flags allow a subset dominance
614     * computation telling whether an initialized var dominates its uses. An inner
615     * function using only such outer vars (and formal parameters) can be optimized
616     * into a flat closure. See JSOP_{GET,CALL}DSLOT.
617     *
618     * Another important subset dominance relation: ... { var x = ...; ... x ... }
619     * where x is not assigned after initialization and not used outside the block.
620     * This style is common in the absence of 'let'. Even though the var x is not
621     * at top level, we can tell its initialization dominates all uses cheaply,
622     * because the above one-pass algorithm sees the definition before any uses,
623     * and because all uses are contained in the same block as the definition.
624     *
625     * We also analyze function uses to flag upward/downward funargs, optimizing
626     * Algol-like (not passed as funargs, only ever called) lightweight functions
627     * using cx->display. See JSOP_{GET,CALL}UPVAR.
628     *
629     * This means that closure optimizations may be frustrated by with, eval, or
630     * assignment to an outer var. Such hard cases require heavyweight functions
631     * and JSOP_NAME, etc.
632   */   */
633  #define PN_MOVE_NODE(pn, pn2)                                                 \  #define dn_uses         pn_link
     JS_BEGIN_MACRO                                                            \  
         (pn)->pn_type = (pn2)->pn_type;                                       \  
         (pn)->pn_op = (pn2)->pn_op;                                           \  
         (pn)->pn_arity = (pn2)->pn_arity;                                     \  
         (pn)->pn_u = (pn2)->pn_u;                                             \  
         PN_CLEAR_NODE(pn2);                                                   \  
     JS_END_MACRO  
   
 #define PN_CLEAR_NODE(pn)                                                     \  
     JS_BEGIN_MACRO                                                            \  
         (pn)->pn_type = TOK_EOF;                                              \  
         (pn)->pn_op = JSOP_NOP;                                               \  
         (pn)->pn_arity = PN_NULLARY;                                          \  
     JS_END_MACRO  
   
 /* True if pn is a parsenode representing a literal constant. */  
 #define PN_IS_CONSTANT(pn)                                                    \  
     ((pn)->pn_type == TOK_NUMBER ||                                           \  
      (pn)->pn_type == TOK_STRING ||                                           \  
      ((pn)->pn_type == TOK_PRIMARY && (pn)->pn_op != JSOP_THIS))  
634    
635  #define PN_OP(pn)    ((JSOp)(pn)->pn_op)  struct JSDefinition : public JSParseNode
636  #define PN_TYPE(pn)  ((JSTokenType)(pn)->pn_type)  {
637        /*
638         * We store definition pointers in PN_NAMESET JSAtomLists in the AST, but
639         * due to redefinition these nodes may become uses of other definitions.
640         * This is unusual, so we simply chase the pn_lexdef link to find the final
641         * definition node. See methods called from JSCompiler::analyzeFunctions.
642         *
643         * FIXME: MakeAssignment mutates for want of a parent link...
644         */
645        JSDefinition *resolve() {
646            JSParseNode *pn = this;
647            while (!pn->pn_defn) {
648                if (pn->pn_type == TOK_ASSIGN) {
649                    pn = pn->pn_left;
650                    continue;
651                }
652                pn = pn->lexdef();
653            }
654            return (JSDefinition *) pn;
655        }
656    
657        bool test(uintN flag) const {
658            JS_ASSERT(pn_defn);
659            if (pn_dflags & flag)
660                return true;
661    #ifdef DEBUG
662            for (JSParseNode *pn = dn_uses; pn; pn = pn->pn_link) {
663                JS_ASSERT(!pn->pn_defn);
664                JS_ASSERT(!(pn->pn_dflags & flag));
665            }
666    #endif
667            return false;
668        }
669    
670        bool isAssigned() const {
671            return test(PND_ASSIGNED);
672        }
673    
674        bool isFunArg() const {
675            return test(PND_FUNARG);
676        }
677    
678        bool isFreeVar() const {
679            JS_ASSERT(pn_defn);
680            return pn_cookie == FREE_UPVAR_COOKIE || test(PND_GVAR);
681        }
682    
683        // Grr, windows.h or something under it #defines CONST...
684    #ifdef CONST
685    # undef CONST
686    #endif
687        enum Kind { VAR, CONST, LET, FUNCTION, ARG, UNKNOWN };
688    
689        bool isBindingForm() { return int(kind()) <= int(LET); }
690    
691        static const char *kindString(Kind kind);
692    
693        Kind kind() {
694            if (PN_TYPE(this) == TOK_FUNCTION)
695                return FUNCTION;
696            JS_ASSERT(PN_TYPE(this) == TOK_NAME);
697            if (PN_OP(this) == JSOP_NOP)
698                return UNKNOWN;
699            if (PN_OP(this) == JSOP_GETARG)
700                return ARG;
701            if (isConst())
702                return CONST;
703            if (isLet())
704                return LET;
705            return VAR;
706        }
707    };
708    
709  /*  /*
710   * Compute a pointer to the last JSParseNode element in a singly-linked list.   * These two are overridden by JSDefinition and we cannot afford virtual
711   * NB: list must be non-empty for correct PN_LAST usage!   * methods -- so we use the mighty 'if' statement!
712   */   */
713  #define PN_LAST(list) \  inline bool
714      ((JSParseNode *)((char *)(list)->pn_tail - offsetof(JSParseNode, pn_next)))  JSParseNode::isAssigned() const
715    {
716    #ifdef DEBUG
717        if (pn_defn)
718            return ((JSDefinition *)this)->isAssigned();
719    #endif
720        return test(PND_ASSIGNED);
721    }
722    
723    inline bool
724    JSParseNode::isFunArg() const
725    {
726    #ifdef DEBUG
727        if (pn_defn)
728            return ((JSDefinition *)this)->isFunArg();
729    #endif
730        return test(PND_FUNARG);
731    }
732    
733  #define PN_INIT_LIST(list)                                                    \  inline void
734      JS_BEGIN_MACRO                                                            \  JSParseNode::setFunArg()
735          (list)->pn_head = NULL;                                               \  {
736          (list)->pn_tail = &(list)->pn_head;                                   \      /*
737          (list)->pn_count = (list)->pn_extra = 0;                              \       * pn_defn NAND pn_used must be true, per this chart:
738      JS_END_MACRO       *
739         *   pn_defn pn_used
740  #define PN_INIT_LIST_1(list, pn)                                              \       *         0       0        anonymous function used implicitly, e.g. by
741      JS_BEGIN_MACRO                                                            \       *                          hidden yield in a genexp
742          (list)->pn_head = (pn);                                               \       *         0       1        a use of a definition or placeholder
743          (list)->pn_tail = &(pn)->pn_next;                                     \       *         1       0        a definition or placeholder
744          (list)->pn_count = 1;                                                 \       *         1       1        error: this case must not be possible
745          (list)->pn_extra = 0;                                                 \       */
746      JS_END_MACRO      JS_ASSERT(!(pn_defn & pn_used));
747        if (pn_used)
748  #define PN_APPEND(list, pn)                                                   \          pn_lexdef->pn_dflags |= PND_FUNARG;
749      JS_BEGIN_MACRO                                                            \      pn_dflags |= PND_FUNARG;
750          *(list)->pn_tail = (pn);                                              \  }
751          (list)->pn_tail = &(pn)->pn_next;                                     \  
752          (list)->pn_count++;                                                   \  struct JSObjectBox {
753      JS_END_MACRO      JSObjectBox         *traceLink;
754        JSObjectBox         *emitLink;
 struct JSParsedObjectBox {  
     JSParsedObjectBox   *traceLink;  
     JSParsedObjectBox   *emitLink;  
755      JSObject            *object;      JSObject            *object;
756  };  };
757    
758  struct JSParseContext {  #define JSFB_LEVEL_BITS 14
     JSTokenStream       tokenStream;  
     void                *tempPoolMark;  /* initial JSContext.tempPool mark */  
     JSPrincipals        *principals;    /* principals associated with source */  
     JSStackFrame        *callerFrame;   /* scripted caller frame for eval and  
                                            debug scripts */  
     JSParseNode         *nodeList;      /* list of recyclable parse-node  
                                            structs */  
     JSParsedObjectBox   *traceListHead; /* list of parsed object for GC  
                                            tracing */  
     JSTempValueRooter   tempRoot;       /* root to trace traceListHead */  
 };  
759    
760  /*  struct JSFunctionBox : public JSObjectBox
761   * Convenience macro to access JSParseContext.tokenStream as a pointer.  {
762   */      JSParseNode         *node;
763  #define TS(pc) (&(pc)->tokenStream)      JSFunctionBox       *siblings;
764        JSFunctionBox       *kids;
765        JSFunctionBox       *parent;
766        uint32              queued:1,
767                            inLoop:1,               /* in a loop in parent function */
768                            level:JSFB_LEVEL_BITS,
769                            tcflags:16;
770    };
771    
772  /*  struct JSFunctionBoxQueue {
773   * Parse a top-level JS script.      JSFunctionBox       **vector;
774   */      size_t              head, tail;
775  extern JSParseNode *      size_t              lengthMask;
776  js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc);  
777        size_t count()  { return head - tail; }
778        size_t length() { return lengthMask + 1; }
779    
780        JSFunctionBoxQueue()
781          : vector(NULL), head(0), tail(0), lengthMask(0) { }
782    
783        bool init(uint32 count) {
784            lengthMask = JS_BITMASK(JS_CeilingLog2(count));
785            vector = new JSFunctionBox*[length()];
786            return !!vector;
787        }
788    
789        ~JSFunctionBoxQueue() { delete[] vector; }
790    
791        void push(JSFunctionBox *funbox) {
792            if (!funbox->queued) {
793                JS_ASSERT(count() < length());
794                vector[head++ & lengthMask] = funbox;
795                funbox->queued = true;
796            }
797        }
798    
799        JSFunctionBox *pull() {
800            if (tail == head)
801                return NULL;
802            JS_ASSERT(tail < head);
803            JSFunctionBox *funbox = vector[tail++ & lengthMask];
804            funbox->queued = false;
805            return funbox;
806        }
807    };
808    
809  extern JSScript *  #define NUM_TEMP_FREELISTS      6U      /* 32 to 2048 byte size classes (32 bit) */
 js_CompileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,  
                  JSPrincipals *principals, uint32 tcflags,  
                  const jschar *chars, size_t length,  
                  FILE *file, const char *filename, uintN lineno);  
810    
811  extern JSBool  struct JSCompiler {
812  js_CompileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,      JSContext           *context;
813                         const jschar *chars, size_t length,      JSAtomListElement   *aleFreeList;
814                         const char *filename, uintN lineno);      void                *tempFreeList[NUM_TEMP_FREELISTS];
815        JSTokenStream       tokenStream;
816        void                *tempPoolMark;  /* initial JSContext.tempPool mark */
817        JSPrincipals        *principals;    /* principals associated with source */
818        JSStackFrame        *callerFrame;   /* scripted caller frame for eval and dbgapi */
819        JSParseNode         *nodeList;      /* list of recyclable parse-node structs */
820        uint32              functionCount;  /* number of functions in current unit */
821        JSObjectBox         *traceListHead; /* list of parsed object for GC tracing */
822        JSTempValueRooter   tempRoot;       /* root to trace traceListHead */
823    
824  extern JSBool      JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL)
825  js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc,        : context(cx), aleFreeList(NULL), principals(NULL), callerFrame(cfp),
826                   bool inCond = false);          nodeList(NULL), functionCount(0), traceListHead(NULL)
827        {
828            memset(tempFreeList, 0, sizeof tempFreeList);
829            setPrincipals(prin);
830            JS_ASSERT_IF(cfp, cfp->script);
831        }
832    
833        ~JSCompiler();
834    
835        /*
836         * Initialize a compiler. Parameters are passed on to js_InitTokenStream.
837         * The compiler owns the arena pool "tops-of-stack" space above the current
838         * JSContext.tempPool mark. This means you cannot allocate from tempPool
839         * and save the pointer beyond the next JSCompiler destructor invocation.
840         */
841        bool init(const jschar *base, size_t length,
842                  FILE *fp, const char *filename, uintN lineno);
843    
844        void setPrincipals(JSPrincipals *prin);
845    
846        /*
847         * Parse a top-level JS script.
848         */
849        JSParseNode *parse(JSObject *chain);
850    
851  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
852  JS_FRIEND_API(JSParseNode *)      JSParseNode *parseXMLText(JSObject *chain, bool allowList);
 js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc,  
                 JSBool allowList);  
853  #endif  #endif
854    
855  /*      /*
856   * Initialize a parse context. All parameters after pc are passed to       * Allocate a new parsed object or function container from cx->tempPool.
857   * js_InitTokenStream.       */
858   *      JSObjectBox *newObjectBox(JSObject *obj);
859   * The parse context owns the arena pool "tops-of-stack" space above the  
860   * current JSContext.tempPool mark. This means you cannot allocate from      JSFunctionBox *newFunctionBox(JSObject *obj, JSParseNode *fn, JSTreeContext *tc);
861   * tempPool and save the pointer beyond the next js_FinishParseContext.  
862   */      /*
863  extern JSBool       * Create a new function object given tree context (tc), optional name
864  js_InitParseContext(JSContext *cx, JSParseContext *pc, JSPrincipals *principals,       * (atom may be null) and lambda flag (JSFUN_LAMBDA or 0).
865                      JSStackFrame *callerFrame,       */
866                      const jschar *base, size_t length, FILE *fp,      JSFunction *newFunction(JSTreeContext *tc, JSAtom *atom, uintN lambda);
867                      const char *filename, uintN lineno);  
868        /*
869  extern void       * Analyze the tree of functions nested within a single compilation unit,
870  js_FinishParseContext(JSContext *cx, JSParseContext *pc);       * starting at funbox, recursively walking its kids, then following its
871         * siblings, their kids, etc.
872  extern void       */
873  js_InitCompilePrincipals(JSContext *cx, JSParseContext *pc,      bool analyzeFunctions(JSFunctionBox *funbox, uint16& tcflags);
874                           JSPrincipals *principals);      bool markFunArgs(JSFunctionBox *funbox, uintN tcflags);
875        void setFunctionKinds(JSFunctionBox *funbox, uint16& tcflags);
876    
877        void trace(JSTracer *trc);
878    
879        static bool
880        compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *principals,
881                            const jschar *chars, size_t length,
882                            const char *filename, uintN lineno);
883    
884        static JSScript *
885        compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
886                      JSPrincipals *principals, uint32 tcflags,
887                      const jschar *chars, size_t length,
888                      FILE *file, const char *filename, uintN lineno,
889                      JSString *source = NULL);
890    };
891    
892  /*  /*
893   * Allocate a new parseed object node from cx->tempPool.   * Convenience macro to access JSCompiler.tokenStream as a pointer.
894   */   */
895  extern JSParsedObjectBox *  #define TS(jsc) (&(jsc)->tokenStream)
 js_NewParsedObjectBox(JSContext *cx, JSParseContext *pc, JSObject *obj);  
896    
897  extern void  extern JSBool
898  js_TraceParseContext(JSTracer *trc, JSParseContext *pc);  js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc,
899                     bool inCond = false);
900    
901  JS_END_EXTERN_C  JS_END_EXTERN_C
902    

Legend:
Removed from v.459  
changed lines
  Added in v.460

  ViewVC Help
Powered by ViewVC 1.1.24