js/src/frontend/ParseNode.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     7 #include "frontend/ParseNode-inl.h"
     9 #include "frontend/Parser.h"
    11 #include "jscntxtinlines.h"
    13 using namespace js;
    14 using namespace js::frontend;
    16 using mozilla::IsFinite;
    18 /*
    19  * Asserts to verify assumptions behind pn_ macros.
    20  */
    21 #define pn_offsetof(m)  offsetof(ParseNode, m)
    23 JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses));
    25 #undef pn_offsetof
    27 #ifdef DEBUG
    28 void
    29 ParseNode::checkListConsistency()
    30 {
    31     JS_ASSERT(isArity(PN_LIST));
    32     ParseNode **tail;
    33     uint32_t count = 0;
    34     if (pn_head) {
    35         ParseNode *pn, *last;
    36         for (pn = last = pn_head; pn; last = pn, pn = pn->pn_next, count++)
    37             ;
    38         tail = &last->pn_next;
    39     } else {
    40         tail = &pn_head;
    41     }
    42     JS_ASSERT(pn_tail == tail);
    43     JS_ASSERT(pn_count == count);
    44 }
    45 #endif
    47 /* Add |node| to |parser|'s free node list. */
    48 void
    49 ParseNodeAllocator::freeNode(ParseNode *pn)
    50 {
    51     /* Catch back-to-back dup recycles. */
    52     JS_ASSERT(pn != freelist);
    54     /*
    55      * It's too hard to clear these nodes from the AtomDefnMaps, etc. that
    56      * hold references to them, so we never free them. It's our caller's job to
    57      * recognize and process these, since their children do need to be dealt
    58      * with.
    59      */
    60     JS_ASSERT(!pn->isUsed());
    61     JS_ASSERT(!pn->isDefn());
    63 #ifdef DEBUG
    64     /* Poison the node, to catch attempts to use it without initializing it. */
    65     memset(pn, 0xab, sizeof(*pn));
    66 #endif
    68     pn->pn_next = freelist;
    69     freelist = pn;
    70 }
    72 namespace {
    74 /*
    75  * A work pool of ParseNodes. The work pool is a stack, chained together
    76  * by nodes' pn_next fields. We use this to avoid creating deep C++ stacks
    77  * when recycling deep parse trees.
    78  *
    79  * Since parse nodes are probably allocated in something close to the order
    80  * they appear in a depth-first traversal of the tree, making the work pool
    81  * a stack should give us pretty good locality.
    82  */
    83 class NodeStack {
    84   public:
    85     NodeStack() : top(nullptr) { }
    86     bool empty() { return top == nullptr; }
    87     void push(ParseNode *pn) {
    88         pn->pn_next = top;
    89         top = pn;
    90     }
    91     void pushUnlessNull(ParseNode *pn) { if (pn) push(pn); }
    92     /* Push the children of the PN_LIST node |pn| on the stack. */
    93     void pushList(ParseNode *pn) {
    94         /* This clobbers pn->pn_head if the list is empty; should be okay. */
    95         *pn->pn_tail = top;
    96         top = pn->pn_head;
    97     }
    98     ParseNode *pop() {
    99         JS_ASSERT(!empty());
   100         ParseNode *hold = top; /* my kingdom for a prog1 */
   101         top = top->pn_next;
   102         return hold;
   103     }
   104   private:
   105     ParseNode *top;
   106 };
   108 } /* anonymous namespace */
   110 /*
   111  * Push the children of |pn| on |stack|. Return true if |pn| itself could be
   112  * safely recycled, or false if it must be cleaned later (pn_used and pn_defn
   113  * nodes, and all function nodes; see comments for CleanFunctionList in
   114  * SemanticAnalysis.cpp). Some callers want to free |pn|; others
   115  * (js::ParseNodeAllocator::prepareNodeForMutation) don't care about |pn|, and
   116  * just need to take care of its children.
   117  */
   118 static bool
   119 PushNodeChildren(ParseNode *pn, NodeStack *stack)
   120 {
   121     switch (pn->getArity()) {
   122       case PN_CODE:
   123         /*
   124          * Function nodes are linked into the function box tree, and may appear
   125          * on method lists. Both of those lists are singly-linked, so trying to
   126          * update them now could result in quadratic behavior when recycling
   127          * trees containing many functions; and the lists can be very long. So
   128          * we put off cleaning the lists up until just before function
   129          * analysis, when we call CleanFunctionList.
   130          *
   131          * In fact, we can't recycle the parse node yet, either: it may appear
   132          * on a method list, and reusing the node would corrupt that. Instead,
   133          * we clear its pn_funbox pointer to mark it as deleted;
   134          * CleanFunctionList recycles it as well.
   135          *
   136          * We do recycle the nodes around it, though, so we must clear pointers
   137          * to them to avoid leaving dangling references where someone can find
   138          * them.
   139          */
   140         pn->pn_funbox = nullptr;
   141         stack->pushUnlessNull(pn->pn_body);
   142         pn->pn_body = nullptr;
   143         return false;
   145       case PN_NAME:
   146         /*
   147          * Because used/defn nodes appear in AtomDefnMaps and elsewhere, we
   148          * don't recycle them. (We'll recover their storage when we free the
   149          * temporary arena.) However, we do recycle the nodes around them, so
   150          * clean up the pointers to avoid dangling references. The top-level
   151          * decls table carries references to them that later iterations through
   152          * the compileScript loop may find, so they need to be neat.
   153          *
   154          * pn_expr and pn_lexdef share storage; the latter isn't an owning
   155          * reference.
   156          */
   157         if (!pn->isUsed()) {
   158             stack->pushUnlessNull(pn->pn_expr);
   159             pn->pn_expr = nullptr;
   160         }
   161         return !pn->isUsed() && !pn->isDefn();
   163       case PN_LIST:
   164         pn->checkListConsistency();
   165         stack->pushList(pn);
   166         break;
   167       case PN_TERNARY:
   168         stack->pushUnlessNull(pn->pn_kid1);
   169         stack->pushUnlessNull(pn->pn_kid2);
   170         stack->pushUnlessNull(pn->pn_kid3);
   171         break;
   172       case PN_BINARY:
   173       case PN_BINARY_OBJ:
   174         if (pn->pn_left != pn->pn_right)
   175             stack->pushUnlessNull(pn->pn_left);
   176         stack->pushUnlessNull(pn->pn_right);
   177         break;
   178       case PN_UNARY:
   179         stack->pushUnlessNull(pn->pn_kid);
   180         break;
   181       case PN_NULLARY:
   182         return !pn->isUsed() && !pn->isDefn();
   183       default:
   184         ;
   185     }
   187     return true;
   188 }
   190 /*
   191  * Prepare |pn| to be mutated in place into a new kind of node. Recycle all
   192  * |pn|'s recyclable children (but not |pn| itself!), and disconnect it from
   193  * metadata structures (the function box tree).
   194  */
   195 void
   196 ParseNodeAllocator::prepareNodeForMutation(ParseNode *pn)
   197 {
   198     if (!pn->isArity(PN_NULLARY)) {
   199         /* Put |pn|'s children (but not |pn| itself) on a work stack. */
   200         NodeStack stack;
   201         PushNodeChildren(pn, &stack);
   202         /*
   203          * For each node on the work stack, push its children on the work stack,
   204          * and free the node if we can.
   205          */
   206         while (!stack.empty()) {
   207             pn = stack.pop();
   208             if (PushNodeChildren(pn, &stack))
   209                 freeNode(pn);
   210         }
   211     }
   212 }
   214 /*
   215  * Return the nodes in the subtree |pn| to the parser's free node list, for
   216  * reallocation.
   217  */
   218 ParseNode *
   219 ParseNodeAllocator::freeTree(ParseNode *pn)
   220 {
   221     if (!pn)
   222         return nullptr;
   224     ParseNode *savedNext = pn->pn_next;
   226     NodeStack stack;
   227     for (;;) {
   228         if (PushNodeChildren(pn, &stack))
   229             freeNode(pn);
   230         if (stack.empty())
   231             break;
   232         pn = stack.pop();
   233     }
   235     return savedNext;
   236 }
   238 /*
   239  * Allocate a ParseNode from parser's node freelist or, failing that, from
   240  * cx's temporary arena.
   241  */
   242 void *
   243 ParseNodeAllocator::allocNode()
   244 {
   245     if (ParseNode *pn = freelist) {
   246         freelist = pn->pn_next;
   247         return pn;
   248     }
   250     void *p = alloc.alloc(sizeof (ParseNode));
   251     if (!p)
   252         js_ReportOutOfMemory(cx);
   253     return p;
   254 }
   256 /* used only by static create methods of subclasses */
   258 ParseNode *
   259 ParseNode::create(ParseNodeKind kind, ParseNodeArity arity, FullParseHandler *handler)
   260 {
   261     const Token &tok = handler->currentToken();
   262     return handler->new_<ParseNode>(kind, JSOP_NOP, arity, tok.pos);
   263 }
   265 ParseNode *
   266 ParseNode::append(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
   267                   FullParseHandler *handler)
   268 {
   269     if (!left || !right)
   270         return nullptr;
   272     JS_ASSERT(left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC));
   274     ListNode *list;
   275     if (left->pn_arity == PN_LIST) {
   276         list = &left->as<ListNode>();
   277     } else {
   278         ParseNode *pn1 = left->pn_left, *pn2 = left->pn_right;
   279         list = handler->new_<ListNode>(kind, op, pn1);
   280         if (!list)
   281             return nullptr;
   282         list->append(pn2);
   283     }
   285     list->append(right);
   286     list->pn_pos.end = right->pn_pos.end;
   288     return list;
   289 }
   291 ParseNode *
   292 ParseNode::newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
   293                              FullParseHandler *handler, ParseContext<FullParseHandler> *pc,
   294                              bool foldConstants)
   295 {
   296     if (!left || !right)
   297         return nullptr;
   299     /*
   300      * Ensure that the parse tree is faithful to the source when "use asm" (for
   301      * the purpose of type checking).
   302      */
   303     if (pc->useAsmOrInsideUseAsm())
   304         return handler->new_<BinaryNode>(kind, op, left, right);
   306     /*
   307      * Flatten a left-associative (left-heavy) tree of a given operator into
   308      * a list to reduce js::FoldConstants and js::frontend::EmitTree recursion.
   309      */
   310     if (left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC))
   311         return append(kind, op, left, right, handler);
   313     return handler->new_<BinaryNode>(kind, op, left, right);
   314 }
   316 const char *
   317 Definition::kindString(Kind kind)
   318 {
   319     static const char * const table[] = {
   320         "", js_var_str, js_const_str, js_let_str, js_function_str, "argument", "unknown"
   321     };
   323     JS_ASSERT(unsigned(kind) <= unsigned(ARG));
   324     return table[kind];
   325 }
   327 namespace js {
   328 namespace frontend {
   330 /*
   331  * This function assumes the cloned tree is for use in the same statement and
   332  * binding context as the original tree.
   333  */
   334 template <>
   335 ParseNode *
   336 Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
   337 {
   338     JS_CHECK_RECURSION(context, return nullptr);
   340     ParseNode *pn = handler.new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
   341                                             opn->pn_pos);
   342     if (!pn)
   343         return nullptr;
   344     pn->setInParens(opn->isInParens());
   345     pn->setDefn(opn->isDefn());
   346     pn->setUsed(opn->isUsed());
   348     switch (pn->getArity()) {
   349 #define NULLCHECK(e)    JS_BEGIN_MACRO if (!(e)) return nullptr; JS_END_MACRO
   351       case PN_CODE:
   352         NULLCHECK(pn->pn_funbox = newFunctionBox(pn, opn->pn_funbox->function(), pc,
   353                                                  Directives(/* strict = */ opn->pn_funbox->strict),
   354                                                  opn->pn_funbox->generatorKind()));
   355         NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body));
   356         pn->pn_cookie = opn->pn_cookie;
   357         pn->pn_dflags = opn->pn_dflags;
   358         pn->pn_blockid = opn->pn_blockid;
   359         break;
   361       case PN_LIST:
   362         pn->makeEmpty();
   363         for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
   364             ParseNode *pn2;
   365             NULLCHECK(pn2 = cloneParseTree(opn2));
   366             pn->append(pn2);
   367         }
   368         pn->pn_xflags = opn->pn_xflags;
   369         break;
   371       case PN_TERNARY:
   372         NULLCHECK(pn->pn_kid1 = cloneParseTree(opn->pn_kid1));
   373         NULLCHECK(pn->pn_kid2 = cloneParseTree(opn->pn_kid2));
   374         NULLCHECK(pn->pn_kid3 = cloneParseTree(opn->pn_kid3));
   375         break;
   377       case PN_BINARY:
   378         NULLCHECK(pn->pn_left = cloneParseTree(opn->pn_left));
   379         if (opn->pn_right != opn->pn_left)
   380             NULLCHECK(pn->pn_right = cloneParseTree(opn->pn_right));
   381         else
   382             pn->pn_right = pn->pn_left;
   383         pn->pn_iflags = opn->pn_iflags;
   384         break;
   386       case PN_BINARY_OBJ:
   387         NULLCHECK(pn->pn_left = cloneParseTree(opn->pn_left));
   388         if (opn->pn_right != opn->pn_left)
   389             NULLCHECK(pn->pn_right = cloneParseTree(opn->pn_right));
   390         else
   391             pn->pn_right = pn->pn_left;
   392         pn->pn_binary_obj = opn->pn_binary_obj;
   393         break;
   395       case PN_UNARY:
   396         NULLCHECK(pn->pn_kid = cloneParseTree(opn->pn_kid));
   397         break;
   399       case PN_NAME:
   400         // PN_NAME could mean several arms in pn_u, so copy the whole thing.
   401         pn->pn_u = opn->pn_u;
   402         if (opn->isUsed()) {
   403             /*
   404              * The old name is a use of its pn_lexdef. Make the clone also be a
   405              * use of that definition.
   406              */
   407             Definition *dn = pn->pn_lexdef;
   409             pn->pn_link = dn->dn_uses;
   410             dn->dn_uses = pn;
   411         } else if (opn->pn_expr) {
   412             NULLCHECK(pn->pn_expr = cloneParseTree(opn->pn_expr));
   414             /*
   415              * If the old name is a definition, the new one has pn_defn set.
   416              * Make the old name a use of the new node.
   417              */
   418             if (opn->isDefn()) {
   419                 opn->setDefn(false);
   420                 handler.linkUseToDef(opn, (Definition *) pn);
   421             }
   422         }
   423         break;
   425       case PN_NULLARY:
   426         pn->pn_u = opn->pn_u;
   427         break;
   429 #undef NULLCHECK
   430     }
   431     return pn;
   432 }
   434 /*
   435  * Used by Parser::forStatement and comprehensionTail to clone the TARGET in
   436  *   for (var/const/let TARGET in EXPR)
   437  *
   438  * opn must be the pn_head of a node produced by Parser::variables, so its form
   439  * is known to be LHS = NAME | [LHS] | {id:LHS}.
   440  *
   441  * The cloned tree is for use only in the same statement and binding context as
   442  * the original tree.
   443  */
   444 template <>
   445 ParseNode *
   446 Parser<FullParseHandler>::cloneLeftHandSide(ParseNode *opn)
   447 {
   448     ParseNode *pn = handler.new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
   449                                             opn->pn_pos);
   450     if (!pn)
   451         return nullptr;
   452     pn->setInParens(opn->isInParens());
   453     pn->setDefn(opn->isDefn());
   454     pn->setUsed(opn->isUsed());
   456     if (opn->isArity(PN_LIST)) {
   457         JS_ASSERT(opn->isKind(PNK_ARRAY) || opn->isKind(PNK_OBJECT));
   458         pn->makeEmpty();
   459         for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
   460             ParseNode *pn2;
   461             if (opn->isKind(PNK_OBJECT)) {
   462                 JS_ASSERT(opn2->isArity(PN_BINARY));
   463                 JS_ASSERT(opn2->isKind(PNK_COLON));
   465                 ParseNode *tag = cloneParseTree(opn2->pn_left);
   466                 if (!tag)
   467                     return nullptr;
   468                 ParseNode *target = cloneLeftHandSide(opn2->pn_right);
   469                 if (!target)
   470                     return nullptr;
   472                 pn2 = handler.new_<BinaryNode>(PNK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target);
   473             } else if (opn2->isArity(PN_NULLARY)) {
   474                 JS_ASSERT(opn2->isKind(PNK_ELISION));
   475                 pn2 = cloneParseTree(opn2);
   476             } else {
   477                 pn2 = cloneLeftHandSide(opn2);
   478             }
   480             if (!pn2)
   481                 return nullptr;
   482             pn->append(pn2);
   483         }
   484         pn->pn_xflags = opn->pn_xflags;
   485         return pn;
   486     }
   488     JS_ASSERT(opn->isArity(PN_NAME));
   489     JS_ASSERT(opn->isKind(PNK_NAME));
   491     /* If opn is a definition or use, make pn a use. */
   492     pn->pn_u.name = opn->pn_u.name;
   493     pn->setOp(JSOP_SETNAME);
   494     if (opn->isUsed()) {
   495         Definition *dn = pn->pn_lexdef;
   497         pn->pn_link = dn->dn_uses;
   498         dn->dn_uses = pn;
   499     } else {
   500         pn->pn_expr = nullptr;
   501         if (opn->isDefn()) {
   502             /* We copied some definition-specific state into pn. Clear it out. */
   503             pn->pn_cookie.makeFree();
   504             pn->pn_dflags &= ~PND_BOUND;
   505             pn->setDefn(false);
   507             handler.linkUseToDef(pn, (Definition *) opn);
   508         }
   509     }
   510     return pn;
   511 }
   513 } /* namespace frontend */
   514 } /* namespace js */
   516 #ifdef DEBUG
   518 static const char * const parseNodeNames[] = {
   519 #define STRINGIFY(name) #name,
   520     FOR_EACH_PARSE_NODE_KIND(STRINGIFY)
   521 #undef STRINGIFY
   522 };
   524 void
   525 frontend::DumpParseTree(ParseNode *pn, int indent)
   526 {
   527     if (pn == nullptr)
   528         fprintf(stderr, "#NULL");
   529     else
   530         pn->dump(indent);
   531 }
   533 static void
   534 IndentNewLine(int indent)
   535 {
   536     fputc('\n', stderr);
   537     for (int i = 0; i < indent; ++i)
   538         fputc(' ', stderr);
   539 }
   541 void
   542 ParseNode::dump()
   543 {
   544     dump(0);
   545     fputc('\n', stderr);
   546 }
   548 void
   549 ParseNode::dump(int indent)
   550 {
   551     switch (pn_arity) {
   552       case PN_NULLARY:
   553         ((NullaryNode *) this)->dump();
   554         break;
   555       case PN_UNARY:
   556         ((UnaryNode *) this)->dump(indent);
   557         break;
   558       case PN_BINARY:
   559         ((BinaryNode *) this)->dump(indent);
   560         break;
   561       case PN_BINARY_OBJ:
   562         ((BinaryObjNode *) this)->dump(indent);
   563         break;
   564       case PN_TERNARY:
   565         ((TernaryNode *) this)->dump(indent);
   566         break;
   567       case PN_CODE:
   568         ((CodeNode *) this)->dump(indent);
   569         break;
   570       case PN_LIST:
   571         ((ListNode *) this)->dump(indent);
   572         break;
   573       case PN_NAME:
   574         ((NameNode *) this)->dump(indent);
   575         break;
   576       default:
   577         fprintf(stderr, "#<BAD NODE %p, kind=%u, arity=%u>",
   578                 (void *) this, unsigned(getKind()), unsigned(pn_arity));
   579         break;
   580     }
   581 }
   583 void
   584 NullaryNode::dump()
   585 {
   586     switch (getKind()) {
   587       case PNK_TRUE:  fprintf(stderr, "#true");  break;
   588       case PNK_FALSE: fprintf(stderr, "#false"); break;
   589       case PNK_NULL:  fprintf(stderr, "#null");  break;
   591       case PNK_NUMBER: {
   592         ToCStringBuf cbuf;
   593         const char *cstr = NumberToCString(nullptr, &cbuf, pn_dval);
   594         if (!IsFinite(pn_dval))
   595             fputc('#', stderr);
   596         if (cstr)
   597             fprintf(stderr, "%s", cstr);
   598         else
   599             fprintf(stderr, "%g", pn_dval);
   600         break;
   601       }
   603       case PNK_STRING:
   604         JSString::dumpChars(pn_atom->chars(), pn_atom->length());
   605         break;
   607       default:
   608         fprintf(stderr, "(%s)", parseNodeNames[getKind()]);
   609     }
   610 }
   612 void
   613 UnaryNode::dump(int indent)
   614 {
   615     const char *name = parseNodeNames[getKind()];
   616     fprintf(stderr, "(%s ", name);
   617     indent += strlen(name) + 2;
   618     DumpParseTree(pn_kid, indent);
   619     fprintf(stderr, ")");
   620 }
   622 void
   623 BinaryNode::dump(int indent)
   624 {
   625     const char *name = parseNodeNames[getKind()];
   626     fprintf(stderr, "(%s ", name);
   627     indent += strlen(name) + 2;
   628     DumpParseTree(pn_left, indent);
   629     IndentNewLine(indent);
   630     DumpParseTree(pn_right, indent);
   631     fprintf(stderr, ")");
   632 }
   634 void
   635 BinaryObjNode::dump(int indent)
   636 {
   637     const char *name = parseNodeNames[getKind()];
   638     fprintf(stderr, "(%s ", name);
   639     indent += strlen(name) + 2;
   640     DumpParseTree(pn_left, indent);
   641     IndentNewLine(indent);
   642     DumpParseTree(pn_right, indent);
   643     fprintf(stderr, ")");
   644 }
   646 void
   647 TernaryNode::dump(int indent)
   648 {
   649     const char *name = parseNodeNames[getKind()];
   650     fprintf(stderr, "(%s ", name);
   651     indent += strlen(name) + 2;
   652     DumpParseTree(pn_kid1, indent);
   653     IndentNewLine(indent);
   654     DumpParseTree(pn_kid2, indent);
   655     IndentNewLine(indent);
   656     DumpParseTree(pn_kid3, indent);
   657     fprintf(stderr, ")");
   658 }
   660 void
   661 CodeNode::dump(int indent)
   662 {
   663     const char *name = parseNodeNames[getKind()];
   664     fprintf(stderr, "(%s ", name);
   665     indent += strlen(name) + 2;
   666     DumpParseTree(pn_body, indent);
   667     fprintf(stderr, ")");
   668 }
   670 void
   671 ListNode::dump(int indent)
   672 {
   673     const char *name = parseNodeNames[getKind()];
   674     fprintf(stderr, "(%s [", name);
   675     if (pn_head != nullptr) {
   676         indent += strlen(name) + 3;
   677         DumpParseTree(pn_head, indent);
   678         ParseNode *pn = pn_head->pn_next;
   679         while (pn != nullptr) {
   680             IndentNewLine(indent);
   681             DumpParseTree(pn, indent);
   682             pn = pn->pn_next;
   683         }
   684     }
   685     fprintf(stderr, "])");
   686 }
   688 void
   689 NameNode::dump(int indent)
   690 {
   691     if (isKind(PNK_NAME) || isKind(PNK_DOT)) {
   692         if (isKind(PNK_DOT))
   693             fprintf(stderr, "(.");
   695         if (!pn_atom) {
   696             fprintf(stderr, "#<null name>");
   697         } else {
   698             const jschar *s = pn_atom->chars();
   699             size_t len = pn_atom->length();
   700             if (len == 0)
   701                 fprintf(stderr, "#<zero-length name>");
   702             for (size_t i = 0; i < len; i++) {
   703                 if (s[i] > 32 && s[i] < 127)
   704                     fputc(s[i], stderr);
   705                 else if (s[i] <= 255)
   706                     fprintf(stderr, "\\x%02x", (unsigned int) s[i]);
   707                 else
   708                     fprintf(stderr, "\\u%04x", (unsigned int) s[i]);
   709             }
   710         }
   712         if (isKind(PNK_DOT)) {
   713             fputc(' ', stderr);
   714             DumpParseTree(expr(), indent + 2);
   715             fputc(')', stderr);
   716         }
   717         return;
   718     }
   720     JS_ASSERT(!isUsed());
   721     const char *name = parseNodeNames[getKind()];
   722     if (isUsed())
   723         fprintf(stderr, "(%s)", name);
   724     else {
   725         fprintf(stderr, "(%s ", name);
   726         indent += strlen(name) + 2;
   727         DumpParseTree(expr(), indent);
   728         fprintf(stderr, ")");
   729     }
   730 }
   731 #endif
   733 ObjectBox::ObjectBox(JSObject *object, ObjectBox* traceLink)
   734   : object(object),
   735     traceLink(traceLink),
   736     emitLink(nullptr)
   737 {
   738     JS_ASSERT(!object->is<JSFunction>());
   739 }
   741 ObjectBox::ObjectBox(JSFunction *function, ObjectBox* traceLink)
   742   : object(function),
   743     traceLink(traceLink),
   744     emitLink(nullptr)
   745 {
   746     JS_ASSERT(object->is<JSFunction>());
   747     JS_ASSERT(asFunctionBox()->function() == function);
   748 }
   750 FunctionBox *
   751 ObjectBox::asFunctionBox()
   752 {
   753     JS_ASSERT(isFunctionBox());
   754     return static_cast<FunctionBox *>(this);
   755 }
   757 void
   758 ObjectBox::trace(JSTracer *trc)
   759 {
   760     ObjectBox *box = this;
   761     while (box) {
   762         MarkObjectRoot(trc, &box->object, "parser.object");
   763         if (box->isFunctionBox())
   764             box->asFunctionBox()->bindings.trace(trc);
   765         box = box->traceLink;
   766     }
   767 }

mercurial