LCOV - code coverage report
Current view: top level - js/src/frontend - ParseNode.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 202 398 50.8 %
Date: 2017-07-14 16:53:18 Functions: 21 38 55.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "frontend/ParseNode-inl.h"
       8             : 
       9             : #include "frontend/Parser.h"
      10             : 
      11             : #include "jscntxtinlines.h"
      12             : 
      13             : using namespace js;
      14             : using namespace js::frontend;
      15             : 
      16             : using mozilla::ArrayLength;
      17             : using mozilla::IsFinite;
      18             : 
      19             : #ifdef DEBUG
      20             : void
      21      127156 : ParseNode::checkListConsistency()
      22             : {
      23      127156 :     MOZ_ASSERT(isArity(PN_LIST));
      24             :     ParseNode** tail;
      25      127156 :     uint32_t count = 0;
      26      127156 :     if (pn_head) {
      27      125227 :         ParseNode* last = pn_head;
      28      125227 :         ParseNode* pn = last;
      29      738195 :         while (pn) {
      30      306484 :             last = pn;
      31      306484 :             pn = pn->pn_next;
      32      306484 :             count++;
      33             :         }
      34             : 
      35      125227 :         tail = &last->pn_next;
      36             :     } else {
      37        1929 :         tail = &pn_head;
      38             :     }
      39      127156 :     MOZ_ASSERT(pn_tail == tail);
      40      127156 :     MOZ_ASSERT(pn_count == count);
      41      127156 : }
      42             : #endif
      43             : 
      44             : /* Add |node| to |parser|'s free node list. */
      45             : void
      46      250533 : ParseNodeAllocator::freeNode(ParseNode* pn)
      47             : {
      48             :     /* Catch back-to-back dup recycles. */
      49      250533 :     MOZ_ASSERT(pn != freelist);
      50             : 
      51             : #ifdef DEBUG
      52             :     /* Poison the node, to catch attempts to use it without initializing it. */
      53      250533 :     memset(pn, 0xab, sizeof(*pn));
      54             : #endif
      55             : 
      56      250533 :     pn->pn_next = freelist;
      57      250533 :     freelist = pn;
      58      250533 : }
      59             : 
      60             : namespace {
      61             : 
      62             : /*
      63             :  * A work pool of ParseNodes. The work pool is a stack, chained together
      64             :  * by nodes' pn_next fields. We use this to avoid creating deep C++ stacks
      65             :  * when recycling deep parse trees.
      66             :  *
      67             :  * Since parse nodes are probably allocated in something close to the order
      68             :  * they appear in a depth-first traversal of the tree, making the work pool
      69             :  * a stack should give us pretty good locality.
      70             :  */
      71             : class NodeStack {
      72             :   public:
      73        3959 :     NodeStack() : top(nullptr) { }
      74      508839 :     bool empty() { return top == nullptr; }
      75      121826 :     void push(ParseNode* pn) {
      76      121826 :         pn->pn_next = top;
      77      121826 :         top = pn;
      78      121826 :     }
      79             :     /* Push the children of the PN_LIST node |pn| on the stack. */
      80       53295 :     void pushList(ParseNode* pn) {
      81             :         /* This clobbers pn->pn_head if the list is empty; should be okay. */
      82       53295 :         *pn->pn_tail = top;
      83       53295 :         top = pn->pn_head;
      84       53295 :     }
      85      252440 :     ParseNode* pop() {
      86      252440 :         MOZ_ASSERT(!empty());
      87      252440 :         ParseNode* hold = top; /* my kingdom for a prog1 */
      88      252440 :         top = top->pn_next;
      89      252440 :         return hold;
      90             :     }
      91             :   private:
      92             :     ParseNode* top;
      93             : };
      94             : 
      95             : } /* anonymous namespace */
      96             : 
      97             : enum class PushResult { Recyclable, CleanUpLater };
      98             : 
      99             : static PushResult
     100        5552 : PushCodeNodeChildren(ParseNode* node, NodeStack* stack)
     101             : {
     102        5552 :     MOZ_ASSERT(node->isArity(PN_CODE));
     103             : 
     104             :     /*
     105             :      * Function nodes are linked into the function box tree, and may appear
     106             :      * on method lists. Both of those lists are singly-linked, so trying to
     107             :      * update them now could result in quadratic behavior when recycling
     108             :      * trees containing many functions; and the lists can be very long. So
     109             :      * we put off cleaning the lists up until just before function
     110             :      * analysis, when we call CleanFunctionList.
     111             :      *
     112             :      * In fact, we can't recycle the parse node yet, either: it may appear
     113             :      * on a method list, and reusing the node would corrupt that. Instead,
     114             :      * we clear its pn_funbox pointer to mark it as deleted;
     115             :      * CleanFunctionList recycles it as well.
     116             :      *
     117             :      * We do recycle the nodes around it, though, so we must clear pointers
     118             :      * to them to avoid leaving dangling references where someone can find
     119             :      * them.
     120             :      */
     121        5552 :     node->pn_funbox = nullptr;
     122        5552 :     if (node->pn_body)
     123        4001 :         stack->push(node->pn_body);
     124        5552 :     node->pn_body = nullptr;
     125             : 
     126        5552 :     return PushResult::CleanUpLater;
     127             : }
     128             : 
     129             : static PushResult
     130       96631 : PushNameNodeChildren(ParseNode* node, NodeStack* stack)
     131             : {
     132       96631 :     MOZ_ASSERT(node->isArity(PN_NAME));
     133             : 
     134       96631 :     if (node->pn_expr)
     135       28351 :         stack->push(node->pn_expr);
     136       96631 :     node->pn_expr = nullptr;
     137       96631 :     return PushResult::Recyclable;
     138             : }
     139             : 
     140             : static PushResult
     141        9660 : PushScopeNodeChildren(ParseNode* node, NodeStack* stack)
     142             : {
     143        9660 :     MOZ_ASSERT(node->isArity(PN_SCOPE));
     144             : 
     145        9660 :     if (node->scopeBody())
     146        9660 :         stack->push(node->scopeBody());
     147        9660 :     node->setScopeBody(nullptr);
     148        9660 :     return PushResult::Recyclable;
     149             : }
     150             : 
     151             : static PushResult
     152       53295 : PushListNodeChildren(ParseNode* node, NodeStack* stack)
     153             : {
     154       53295 :     MOZ_ASSERT(node->isArity(PN_LIST));
     155       53295 :     node->checkListConsistency();
     156             : 
     157       53295 :     stack->pushList(node);
     158             : 
     159       53295 :     return PushResult::Recyclable;
     160             : }
     161             : 
     162             : static PushResult
     163        4637 : PushUnaryNodeChild(ParseNode* node, NodeStack* stack)
     164             : {
     165        4637 :     MOZ_ASSERT(node->isArity(PN_UNARY));
     166             : 
     167        4637 :     stack->push(node->pn_kid);
     168             : 
     169        4637 :     return PushResult::Recyclable;
     170             : }
     171             : 
     172             : /*
     173             :  * Push the children of |pn| on |stack|. Return true if |pn| itself could be
     174             :  * safely recycled, or false if it must be cleaned later (pn_used and pn_defn
     175             :  * nodes, and all function nodes; see comments for CleanFunctionList in
     176             :  * SemanticAnalysis.cpp). Some callers want to free |pn|; others
     177             :  * (js::ParseNodeAllocator::prepareNodeForMutation) don't care about |pn|, and
     178             :  * just need to take care of its children.
     179             :  */
     180             : static PushResult
     181      256399 : PushNodeChildren(ParseNode* pn, NodeStack* stack)
     182             : {
     183      256399 :     switch (pn->getKind()) {
     184             :       // Trivial nodes that refer to no nodes, are referred to by nothing
     185             :       // but their parents, are never used, and are never a definition.
     186             :       case PNK_NOP:
     187             :       case PNK_STRING:
     188             :       case PNK_TEMPLATE_STRING:
     189             :       case PNK_REGEXP:
     190             :       case PNK_TRUE:
     191             :       case PNK_FALSE:
     192             :       case PNK_NULL:
     193             :       case PNK_RAW_UNDEFINED:
     194             :       case PNK_ELISION:
     195             :       case PNK_GENERATOR:
     196             :       case PNK_NUMBER:
     197             :       case PNK_BREAK:
     198             :       case PNK_CONTINUE:
     199             :       case PNK_DEBUGGER:
     200             :       case PNK_EXPORT_BATCH_SPEC:
     201             :       case PNK_OBJECT_PROPERTY_NAME:
     202             :       case PNK_POSHOLDER:
     203       38108 :         MOZ_ASSERT(pn->isArity(PN_NULLARY));
     204       38108 :         return PushResult::Recyclable;
     205             : 
     206             :       // Nodes with a single non-null child.
     207             :       case PNK_TYPEOFNAME:
     208             :       case PNK_TYPEOFEXPR:
     209             :       case PNK_VOID:
     210             :       case PNK_NOT:
     211             :       case PNK_BITNOT:
     212             :       case PNK_THROW:
     213             :       case PNK_DELETENAME:
     214             :       case PNK_DELETEPROP:
     215             :       case PNK_DELETEELEM:
     216             :       case PNK_DELETEEXPR:
     217             :       case PNK_POS:
     218             :       case PNK_NEG:
     219             :       case PNK_PREINCREMENT:
     220             :       case PNK_POSTINCREMENT:
     221             :       case PNK_PREDECREMENT:
     222             :       case PNK_POSTDECREMENT:
     223             :       case PNK_COMPUTED_NAME:
     224             :       case PNK_ARRAYPUSH:
     225             :       case PNK_SPREAD:
     226             :       case PNK_MUTATEPROTO:
     227             :       case PNK_EXPORT:
     228             :       case PNK_SUPERBASE:
     229        4637 :         return PushUnaryNodeChild(pn, stack);
     230             : 
     231             :       // Nodes with a single nullable child.
     232             :       case PNK_THIS:
     233             :       case PNK_SEMI: {
     234       17204 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
     235       17204 :         if (pn->pn_kid)
     236       16460 :             stack->push(pn->pn_kid);
     237       17204 :         return PushResult::Recyclable;
     238             :       }
     239             : 
     240             :       // Binary nodes with two non-null children.
     241             : 
     242             :       // All assignment and compound assignment nodes qualify.
     243             :       case PNK_ASSIGN:
     244             :       case PNK_ADDASSIGN:
     245             :       case PNK_SUBASSIGN:
     246             :       case PNK_BITORASSIGN:
     247             :       case PNK_BITXORASSIGN:
     248             :       case PNK_BITANDASSIGN:
     249             :       case PNK_LSHASSIGN:
     250             :       case PNK_RSHASSIGN:
     251             :       case PNK_URSHASSIGN:
     252             :       case PNK_MULASSIGN:
     253             :       case PNK_DIVASSIGN:
     254             :       case PNK_MODASSIGN:
     255             :       case PNK_POWASSIGN:
     256             :       // ...and a few others.
     257             :       case PNK_ELEM:
     258             :       case PNK_IMPORT_SPEC:
     259             :       case PNK_EXPORT_SPEC:
     260             :       case PNK_COLON:
     261             :       case PNK_SHORTHAND:
     262             :       case PNK_DOWHILE:
     263             :       case PNK_WHILE:
     264             :       case PNK_SWITCH:
     265             :       case PNK_CLASSMETHOD:
     266             :       case PNK_NEWTARGET:
     267             :       case PNK_SETTHIS:
     268             :       case PNK_FOR:
     269             :       case PNK_COMPREHENSIONFOR:
     270             :       case PNK_WITH: {
     271       17277 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
     272       17277 :         stack->push(pn->pn_left);
     273       17277 :         stack->push(pn->pn_right);
     274       17277 :         return PushResult::Recyclable;
     275             :       }
     276             : 
     277             :       // Default clauses are PNK_CASE but do not have case expressions.
     278             :       // Named class expressions do not have outer binding nodes.
     279             :       // So both are binary nodes with a possibly-null pn_left.
     280             :       case PNK_CASE:
     281             :       case PNK_CLASSNAMES: {
     282         947 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
     283         947 :         if (pn->pn_left)
     284         901 :             stack->push(pn->pn_left);
     285         947 :         stack->push(pn->pn_right);
     286         947 :         return PushResult::Recyclable;
     287             :       }
     288             : 
     289             :       // The child is an assignment of a PNK_GENERATOR node to the
     290             :       // '.generator' local, for a synthesized, prepended initial yield.
     291             :       case PNK_INITIALYIELD: {
     292          96 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
     293          96 :         MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
     294             :                    pn->pn_kid->pn_left->isKind(PNK_NAME) &&
     295             :                    pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
     296          96 :         stack->push(pn->pn_kid);
     297          96 :         return PushResult::Recyclable;
     298             :       }
     299             : 
     300             :       // The child is the expression being yielded.
     301             :       case PNK_YIELD_STAR:
     302             :       case PNK_YIELD:
     303             :       case PNK_AWAIT: {
     304         192 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
     305         192 :         if (pn->pn_kid)
     306         192 :             stack->push(pn->pn_kid);
     307         192 :         return PushResult::Recyclable;
     308             :       }
     309             : 
     310             :       // A return node's child is what you'd expect: the return expression,
     311             :       // if any.
     312             :       case PNK_RETURN: {
     313        4971 :         MOZ_ASSERT(pn->isArity(PN_UNARY));
     314        4971 :         if (pn->pn_kid)
     315        4663 :             stack->push(pn->pn_kid);
     316        4971 :         return PushResult::Recyclable;
     317             :       }
     318             : 
     319             :       // Import and export-from nodes have a list of specifiers on the left
     320             :       // and a module string on the right.
     321             :       case PNK_IMPORT:
     322             :       case PNK_EXPORT_FROM: {
     323           0 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
     324           0 :         MOZ_ASSERT_IF(pn->isKind(PNK_IMPORT), pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST));
     325           0 :         MOZ_ASSERT_IF(pn->isKind(PNK_EXPORT_FROM), pn->pn_left->isKind(PNK_EXPORT_SPEC_LIST));
     326           0 :         MOZ_ASSERT(pn->pn_left->isArity(PN_LIST));
     327           0 :         MOZ_ASSERT(pn->pn_right->isKind(PNK_STRING));
     328           0 :         stack->pushList(pn->pn_left);
     329           0 :         stack->push(pn->pn_right);
     330           0 :         return PushResult::Recyclable;
     331             :       }
     332             : 
     333             :       case PNK_EXPORT_DEFAULT: {
     334           0 :         MOZ_ASSERT(pn->isArity(PN_BINARY));
     335           0 :         MOZ_ASSERT_IF(pn->pn_right, pn->pn_right->isKind(PNK_NAME));
     336           0 :         stack->push(pn->pn_left);
     337           0 :         if (pn->pn_right)
     338           0 :             stack->push(pn->pn_right);
     339           0 :         return PushResult::Recyclable;
     340             :       }
     341             : 
     342             :       // Ternary nodes with all children non-null.
     343             :       case PNK_CONDITIONAL: {
     344         569 :         MOZ_ASSERT(pn->isArity(PN_TERNARY));
     345         569 :         stack->push(pn->pn_kid1);
     346         569 :         stack->push(pn->pn_kid2);
     347         569 :         stack->push(pn->pn_kid3);
     348         569 :         return PushResult::Recyclable;
     349             :       }
     350             : 
     351             :       // For for-in and for-of, the first child is the left-hand side of the
     352             :       // 'in' or 'of' (a declaration or an assignment target). The second
     353             :       // child is always null, and the third child is the expression looped
     354             :       // over.  For example, in |for (var p in obj)|, the first child is |var
     355             :       // p|, the second child is null, and the third child is |obj|.
     356             :       case PNK_FORIN:
     357             :       case PNK_FOROF: {
     358         271 :         MOZ_ASSERT(pn->isArity(PN_TERNARY));
     359         271 :         MOZ_ASSERT(!pn->pn_kid2);
     360         271 :         stack->push(pn->pn_kid1);
     361         271 :         stack->push(pn->pn_kid3);
     362         271 :         return PushResult::Recyclable;
     363             :       }
     364             : 
     365             :       // for (;;) nodes have one child per optional component of the loop head.
     366             :       case PNK_FORHEAD: {
     367         412 :         MOZ_ASSERT(pn->isArity(PN_TERNARY));
     368         412 :         if (pn->pn_kid1)
     369         365 :             stack->push(pn->pn_kid1);
     370         412 :         if (pn->pn_kid2)
     371         403 :             stack->push(pn->pn_kid2);
     372         412 :         if (pn->pn_kid3)
     373         403 :             stack->push(pn->pn_kid3);
     374         412 :         return PushResult::Recyclable;
     375             :       }
     376             : 
     377             :       // classes might have an optional node for the heritage, as well as the names
     378             :       case PNK_CLASS: {
     379          32 :         MOZ_ASSERT(pn->isArity(PN_TERNARY));
     380          32 :         if (pn->pn_kid1)
     381          26 :             stack->push(pn->pn_kid1);
     382          32 :         if (pn->pn_kid2)
     383          16 :             stack->push(pn->pn_kid2);
     384          32 :         stack->push(pn->pn_kid3);
     385          32 :         return PushResult::Recyclable;
     386             :       }
     387             : 
     388             :       // if-statement nodes have condition and consequent children and a
     389             :       // possibly-null alternative.
     390             :       case PNK_IF: {
     391        5783 :         MOZ_ASSERT(pn->isArity(PN_TERNARY));
     392        5783 :         stack->push(pn->pn_kid1);
     393        5783 :         stack->push(pn->pn_kid2);
     394        5783 :         if (pn->pn_kid3)
     395         763 :             stack->push(pn->pn_kid3);
     396        5783 :         return PushResult::Recyclable;
     397             :       }
     398             : 
     399             :       // try-statements have statements to execute, and one or both of a
     400             :       // catch-list and a finally-block.
     401             :       case PNK_TRY: {
     402         389 :         MOZ_ASSERT(pn->isArity(PN_TERNARY));
     403         389 :         MOZ_ASSERT(pn->pn_kid2 || pn->pn_kid3);
     404         389 :         stack->push(pn->pn_kid1);
     405         389 :         if (pn->pn_kid2)
     406         373 :             stack->push(pn->pn_kid2);
     407         389 :         if (pn->pn_kid3)
     408          33 :             stack->push(pn->pn_kid3);
     409         389 :         return PushResult::Recyclable;
     410             :       }
     411             : 
     412             :       // A catch node has first kid as catch-variable pattern, the second kid
     413             :       // as catch condition (which, if non-null, records the |<cond>| in
     414             :       // SpiderMonkey's |catch (e if <cond>)| extension), and third kid as the
     415             :       // statements in the catch block.
     416             :       case PNK_CATCH: {
     417         373 :         MOZ_ASSERT(pn->isArity(PN_TERNARY));
     418         373 :         stack->push(pn->pn_kid1);
     419         373 :         if (pn->pn_kid2)
     420           0 :             stack->push(pn->pn_kid2);
     421         373 :         stack->push(pn->pn_kid3);
     422         373 :         return PushResult::Recyclable;
     423             :       }
     424             : 
     425             :       // List nodes with all non-null children.
     426             :       case PNK_OR:
     427             :       case PNK_AND:
     428             :       case PNK_BITOR:
     429             :       case PNK_BITXOR:
     430             :       case PNK_BITAND:
     431             :       case PNK_STRICTEQ:
     432             :       case PNK_EQ:
     433             :       case PNK_STRICTNE:
     434             :       case PNK_NE:
     435             :       case PNK_LT:
     436             :       case PNK_LE:
     437             :       case PNK_GT:
     438             :       case PNK_GE:
     439             :       case PNK_INSTANCEOF:
     440             :       case PNK_IN:
     441             :       case PNK_LSH:
     442             :       case PNK_RSH:
     443             :       case PNK_URSH:
     444             :       case PNK_ADD:
     445             :       case PNK_SUB:
     446             :       case PNK_STAR:
     447             :       case PNK_DIV:
     448             :       case PNK_MOD:
     449             :       case PNK_POW:
     450             :       case PNK_COMMA:
     451             :       case PNK_NEW:
     452             :       case PNK_CALL:
     453             :       case PNK_SUPERCALL:
     454             :       case PNK_GENEXP:
     455             :       case PNK_ARRAY:
     456             :       case PNK_OBJECT:
     457             :       case PNK_TEMPLATE_STRING_LIST:
     458             :       case PNK_TAGGED_TEMPLATE:
     459             :       case PNK_CALLSITEOBJ:
     460             :       case PNK_VAR:
     461             :       case PNK_CONST:
     462             :       case PNK_LET:
     463             :       case PNK_CATCHLIST:
     464             :       case PNK_STATEMENTLIST:
     465             :       case PNK_IMPORT_SPEC_LIST:
     466             :       case PNK_EXPORT_SPEC_LIST:
     467             :       case PNK_PARAMSBODY:
     468             :       case PNK_CLASSMETHODLIST:
     469       53295 :         return PushListNodeChildren(pn, stack);
     470             : 
     471             :       // Array comprehension nodes are lists with a single child:
     472             :       // PNK_COMPREHENSIONFOR for comprehensions, PNK_LEXICALSCOPE for legacy
     473             :       // comprehensions.  Probably this should be a non-list eventually.
     474             :       case PNK_ARRAYCOMP: {
     475             : #ifdef DEBUG
     476           0 :         MOZ_ASSERT(pn->isKind(PNK_ARRAYCOMP));
     477           0 :         MOZ_ASSERT(pn->isArity(PN_LIST));
     478           0 :         MOZ_ASSERT(pn->pn_count == 1);
     479           0 :         MOZ_ASSERT(pn->pn_head->isKind(PNK_LEXICALSCOPE) ||
     480             :                    pn->pn_head->isKind(PNK_COMPREHENSIONFOR));
     481             : #endif
     482           0 :         return PushListNodeChildren(pn, stack);
     483             :       }
     484             : 
     485             :       case PNK_LABEL:
     486             :       case PNK_DOT:
     487             :       case PNK_NAME:
     488       96631 :         return PushNameNodeChildren(pn, stack);
     489             : 
     490             :       case PNK_LEXICALSCOPE:
     491        9660 :         return PushScopeNodeChildren(pn, stack);
     492             : 
     493             :       case PNK_FUNCTION:
     494             :       case PNK_MODULE:
     495        5552 :         return PushCodeNodeChildren(pn, stack);
     496             : 
     497             :       case PNK_LIMIT: // invalid sentinel value
     498           0 :         MOZ_CRASH("invalid node kind");
     499             :     }
     500             : 
     501           0 :     MOZ_CRASH("bad ParseNodeKind");
     502             :     return PushResult::CleanUpLater;
     503             : }
     504             : 
     505             : /*
     506             :  * Prepare |pn| to be mutated in place into a new kind of node. Recycle all
     507             :  * |pn|'s recyclable children (but not |pn| itself!), and disconnect it from
     508             :  * metadata structures (the function box tree).
     509             :  */
     510             : void
     511         455 : ParseNodeAllocator::prepareNodeForMutation(ParseNode* pn)
     512             : {
     513             :     // Nothing to do for nullary nodes.
     514         455 :     if (pn->isArity(PN_NULLARY))
     515         141 :         return;
     516             : 
     517             :     // Put |pn|'s children (but not |pn| itself) on a work stack.
     518         314 :     NodeStack stack;
     519         314 :     PushNodeChildren(pn, &stack);
     520             : 
     521             :     // For each node on the work stack, push its children on the work stack,
     522             :     // and free the node if we can.
     523         996 :     while (!stack.empty()) {
     524         341 :         pn = stack.pop();
     525         341 :         if (PushNodeChildren(pn, &stack) == PushResult::Recyclable)
     526         341 :             freeNode(pn);
     527             :     }
     528             : }
     529             : 
     530             : /*
     531             :  * Return the nodes in the subtree |pn| to the parser's free node list, for
     532             :  * reallocation.
     533             :  */
     534             : ParseNode*
     535        3645 : ParseNodeAllocator::freeTree(ParseNode* pn)
     536             : {
     537        3645 :     if (!pn)
     538           0 :         return nullptr;
     539             : 
     540        3645 :     ParseNode* savedNext = pn->pn_next;
     541             : 
     542        3645 :     NodeStack stack;
     543             :     for (;;) {
     544      507843 :         if (PushNodeChildren(pn, &stack) == PushResult::Recyclable)
     545      250192 :             freeNode(pn);
     546      255744 :         if (stack.empty())
     547        3645 :             break;
     548      252099 :         pn = stack.pop();
     549             :     }
     550             : 
     551        3645 :     return savedNext;
     552             : }
     553             : 
     554             : /*
     555             :  * Allocate a ParseNode from parser's node freelist or, failing that, from
     556             :  * cx's temporary arena.
     557             :  */
     558             : void*
     559      310658 : ParseNodeAllocator::allocNode()
     560             : {
     561      310658 :     if (ParseNode* pn = freelist) {
     562         264 :         freelist = pn->pn_next;
     563         264 :         return pn;
     564             :     }
     565             : 
     566      620788 :     LifoAlloc::AutoFallibleScope fallibleAllocator(&alloc);
     567      310394 :     void* p = alloc.alloc(sizeof (ParseNode));
     568      310394 :     if (!p)
     569           0 :         ReportOutOfMemory(cx);
     570      310394 :     return p;
     571             : }
     572             : 
     573             : ParseNode*
     574       13783 : ParseNode::appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode* left, ParseNode* right,
     575             :                               FullParseHandler* handler, ParseContext* pc)
     576             : {
     577             :     // The asm.js specification is written in ECMAScript grammar terms that
     578             :     // specify *only* a binary tree.  It's a royal pain to implement the asm.js
     579             :     // spec to act upon n-ary lists as created below.  So for asm.js, form a
     580             :     // binary tree of lists exactly as ECMAScript would by skipping the
     581             :     // following optimization.
     582       13783 :     if (!pc->useAsmOrInsideUseAsm()) {
     583             :         // Left-associative trees of a given operator (e.g. |a + b + c|) are
     584             :         // binary trees in the spec: (+ (+ a b) c) in Lisp terms.  Recursively
     585             :         // processing such a tree, exactly implemented that way, would blow the
     586             :         // the stack.  We use a list node that uses O(1) stack to represent
     587             :         // such operations: (+ a b c).
     588             :         //
     589             :         // (**) is right-associative; per spec |a ** b ** c| parses as
     590             :         // (** a (** b c)). But we treat this the same way, creating a list
     591             :         // node: (** a b c). All consumers must understand that this must be
     592             :         // processed with a right fold, whereas the list (+ a b c) must be
     593             :         // processed with a left fold because (+) is left-associative.
     594             :         //
     595       30579 :         if (left->isKind(kind) &&
     596       19809 :             left->isOp(op) &&
     597        3013 :             (CodeSpec[op].format & JOF_LEFTASSOC ||
     598           0 :              (kind == PNK_POW && !left->pn_parens)))
     599             :         {
     600        3013 :             ListNode* list = &left->as<ListNode>();
     601             : 
     602        3013 :             list->append(right);
     603        3013 :             list->pn_pos.end = right->pn_pos.end;
     604             : 
     605        3013 :             return list;
     606             :         }
     607             :     }
     608             : 
     609       10770 :     ParseNode* list = handler->new_<ListNode>(kind, op, left);
     610       10770 :     if (!list)
     611           0 :         return nullptr;
     612             : 
     613       10770 :     list->append(right);
     614       10770 :     return list;
     615             : }
     616             : 
     617             : #ifdef DEBUG
     618             : 
     619             : static const char * const parseNodeNames[] = {
     620             : #define STRINGIFY(name) #name,
     621             :     FOR_EACH_PARSE_NODE_KIND(STRINGIFY)
     622             : #undef STRINGIFY
     623             : };
     624             : 
     625             : void
     626           0 : frontend::DumpParseTree(ParseNode* pn, int indent)
     627             : {
     628           0 :     if (pn == nullptr)
     629           0 :         fprintf(stderr, "#NULL");
     630             :     else
     631           0 :         pn->dump(indent);
     632           0 : }
     633             : 
     634             : static void
     635           0 : IndentNewLine(int indent)
     636             : {
     637           0 :     fputc('\n', stderr);
     638           0 :     for (int i = 0; i < indent; ++i)
     639           0 :         fputc(' ', stderr);
     640           0 : }
     641             : 
     642             : void
     643           0 : ParseNode::dump()
     644             : {
     645           0 :     dump(0);
     646           0 :     fputc('\n', stderr);
     647           0 : }
     648             : 
     649             : void
     650           0 : ParseNode::dump(int indent)
     651             : {
     652           0 :     switch (pn_arity) {
     653             :       case PN_NULLARY:
     654           0 :         ((NullaryNode*) this)->dump();
     655           0 :         break;
     656             :       case PN_UNARY:
     657           0 :         ((UnaryNode*) this)->dump(indent);
     658           0 :         break;
     659             :       case PN_BINARY:
     660           0 :         ((BinaryNode*) this)->dump(indent);
     661           0 :         break;
     662             :       case PN_TERNARY:
     663           0 :         ((TernaryNode*) this)->dump(indent);
     664           0 :         break;
     665             :       case PN_CODE:
     666           0 :         ((CodeNode*) this)->dump(indent);
     667           0 :         break;
     668             :       case PN_LIST:
     669           0 :         ((ListNode*) this)->dump(indent);
     670           0 :         break;
     671             :       case PN_NAME:
     672           0 :         ((NameNode*) this)->dump(indent);
     673           0 :         break;
     674             :       case PN_SCOPE:
     675           0 :         ((LexicalScopeNode*) this)->dump(indent);
     676           0 :         break;
     677             :       default:
     678           0 :         fprintf(stderr, "#<BAD NODE %p, kind=%u, arity=%u>",
     679           0 :                 (void*) this, unsigned(getKind()), unsigned(pn_arity));
     680           0 :         break;
     681             :     }
     682           0 : }
     683             : 
     684             : void
     685           0 : NullaryNode::dump()
     686             : {
     687           0 :     switch (getKind()) {
     688           0 :       case PNK_TRUE:  fprintf(stderr, "#true");  break;
     689           0 :       case PNK_FALSE: fprintf(stderr, "#false"); break;
     690           0 :       case PNK_NULL:  fprintf(stderr, "#null");  break;
     691           0 :       case PNK_RAW_UNDEFINED: fprintf(stderr, "#undefined"); break;
     692             : 
     693             :       case PNK_NUMBER: {
     694           0 :         ToCStringBuf cbuf;
     695           0 :         const char* cstr = NumberToCString(nullptr, &cbuf, pn_dval);
     696           0 :         if (!IsFinite(pn_dval))
     697           0 :             fputc('#', stderr);
     698           0 :         if (cstr)
     699           0 :             fprintf(stderr, "%s", cstr);
     700             :         else
     701           0 :             fprintf(stderr, "%g", pn_dval);
     702           0 :         break;
     703             :       }
     704             : 
     705             :       case PNK_STRING:
     706           0 :         pn_atom->dumpCharsNoNewline();
     707           0 :         break;
     708             : 
     709             :       default:
     710           0 :         fprintf(stderr, "(%s)", parseNodeNames[getKind()]);
     711             :     }
     712           0 : }
     713             : 
     714             : void
     715           0 : UnaryNode::dump(int indent)
     716             : {
     717           0 :     const char* name = parseNodeNames[getKind()];
     718           0 :     fprintf(stderr, "(%s ", name);
     719           0 :     indent += strlen(name) + 2;
     720           0 :     DumpParseTree(pn_kid, indent);
     721           0 :     fprintf(stderr, ")");
     722           0 : }
     723             : 
     724             : void
     725           0 : BinaryNode::dump(int indent)
     726             : {
     727           0 :     const char* name = parseNodeNames[getKind()];
     728           0 :     fprintf(stderr, "(%s ", name);
     729           0 :     indent += strlen(name) + 2;
     730           0 :     DumpParseTree(pn_left, indent);
     731           0 :     IndentNewLine(indent);
     732           0 :     DumpParseTree(pn_right, indent);
     733           0 :     fprintf(stderr, ")");
     734           0 : }
     735             : 
     736             : void
     737           0 : TernaryNode::dump(int indent)
     738             : {
     739           0 :     const char* name = parseNodeNames[getKind()];
     740           0 :     fprintf(stderr, "(%s ", name);
     741           0 :     indent += strlen(name) + 2;
     742           0 :     DumpParseTree(pn_kid1, indent);
     743           0 :     IndentNewLine(indent);
     744           0 :     DumpParseTree(pn_kid2, indent);
     745           0 :     IndentNewLine(indent);
     746           0 :     DumpParseTree(pn_kid3, indent);
     747           0 :     fprintf(stderr, ")");
     748           0 : }
     749             : 
     750             : void
     751           0 : CodeNode::dump(int indent)
     752             : {
     753           0 :     const char* name = parseNodeNames[getKind()];
     754           0 :     fprintf(stderr, "(%s ", name);
     755           0 :     indent += strlen(name) + 2;
     756           0 :     DumpParseTree(pn_body, indent);
     757           0 :     fprintf(stderr, ")");
     758           0 : }
     759             : 
     760             : void
     761           0 : ListNode::dump(int indent)
     762             : {
     763           0 :     const char* name = parseNodeNames[getKind()];
     764           0 :     fprintf(stderr, "(%s [", name);
     765           0 :     if (pn_head != nullptr) {
     766           0 :         indent += strlen(name) + 3;
     767           0 :         DumpParseTree(pn_head, indent);
     768           0 :         ParseNode* pn = pn_head->pn_next;
     769           0 :         while (pn != nullptr) {
     770           0 :             IndentNewLine(indent);
     771           0 :             DumpParseTree(pn, indent);
     772           0 :             pn = pn->pn_next;
     773             :         }
     774             :     }
     775           0 :     fprintf(stderr, "])");
     776           0 : }
     777             : 
     778             : template <typename CharT>
     779             : static void
     780           0 : DumpName(const CharT* s, size_t len)
     781             : {
     782           0 :     if (len == 0)
     783           0 :         fprintf(stderr, "#<zero-length name>");
     784             : 
     785           0 :     for (size_t i = 0; i < len; i++) {
     786           0 :         char16_t c = s[i];
     787           0 :         if (c > 32 && c < 127)
     788           0 :             fputc(c, stderr);
     789           0 :         else if (c <= 255)
     790           0 :             fprintf(stderr, "\\x%02x", unsigned(c));
     791             :         else
     792           0 :             fprintf(stderr, "\\u%04x", unsigned(c));
     793             :     }
     794           0 : }
     795             : 
     796             : void
     797           0 : NameNode::dump(int indent)
     798             : {
     799           0 :     if (isKind(PNK_NAME) || isKind(PNK_DOT)) {
     800           0 :         if (isKind(PNK_DOT))
     801           0 :             fprintf(stderr, "(.");
     802             : 
     803           0 :         if (!pn_atom) {
     804           0 :             fprintf(stderr, "#<null name>");
     805           0 :         } else if (getOp() == JSOP_GETARG && pn_atom->length() == 0) {
     806             :             // Dump destructuring parameter.
     807           0 :             fprintf(stderr, "(#<zero-length name> ");
     808           0 :             DumpParseTree(expr(), indent + 21);
     809           0 :             fputc(')', stderr);
     810             :         } else {
     811           0 :             JS::AutoCheckCannotGC nogc;
     812           0 :             if (pn_atom->hasLatin1Chars())
     813           0 :                 DumpName(pn_atom->latin1Chars(nogc), pn_atom->length());
     814             :             else
     815           0 :                 DumpName(pn_atom->twoByteChars(nogc), pn_atom->length());
     816             :         }
     817             : 
     818           0 :         if (isKind(PNK_DOT)) {
     819           0 :             fputc(' ', stderr);
     820           0 :             if (as<PropertyAccess>().isSuper())
     821           0 :                 fprintf(stderr, "super");
     822             :             else
     823           0 :                 DumpParseTree(expr(), indent + 2);
     824           0 :             fputc(')', stderr);
     825             :         }
     826           0 :         return;
     827             :     }
     828             : 
     829           0 :     const char* name = parseNodeNames[getKind()];
     830           0 :     fprintf(stderr, "(%s ", name);
     831           0 :     indent += strlen(name) + 2;
     832           0 :     DumpParseTree(expr(), indent);
     833           0 :     fprintf(stderr, ")");
     834             : }
     835             : 
     836             : void
     837           0 : LexicalScopeNode::dump(int indent)
     838             : {
     839           0 :     const char* name = parseNodeNames[getKind()];
     840           0 :     fprintf(stderr, "(%s [", name);
     841           0 :     int nameIndent = indent + strlen(name) + 3;
     842           0 :     if (!isEmptyScope()) {
     843           0 :         LexicalScope::Data* bindings = scopeBindings();
     844           0 :         for (uint32_t i = 0; i < bindings->length; i++) {
     845           0 :             JSAtom* name = bindings->names[i].name();
     846           0 :             JS::AutoCheckCannotGC nogc;
     847           0 :             if (name->hasLatin1Chars())
     848           0 :                 DumpName(name->latin1Chars(nogc), name->length());
     849             :             else
     850           0 :                 DumpName(name->twoByteChars(nogc), name->length());
     851           0 :             if (i < bindings->length - 1)
     852           0 :                 IndentNewLine(nameIndent);
     853             :         }
     854             :     }
     855           0 :     fprintf(stderr, "]");
     856           0 :     indent += 2;
     857           0 :     IndentNewLine(indent);
     858           0 :     DumpParseTree(scopeBody(), indent);
     859           0 :     fprintf(stderr, ")");
     860           0 : }
     861             : #endif
     862             : 
     863        2178 : ObjectBox::ObjectBox(JSObject* object, ObjectBox* traceLink)
     864             :   : object(object),
     865             :     traceLink(traceLink),
     866        2178 :     emitLink(nullptr)
     867             : {
     868        2178 :     MOZ_ASSERT(!object->is<JSFunction>());
     869        2178 :     MOZ_ASSERT(object->isTenured());
     870        2178 : }
     871             : 
     872        7633 : ObjectBox::ObjectBox(JSFunction* function, ObjectBox* traceLink)
     873             :   : object(function),
     874             :     traceLink(traceLink),
     875        7633 :     emitLink(nullptr)
     876             : {
     877        7633 :     MOZ_ASSERT(object->is<JSFunction>());
     878        7633 :     MOZ_ASSERT(asFunctionBox()->function() == function);
     879        7633 :     MOZ_ASSERT(object->isTenured());
     880        7633 : }
     881             : 
     882             : FunctionBox*
     883        7633 : ObjectBox::asFunctionBox()
     884             : {
     885        7633 :     MOZ_ASSERT(isFunctionBox());
     886        7633 :     return static_cast<FunctionBox*>(this);
     887             : }
     888             : 
     889             : /* static */ void
     890           0 : ObjectBox::TraceList(JSTracer* trc, ObjectBox* listHead)
     891             : {
     892           0 :     for (ObjectBox* box = listHead; box; box = box->traceLink)
     893           0 :         box->trace(trc);
     894           0 : }
     895             : 
     896             : void
     897           0 : ObjectBox::trace(JSTracer* trc)
     898             : {
     899           0 :     TraceRoot(trc, &object, "parser.object");
     900           0 : }
     901             : 
     902             : void
     903           0 : FunctionBox::trace(JSTracer* trc)
     904             : {
     905           0 :     ObjectBox::trace(trc);
     906           0 :     if (enclosingScope_)
     907           0 :         TraceRoot(trc, &enclosingScope_, "funbox-enclosingScope");
     908           0 : }
     909             : 
     910             : bool
     911       22880 : js::frontend::IsAnonymousFunctionDefinition(ParseNode* pn)
     912             : {
     913             :     // ES 2017 draft
     914             :     // 12.15.2 (ArrowFunction, AsyncArrowFunction).
     915             :     // 14.1.12 (FunctionExpression).
     916             :     // 14.4.8 (GeneratorExpression).
     917             :     // 14.6.8 (AsyncFunctionExpression)
     918       22880 :     if (pn->isKind(PNK_FUNCTION) && !pn->pn_funbox->function()->explicitName())
     919         485 :         return true;
     920             : 
     921             :     // 14.5.8 (ClassExpression)
     922       22395 :     if (pn->is<ClassNode>() && !pn->as<ClassNode>().names())
     923           6 :         return true;
     924             : 
     925       22389 :     return false;
     926             : }

Generated by: LCOV version 1.13