LCOV - code coverage report
Current view: directory - js/src/frontend - ParseNode.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 280 212 75.7 %
Date: 2012-06-02 Functions: 24 22 91.7 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=99:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla Communicator client code, released
      18                 :  * March 31, 1998.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  * Netscape Communications Corporation.
      22                 :  * Portions created by the Initial Developer are Copyright (C) 1998-2011
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "frontend/ParseNode.h"
      42                 : 
      43                 : #include "jsscriptinlines.h"
      44                 : 
      45                 : #include "frontend/ParseMaps-inl.h"
      46                 : #include "frontend/ParseNode-inl.h"
      47                 : 
      48                 : using namespace js;
      49                 : 
      50                 : /*
      51                 :  * Asserts to verify assumptions behind pn_ macros.
      52                 :  */
      53                 : #define pn_offsetof(m)  offsetof(ParseNode, m)
      54                 : 
      55                 : JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses));
      56                 : 
      57                 : #undef pn_offsetof
      58                 : 
      59                 : void
      60             331 : ParseNode::become(ParseNode *pn2)
      61                 : {
      62             331 :     JS_ASSERT(!pn_defn);
      63             331 :     JS_ASSERT(!pn2->isDefn());
      64                 : 
      65             331 :     JS_ASSERT(!pn_used);
      66             331 :     if (pn2->isUsed()) {
      67               0 :         ParseNode **pnup = &pn2->pn_lexdef->dn_uses;
      68               0 :         while (*pnup != pn2)
      69               0 :             pnup = &(*pnup)->pn_link;
      70               0 :         *pnup = this;
      71               0 :         pn_link = pn2->pn_link;
      72               0 :         pn_used = true;
      73               0 :         pn2->pn_link = NULL;
      74               0 :         pn2->pn_used = false;
      75                 :     }
      76                 : 
      77             331 :     pn_type = pn2->pn_type;
      78             331 :     pn_op = pn2->pn_op;
      79             331 :     pn_arity = pn2->pn_arity;
      80             331 :     pn_parens = pn2->pn_parens;
      81             331 :     pn_u = pn2->pn_u;
      82                 : 
      83                 :     /*
      84                 :      * If any pointers are pointing to pn2, change them to point to this
      85                 :      * instead, since pn2 will be cleared and probably recycled.
      86                 :      */
      87             331 :     if (this->isKind(PNK_FUNCTION) && isArity(PN_FUNC)) {
      88                 :         /* Function node: fix up the pn_funbox->node back-pointer. */
      89               9 :         JS_ASSERT(pn_funbox->node == pn2);
      90               9 :         pn_funbox->node = this;
      91             322 :     } else if (pn_arity == PN_LIST && !pn_head) {
      92                 :         /* Empty list: fix up the pn_tail pointer. */
      93              18 :         JS_ASSERT(pn_count == 0);
      94              18 :         JS_ASSERT(pn_tail == &pn2->pn_head);
      95              18 :         pn_tail = &pn_head;
      96                 :     }
      97                 : 
      98             331 :     pn2->clear();
      99             331 : }
     100                 : 
     101                 : void
     102             331 : ParseNode::clear()
     103                 : {
     104             331 :     pn_type = PNK_LIMIT;
     105             331 :     setOp(JSOP_NOP);
     106             331 :     pn_used = pn_defn = false;
     107             331 :     pn_arity = PN_NULLARY;
     108             331 :     pn_parens = false;
     109             331 : }
     110                 : 
     111                 : bool
     112               0 : FunctionBox::joinable() const
     113                 : {
     114               0 :     return function()->isNullClosure() &&
     115                 :            (tcflags & (TCF_FUN_USES_ARGUMENTS |
     116                 :                        TCF_FUN_USES_OWN_NAME |
     117               0 :                        TCF_COMPILE_N_GO)) == TCF_COMPILE_N_GO;
     118                 : }
     119                 : 
     120                 : bool
     121          900444 : FunctionBox::inAnyDynamicScope() const
     122                 : {
     123         2095732 :     for (const FunctionBox *funbox = this; funbox; funbox = funbox->parent) {
     124         1203774 :         if (funbox->tcflags & (TCF_IN_WITH | TCF_FUN_EXTENSIBLE_SCOPE))
     125            8486 :             return true;
     126                 :     }
     127          891958 :     return false;
     128                 : }
     129                 : 
     130                 : bool
     131          163731 : FunctionBox::scopeIsExtensible() const
     132                 : {
     133          163731 :     return tcflags & TCF_FUN_EXTENSIBLE_SCOPE;
     134                 : }
     135                 : 
     136                 : /* Add |node| to |parser|'s free node list. */
     137                 : void
     138        21828853 : ParseNodeAllocator::freeNode(ParseNode *pn)
     139                 : {
     140                 :     /* Catch back-to-back dup recycles. */
     141        21828853 :     JS_ASSERT(pn != freelist);
     142                 : 
     143                 :     /* 
     144                 :      * It's too hard to clear these nodes from the AtomDefnMaps, etc. that
     145                 :      * hold references to them, so we never free them. It's our caller's job to
     146                 :      * recognize and process these, since their children do need to be dealt
     147                 :      * with.
     148                 :      */
     149        21828853 :     JS_ASSERT(!pn->isUsed());
     150        21828853 :     JS_ASSERT(!pn->isDefn());
     151                 : 
     152        21828853 :     if (pn->isArity(PN_NAMESET) && pn->pn_names.hasMap())
     153               9 :         pn->pn_names.releaseMap(cx);
     154                 : 
     155                 : #ifdef DEBUG
     156                 :     /* Poison the node, to catch attempts to use it without initializing it. */
     157        21828853 :     memset(pn, 0xab, sizeof(*pn));
     158                 : #endif
     159                 : 
     160        21828853 :     pn->pn_next = freelist;
     161        21828853 :     freelist = pn;
     162        21828853 : }
     163                 : 
     164                 : /*
     165                 :  * A work pool of ParseNodes. The work pool is a stack, chained together
     166                 :  * by nodes' pn_next fields. We use this to avoid creating deep C++ stacks
     167                 :  * when recycling deep parse trees.
     168                 :  *
     169                 :  * Since parse nodes are probably allocated in something close to the order
     170                 :  * they appear in a depth-first traversal of the tree, making the work pool
     171                 :  * a stack should give us pretty good locality.
     172                 :  */
     173                 : class NodeStack {
     174                 :   public:
     175         1141794 :     NodeStack() : top(NULL) { }
     176        53550136 :     bool empty() { return top == NULL; }
     177        15271724 :     void push(ParseNode *pn) {
     178        15271724 :         pn->pn_next = top;
     179        15271724 :         top = pn;
     180        15271724 :     }
     181        15863436 :     void pushUnlessNull(ParseNode *pn) { if (pn) push(pn); }
     182                 :     /* Push the children of the PN_LIST node |pn| on the stack. */
     183         1335213 :     void pushList(ParseNode *pn) {
     184                 :         /* This clobbers pn->pn_head if the list is empty; should be okay. */
     185         1335213 :         *pn->pn_tail = top;
     186         1335213 :         top = pn->pn_head;
     187         1335213 :     }
     188        26204171 :     ParseNode *pop() {
     189        26204171 :         JS_ASSERT(!empty());
     190        26204171 :         ParseNode *hold = top; /* my kingdom for a prog1 */
     191        26204171 :         top = top->pn_next;
     192        26204171 :         return hold;
     193                 :     }
     194                 :   private:
     195                 :     ParseNode *top;
     196                 : };
     197                 : 
     198                 : /*
     199                 :  * Push the children of |pn| on |stack|. Return true if |pn| itself could be
     200                 :  * safely recycled, or false if it must be cleaned later (pn_used and pn_defn
     201                 :  * nodes, and all function nodes; see comments for CleanFunctionList in
     202                 :  * SemanticAnalysis.cpp). Some callers want to free |pn|; others
     203                 :  * (js::ParseNodeAllocator::prepareNodeForMutation) don't care about |pn|, and
     204                 :  * just need to take care of its children.
     205                 :  */
     206                 : static bool
     207        27345965 : PushNodeChildren(ParseNode *pn, NodeStack *stack)
     208                 : {
     209        27345965 :     switch (pn->getArity()) {
     210                 :       case PN_FUNC:
     211                 :         /*
     212                 :          * Function nodes are linked into the function box tree, and may appear
     213                 :          * on method lists. Both of those lists are singly-linked, so trying to
     214                 :          * update them now could result in quadratic behavior when recycling
     215                 :          * trees containing many functions; and the lists can be very long. So
     216                 :          * we put off cleaning the lists up until just before function
     217                 :          * analysis, when we call CleanFunctionList.
     218                 :          *
     219                 :          * In fact, we can't recycle the parse node yet, either: it may appear
     220                 :          * on a method list, and reusing the node would corrupt that. Instead,
     221                 :          * we clear its pn_funbox pointer to mark it as deleted;
     222                 :          * CleanFunctionList recycles it as well.
     223                 :          *
     224                 :          * We do recycle the nodes around it, though, so we must clear pointers
     225                 :          * to them to avoid leaving dangling references where someone can find
     226                 :          * them.
     227                 :          */
     228          769403 :         pn->pn_funbox = NULL;
     229          769403 :         stack->pushUnlessNull(pn->pn_body);
     230          769403 :         pn->pn_body = NULL;
     231          769403 :         return false;
     232                 : 
     233                 :       case PN_NAME:
     234                 :         /*
     235                 :          * Because used/defn nodes appear in AtomDefnMaps and elsewhere, we
     236                 :          * don't recycle them. (We'll recover their storage when we free the
     237                 :          * temporary arena.) However, we do recycle the nodes around them, so
     238                 :          * clean up the pointers to avoid dangling references. The top-level
     239                 :          * decls table carries references to them that later iterations through
     240                 :          * the compileScript loop may find, so they need to be neat.
     241                 :          *
     242                 :          * pn_expr and pn_lexdef share storage; the latter isn't an owning
     243                 :          * reference.
     244                 :          */
     245         7274514 :         if (!pn->isUsed()) {
     246         3187558 :             stack->pushUnlessNull(pn->pn_expr);
     247         3187558 :             pn->pn_expr = NULL;
     248                 :         }
     249         7274514 :         return !pn->isUsed() && !pn->isDefn();
     250                 : 
     251                 :       case PN_LIST:
     252         1335213 :         stack->pushList(pn);
     253         1335213 :         break;
     254                 :       case PN_TERNARY:
     255          194197 :         stack->pushUnlessNull(pn->pn_kid1);
     256          194197 :         stack->pushUnlessNull(pn->pn_kid2);
     257          194197 :         stack->pushUnlessNull(pn->pn_kid3);
     258          194197 :         break;
     259                 :       case PN_BINARY:
     260         4438142 :         if (pn->pn_left != pn->pn_right)
     261         4438115 :             stack->pushUnlessNull(pn->pn_left);
     262         4438142 :         stack->pushUnlessNull(pn->pn_right);
     263         4438142 :         break;
     264                 :       case PN_UNARY:
     265         2447627 :         stack->pushUnlessNull(pn->pn_kid);
     266         2447627 :         break;
     267                 :       case PN_NULLARY:
     268                 :         /* 
     269                 :          * E4X function namespace nodes are PN_NULLARY, but can appear on use
     270                 :          * lists.
     271                 :          */
     272        10305811 :         return !pn->isUsed() && !pn->isDefn();
     273                 :       default:
     274                 :         ;
     275                 :     }
     276                 : 
     277         8996237 :     return true;
     278                 : }
     279                 : 
     280                 : /*
     281                 :  * Prepare |pn| to be mutated in place into a new kind of node. Recycle all
     282                 :  * |pn|'s recyclable children (but not |pn| itself!), and disconnect it from
     283                 :  * metadata structures (the function box tree).
     284                 :  */
     285                 : void
     286            1608 : ParseNodeAllocator::prepareNodeForMutation(ParseNode *pn)
     287                 : {
     288            1608 :     if (!pn->isArity(PN_NULLARY)) {
     289              23 :         if (pn->isArity(PN_FUNC)) {
     290                 :             /*
     291                 :              * Since this node could be turned into anything, we can't
     292                 :              * ensure it won't be subsequently recycled, so we must
     293                 :              * disconnect it from the funbox tree entirely.
     294                 :              *
     295                 :              * Note that pn_funbox may legitimately be NULL. functionDef
     296                 :              * applies MakeDefIntoUse to definition nodes, which can come
     297                 :              * from prior iterations of the big loop in compileScript. In
     298                 :              * such cases, the defn nodes have been visited by the recycler
     299                 :              * (but not actually recycled!), and their funbox pointers
     300                 :              * cleared. But it's fine to mutate them into uses of some new
     301                 :              * definition.
     302                 :              */
     303              23 :             if (pn->pn_funbox)
     304               0 :                 pn->pn_funbox->node = NULL;
     305                 :         }
     306                 : 
     307                 :         /* Put |pn|'s children (but not |pn| itself) on a work stack. */
     308              23 :         NodeStack stack;
     309              23 :         PushNodeChildren(pn, &stack);
     310                 :         /*
     311                 :          * For each node on the work stack, push its children on the work stack,
     312                 :          * and free the node if we can.
     313                 :          */
     314              46 :         while (!stack.empty()) {
     315               0 :             pn = stack.pop();
     316               0 :             if (PushNodeChildren(pn, &stack))
     317               0 :                 freeNode(pn);
     318                 :         }
     319                 :     }
     320            1608 : }
     321                 : 
     322                 : /*
     323                 :  * Return the nodes in the subtree |pn| to the parser's free node list, for
     324                 :  * reallocation.
     325                 :  *
     326                 :  * Note that all functions in |pn| that are not enclosed by other functions
     327                 :  * in |pn| must be direct children of |tc|, because we only clean up |tc|'s
     328                 :  * function and method lists. You must not reach into a function and
     329                 :  * recycle some part of it (unless you've updated |tc|->functionList, the
     330                 :  * way js_FoldConstants does).
     331                 :  */
     332                 : ParseNode *
     333         1141819 : ParseNodeAllocator::freeTree(ParseNode *pn)
     334                 : {
     335         1141819 :     if (!pn)
     336              48 :         return NULL;
     337                 : 
     338         1141771 :     ParseNode *savedNext = pn->pn_next;
     339                 : 
     340         1141771 :     NodeStack stack;
     341        26204171 :     for (;;) {
     342        27345942 :         if (PushNodeChildren(pn, &stack))
     343        21828853 :             freeNode(pn);
     344        27345942 :         if (stack.empty())
     345                 :             break;
     346        26204171 :         pn = stack.pop();
     347                 :     }
     348                 : 
     349         1141771 :     return savedNext;
     350                 : }
     351                 : 
     352                 : /*
     353                 :  * Allocate a ParseNode from parser's node freelist or, failing that, from
     354                 :  * cx's temporary arena.
     355                 :  */
     356                 : void *
     357        80627913 : ParseNodeAllocator::allocNode()
     358                 : {
     359        80627913 :     if (ParseNode *pn = freelist) {
     360        20313938 :         freelist = pn->pn_next;
     361        20313938 :         return pn;
     362                 :     }
     363                 : 
     364        60313975 :     void *p = cx->tempLifoAlloc().alloc(sizeof (ParseNode));
     365        60313975 :     if (!p)
     366               0 :         js_ReportOutOfMemory(cx);
     367        60313975 :     return p;
     368                 : }
     369                 : 
     370                 : /* used only by static create methods of subclasses */
     371                 : 
     372                 : ParseNode *
     373        58615682 : ParseNode::create(ParseNodeKind kind, ParseNodeArity arity, TreeContext *tc)
     374                 : {
     375        58615682 :     Parser *parser = tc->parser;
     376        58615682 :     const Token &tok = parser->tokenStream.currentToken();
     377        58615682 :     return parser->new_<ParseNode>(kind, JSOP_NOP, arity, tok.pos);
     378                 : }
     379                 : 
     380                 : ParseNode *
     381         1986676 : ParseNode::append(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right)
     382                 : {
     383         1986676 :     if (!left || !right)
     384               0 :         return NULL;
     385                 : 
     386         1986676 :     JS_ASSERT(left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC));
     387                 : 
     388         1986676 :     if (left->pn_arity != PN_LIST) {
     389          216277 :         ParseNode *pn1 = left->pn_left, *pn2 = left->pn_right;
     390          216277 :         left->setArity(PN_LIST);
     391          216277 :         left->pn_parens = false;
     392          216277 :         left->initList(pn1);
     393          216277 :         left->append(pn2);
     394          216277 :         if (kind == PNK_ADD) {
     395          174368 :             if (pn1->isKind(PNK_STRING))
     396          152010 :                 left->pn_xflags |= PNX_STRCAT;
     397           22358 :             else if (!pn1->isKind(PNK_NUMBER))
     398           22318 :                 left->pn_xflags |= PNX_CANTFOLD;
     399          174368 :             if (pn2->isKind(PNK_STRING))
     400           40246 :                 left->pn_xflags |= PNX_STRCAT;
     401          134122 :             else if (!pn2->isKind(PNK_NUMBER))
     402          134075 :                 left->pn_xflags |= PNX_CANTFOLD;
     403                 :         }
     404                 :     }
     405         1986676 :     left->append(right);
     406         1986676 :     left->pn_pos.end = right->pn_pos.end;
     407         1986676 :     if (kind == PNK_ADD) {
     408         1925121 :         if (right->isKind(PNK_STRING))
     409          306165 :             left->pn_xflags |= PNX_STRCAT;
     410         1618956 :         else if (!right->isKind(PNK_NUMBER))
     411         1618861 :             left->pn_xflags |= PNX_CANTFOLD;
     412                 :     }
     413                 : 
     414         1986676 :     return left;
     415                 : }
     416                 : 
     417                 : ParseNode *
     418         6003185 : ParseNode::newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
     419                 :                              TreeContext *tc)
     420                 : {
     421         6003185 :     if (!left || !right)
     422               0 :         return NULL;
     423                 : 
     424                 :     /*
     425                 :      * Flatten a left-associative (left-heavy) tree of a given operator into
     426                 :      * a list to reduce js::FoldConstants and js::frontend::EmitTree recursion.
     427                 :      */
     428         6003185 :     if (left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC))
     429         1986676 :         return append(kind, op, left, right);
     430                 : 
     431                 :     /*
     432                 :      * Fold constant addition immediately, to conserve node space and, what's
     433                 :      * more, so js::FoldConstants never sees mixed addition and concatenation
     434                 :      * operations with more than one leading non-string operand in a PN_LIST
     435                 :      * generated for expressions such as 1 + 2 + "pt" (which should evaluate
     436                 :      * to "3pt", not "12pt").
     437                 :      */
     438         4387291 :     if (kind == PNK_ADD &&
     439          370023 :         left->isKind(PNK_NUMBER) &&
     440             759 :         right->isKind(PNK_NUMBER) &&
     441                 :         tc->parser->foldConstants)
     442                 :     {
     443             332 :         left->pn_dval += right->pn_dval;
     444             332 :         left->pn_pos.end = right->pn_pos.end;
     445             332 :         tc->freeTree(right);
     446             332 :         return left;
     447                 :     }
     448                 : 
     449         4016177 :     return tc->parser->new_<BinaryNode>(kind, op, left, right);
     450                 : }
     451                 : 
     452                 : NameNode *
     453        19814859 : NameNode::create(ParseNodeKind kind, JSAtom *atom, TreeContext *tc)
     454                 : {
     455        19814859 :     ParseNode *pn = ParseNode::create(kind, PN_NAME, tc);
     456        19814859 :     if (pn) {
     457        19814859 :         pn->pn_atom = atom;
     458        19814859 :         ((NameNode *)pn)->initCommon(tc);
     459                 :     }
     460        19814859 :     return (NameNode *)pn;
     461                 : }
     462                 : 
     463                 : const char js_argument_str[] = "argument";
     464                 : const char js_variable_str[] = "variable";
     465                 : const char js_unknown_str[]  = "unknown";
     466                 : 
     467                 : const char *
     468               5 : Definition::kindString(Kind kind)
     469                 : {
     470                 :     static const char *table[] = {
     471                 :         js_var_str, js_const_str, js_let_str,
     472                 :         js_function_str, js_argument_str, js_unknown_str
     473                 :     };
     474                 : 
     475               5 :     JS_ASSERT(unsigned(kind) <= unsigned(ARG));
     476               5 :     return table[kind];
     477                 : }
     478                 : 
     479                 : #if JS_HAS_DESTRUCTURING
     480                 : 
     481                 : /*
     482                 :  * This function assumes the cloned tree is for use in the same statement and
     483                 :  * binding context as the original tree.
     484                 :  */
     485                 : static ParseNode *
     486             276 : CloneParseTree(ParseNode *opn, TreeContext *tc)
     487                 : {
     488             276 :     JS_CHECK_RECURSION(tc->parser->context, return NULL);
     489                 : 
     490                 :     ParseNode *pn = tc->parser->new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
     491             276 :                                                 opn->pn_pos);
     492             276 :     if (!pn)
     493               0 :         return NULL;
     494             276 :     pn->setInParens(opn->isInParens());
     495             276 :     pn->setDefn(opn->isDefn());
     496             276 :     pn->setUsed(opn->isUsed());
     497                 : 
     498             276 :     switch (pn->getArity()) {
     499                 : #define NULLCHECK(e)    JS_BEGIN_MACRO if (!(e)) return NULL; JS_END_MACRO
     500                 : 
     501                 :       case PN_FUNC:
     502               0 :         NULLCHECK(pn->pn_funbox =
     503                 :                   tc->parser->newFunctionBox(opn->pn_funbox->object, pn, tc));
     504               0 :         NULLCHECK(pn->pn_body = CloneParseTree(opn->pn_body, tc));
     505               0 :         pn->pn_cookie = opn->pn_cookie;
     506               0 :         pn->pn_dflags = opn->pn_dflags;
     507               0 :         pn->pn_blockid = opn->pn_blockid;
     508               0 :         break;
     509                 : 
     510                 :       case PN_LIST:
     511               0 :         pn->makeEmpty();
     512               0 :         for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
     513                 :             ParseNode *pn2;
     514               0 :             NULLCHECK(pn2 = CloneParseTree(opn2, tc));
     515               0 :             pn->append(pn2);
     516                 :         }
     517               0 :         pn->pn_xflags = opn->pn_xflags;
     518               0 :         break;
     519                 : 
     520                 :       case PN_TERNARY:
     521               0 :         NULLCHECK(pn->pn_kid1 = CloneParseTree(opn->pn_kid1, tc));
     522               0 :         NULLCHECK(pn->pn_kid2 = CloneParseTree(opn->pn_kid2, tc));
     523               0 :         NULLCHECK(pn->pn_kid3 = CloneParseTree(opn->pn_kid3, tc));
     524               0 :         break;
     525                 : 
     526                 :       case PN_BINARY:
     527               0 :         NULLCHECK(pn->pn_left = CloneParseTree(opn->pn_left, tc));
     528               0 :         if (opn->pn_right != opn->pn_left)
     529               0 :             NULLCHECK(pn->pn_right = CloneParseTree(opn->pn_right, tc));
     530                 :         else
     531               0 :             pn->pn_right = pn->pn_left;
     532               0 :         pn->pn_pval = opn->pn_pval;
     533               0 :         pn->pn_iflags = opn->pn_iflags;
     534               0 :         break;
     535                 : 
     536                 :       case PN_UNARY:
     537               0 :         NULLCHECK(pn->pn_kid = CloneParseTree(opn->pn_kid, tc));
     538               0 :         pn->pn_hidden = opn->pn_hidden;
     539               0 :         break;
     540                 : 
     541                 :       case PN_NAME:
     542                 :         // PN_NAME could mean several arms in pn_u, so copy the whole thing.
     543               0 :         pn->pn_u = opn->pn_u;
     544               0 :         if (opn->isUsed()) {
     545                 :             /*
     546                 :              * The old name is a use of its pn_lexdef. Make the clone also be a
     547                 :              * use of that definition.
     548                 :              */
     549               0 :             Definition *dn = pn->pn_lexdef;
     550                 : 
     551               0 :             pn->pn_link = dn->dn_uses;
     552               0 :             dn->dn_uses = pn;
     553               0 :         } else if (opn->pn_expr) {
     554               0 :             NULLCHECK(pn->pn_expr = CloneParseTree(opn->pn_expr, tc));
     555                 : 
     556                 :             /*
     557                 :              * If the old name is a definition, the new one has pn_defn set.
     558                 :              * Make the old name a use of the new node.
     559                 :              */
     560               0 :             if (opn->isDefn()) {
     561               0 :                 opn->setDefn(false);
     562               0 :                 LinkUseToDef(opn, (Definition *) pn, tc);
     563                 :             }
     564                 :         }
     565               0 :         break;
     566                 : 
     567                 :       case PN_NAMESET:
     568               0 :         pn->pn_names = opn->pn_names;
     569               0 :         NULLCHECK(pn->pn_tree = CloneParseTree(opn->pn_tree, tc));
     570               0 :         break;
     571                 : 
     572                 :       case PN_NULLARY:
     573                 :         // Even PN_NULLARY may have data (xmlpi for E4X -- what a botch).
     574             276 :         pn->pn_u = opn->pn_u;
     575             276 :         break;
     576                 : 
     577                 : #undef NULLCHECK
     578                 :     }
     579             276 :     return pn;
     580                 : }
     581                 : 
     582                 : #endif /* JS_HAS_DESTRUCTURING */
     583                 : 
     584                 : /*
     585                 :  * Used by Parser::forStatement and comprehensionTail to clone the TARGET in
     586                 :  *   for (var/const/let TARGET in EXPR)
     587                 :  *
     588                 :  * opn must be the pn_head of a node produced by Parser::variables, so its form
     589                 :  * is known to be LHS = NAME | [LHS] | {id:LHS}.
     590                 :  *
     591                 :  * The cloned tree is for use only in the same statement and binding context as
     592                 :  * the original tree.
     593                 :  */
     594                 : ParseNode *
     595           58468 : js::CloneLeftHandSide(ParseNode *opn, TreeContext *tc)
     596                 : {
     597                 :     ParseNode *pn = tc->parser->new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
     598           58468 :                                                 opn->pn_pos);
     599           58468 :     if (!pn)
     600               0 :         return NULL;
     601           58468 :     pn->setInParens(opn->isInParens());
     602           58468 :     pn->setDefn(opn->isDefn());
     603           58468 :     pn->setUsed(opn->isUsed());
     604                 : 
     605                 : #if JS_HAS_DESTRUCTURING
     606           58468 :     if (opn->isArity(PN_LIST)) {
     607            3067 :         JS_ASSERT(opn->isKind(PNK_RB) || opn->isKind(PNK_RC));
     608            3067 :         pn->makeEmpty();
     609            9226 :         for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
     610                 :             ParseNode *pn2;
     611            6159 :             if (opn->isKind(PNK_RC)) {
     612             274 :                 JS_ASSERT(opn2->isArity(PN_BINARY));
     613             274 :                 JS_ASSERT(opn2->isKind(PNK_COLON));
     614                 : 
     615             274 :                 ParseNode *tag = CloneParseTree(opn2->pn_left, tc);
     616             274 :                 if (!tag)
     617               0 :                     return NULL;
     618             274 :                 ParseNode *target = CloneLeftHandSide(opn2->pn_right, tc);
     619             274 :                 if (!target)
     620               0 :                     return NULL;
     621                 : 
     622             274 :                 pn2 = tc->parser->new_<BinaryNode>(PNK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target);
     623            5885 :             } else if (opn2->isArity(PN_NULLARY)) {
     624               2 :                 JS_ASSERT(opn2->isKind(PNK_COMMA));
     625               2 :                 pn2 = CloneParseTree(opn2, tc);
     626                 :             } else {
     627            5883 :                 pn2 = CloneLeftHandSide(opn2, tc);
     628                 :             }
     629                 : 
     630            6159 :             if (!pn2)
     631               0 :                 return NULL;
     632            6159 :             pn->append(pn2);
     633                 :         }
     634            3067 :         pn->pn_xflags = opn->pn_xflags;
     635            3067 :         return pn;
     636                 :     }
     637                 : #endif
     638                 : 
     639           55401 :     JS_ASSERT(opn->isArity(PN_NAME));
     640           55401 :     JS_ASSERT(opn->isKind(PNK_NAME));
     641                 : 
     642                 :     /* If opn is a definition or use, make pn a use. */
     643           55401 :     pn->pn_u.name = opn->pn_u.name;
     644           55401 :     pn->setOp(JSOP_SETNAME);
     645           55401 :     if (opn->isUsed()) {
     646            1053 :         Definition *dn = pn->pn_lexdef;
     647                 : 
     648            1053 :         pn->pn_link = dn->dn_uses;
     649            1053 :         dn->dn_uses = pn;
     650                 :     } else {
     651           54348 :         pn->pn_expr = NULL;
     652           54348 :         if (opn->isDefn()) {
     653                 :             /* We copied some definition-specific state into pn. Clear it out. */
     654           54339 :             pn->pn_cookie.makeFree();
     655           54339 :             pn->pn_dflags &= ~PND_BOUND;
     656           54339 :             pn->setDefn(false);
     657                 : 
     658           54339 :             LinkUseToDef(pn, (Definition *) opn, tc);
     659                 :         }
     660                 :     }
     661           55401 :     return pn;
     662                 : }
     663                 : 
     664                 : #ifdef DEBUG
     665                 : void
     666               0 : js::DumpParseTree(ParseNode *pn, int indent)
     667                 : {
     668               0 :     if (pn == NULL) 
     669               0 :         fprintf(stderr, "()");
     670                 :     else
     671               0 :         pn->dump(indent);
     672               0 : }
     673                 : #endif

Generated by: LCOV version 1.7