1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/frontend/ParseNode.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,767 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "frontend/ParseNode-inl.h" 1.11 + 1.12 +#include "frontend/Parser.h" 1.13 + 1.14 +#include "jscntxtinlines.h" 1.15 + 1.16 +using namespace js; 1.17 +using namespace js::frontend; 1.18 + 1.19 +using mozilla::IsFinite; 1.20 + 1.21 +/* 1.22 + * Asserts to verify assumptions behind pn_ macros. 1.23 + */ 1.24 +#define pn_offsetof(m) offsetof(ParseNode, m) 1.25 + 1.26 +JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses)); 1.27 + 1.28 +#undef pn_offsetof 1.29 + 1.30 +#ifdef DEBUG 1.31 +void 1.32 +ParseNode::checkListConsistency() 1.33 +{ 1.34 + JS_ASSERT(isArity(PN_LIST)); 1.35 + ParseNode **tail; 1.36 + uint32_t count = 0; 1.37 + if (pn_head) { 1.38 + ParseNode *pn, *last; 1.39 + for (pn = last = pn_head; pn; last = pn, pn = pn->pn_next, count++) 1.40 + ; 1.41 + tail = &last->pn_next; 1.42 + } else { 1.43 + tail = &pn_head; 1.44 + } 1.45 + JS_ASSERT(pn_tail == tail); 1.46 + JS_ASSERT(pn_count == count); 1.47 +} 1.48 +#endif 1.49 + 1.50 +/* Add |node| to |parser|'s free node list. */ 1.51 +void 1.52 +ParseNodeAllocator::freeNode(ParseNode *pn) 1.53 +{ 1.54 + /* Catch back-to-back dup recycles. */ 1.55 + JS_ASSERT(pn != freelist); 1.56 + 1.57 + /* 1.58 + * It's too hard to clear these nodes from the AtomDefnMaps, etc. that 1.59 + * hold references to them, so we never free them. It's our caller's job to 1.60 + * recognize and process these, since their children do need to be dealt 1.61 + * with. 1.62 + */ 1.63 + JS_ASSERT(!pn->isUsed()); 1.64 + JS_ASSERT(!pn->isDefn()); 1.65 + 1.66 +#ifdef DEBUG 1.67 + /* Poison the node, to catch attempts to use it without initializing it. */ 1.68 + memset(pn, 0xab, sizeof(*pn)); 1.69 +#endif 1.70 + 1.71 + pn->pn_next = freelist; 1.72 + freelist = pn; 1.73 +} 1.74 + 1.75 +namespace { 1.76 + 1.77 +/* 1.78 + * A work pool of ParseNodes. The work pool is a stack, chained together 1.79 + * by nodes' pn_next fields. We use this to avoid creating deep C++ stacks 1.80 + * when recycling deep parse trees. 1.81 + * 1.82 + * Since parse nodes are probably allocated in something close to the order 1.83 + * they appear in a depth-first traversal of the tree, making the work pool 1.84 + * a stack should give us pretty good locality. 1.85 + */ 1.86 +class NodeStack { 1.87 + public: 1.88 + NodeStack() : top(nullptr) { } 1.89 + bool empty() { return top == nullptr; } 1.90 + void push(ParseNode *pn) { 1.91 + pn->pn_next = top; 1.92 + top = pn; 1.93 + } 1.94 + void pushUnlessNull(ParseNode *pn) { if (pn) push(pn); } 1.95 + /* Push the children of the PN_LIST node |pn| on the stack. */ 1.96 + void pushList(ParseNode *pn) { 1.97 + /* This clobbers pn->pn_head if the list is empty; should be okay. */ 1.98 + *pn->pn_tail = top; 1.99 + top = pn->pn_head; 1.100 + } 1.101 + ParseNode *pop() { 1.102 + JS_ASSERT(!empty()); 1.103 + ParseNode *hold = top; /* my kingdom for a prog1 */ 1.104 + top = top->pn_next; 1.105 + return hold; 1.106 + } 1.107 + private: 1.108 + ParseNode *top; 1.109 +}; 1.110 + 1.111 +} /* anonymous namespace */ 1.112 + 1.113 +/* 1.114 + * Push the children of |pn| on |stack|. Return true if |pn| itself could be 1.115 + * safely recycled, or false if it must be cleaned later (pn_used and pn_defn 1.116 + * nodes, and all function nodes; see comments for CleanFunctionList in 1.117 + * SemanticAnalysis.cpp). Some callers want to free |pn|; others 1.118 + * (js::ParseNodeAllocator::prepareNodeForMutation) don't care about |pn|, and 1.119 + * just need to take care of its children. 1.120 + */ 1.121 +static bool 1.122 +PushNodeChildren(ParseNode *pn, NodeStack *stack) 1.123 +{ 1.124 + switch (pn->getArity()) { 1.125 + case PN_CODE: 1.126 + /* 1.127 + * Function nodes are linked into the function box tree, and may appear 1.128 + * on method lists. Both of those lists are singly-linked, so trying to 1.129 + * update them now could result in quadratic behavior when recycling 1.130 + * trees containing many functions; and the lists can be very long. So 1.131 + * we put off cleaning the lists up until just before function 1.132 + * analysis, when we call CleanFunctionList. 1.133 + * 1.134 + * In fact, we can't recycle the parse node yet, either: it may appear 1.135 + * on a method list, and reusing the node would corrupt that. Instead, 1.136 + * we clear its pn_funbox pointer to mark it as deleted; 1.137 + * CleanFunctionList recycles it as well. 1.138 + * 1.139 + * We do recycle the nodes around it, though, so we must clear pointers 1.140 + * to them to avoid leaving dangling references where someone can find 1.141 + * them. 1.142 + */ 1.143 + pn->pn_funbox = nullptr; 1.144 + stack->pushUnlessNull(pn->pn_body); 1.145 + pn->pn_body = nullptr; 1.146 + return false; 1.147 + 1.148 + case PN_NAME: 1.149 + /* 1.150 + * Because used/defn nodes appear in AtomDefnMaps and elsewhere, we 1.151 + * don't recycle them. (We'll recover their storage when we free the 1.152 + * temporary arena.) However, we do recycle the nodes around them, so 1.153 + * clean up the pointers to avoid dangling references. The top-level 1.154 + * decls table carries references to them that later iterations through 1.155 + * the compileScript loop may find, so they need to be neat. 1.156 + * 1.157 + * pn_expr and pn_lexdef share storage; the latter isn't an owning 1.158 + * reference. 1.159 + */ 1.160 + if (!pn->isUsed()) { 1.161 + stack->pushUnlessNull(pn->pn_expr); 1.162 + pn->pn_expr = nullptr; 1.163 + } 1.164 + return !pn->isUsed() && !pn->isDefn(); 1.165 + 1.166 + case PN_LIST: 1.167 + pn->checkListConsistency(); 1.168 + stack->pushList(pn); 1.169 + break; 1.170 + case PN_TERNARY: 1.171 + stack->pushUnlessNull(pn->pn_kid1); 1.172 + stack->pushUnlessNull(pn->pn_kid2); 1.173 + stack->pushUnlessNull(pn->pn_kid3); 1.174 + break; 1.175 + case PN_BINARY: 1.176 + case PN_BINARY_OBJ: 1.177 + if (pn->pn_left != pn->pn_right) 1.178 + stack->pushUnlessNull(pn->pn_left); 1.179 + stack->pushUnlessNull(pn->pn_right); 1.180 + break; 1.181 + case PN_UNARY: 1.182 + stack->pushUnlessNull(pn->pn_kid); 1.183 + break; 1.184 + case PN_NULLARY: 1.185 + return !pn->isUsed() && !pn->isDefn(); 1.186 + default: 1.187 + ; 1.188 + } 1.189 + 1.190 + return true; 1.191 +} 1.192 + 1.193 +/* 1.194 + * Prepare |pn| to be mutated in place into a new kind of node. Recycle all 1.195 + * |pn|'s recyclable children (but not |pn| itself!), and disconnect it from 1.196 + * metadata structures (the function box tree). 1.197 + */ 1.198 +void 1.199 +ParseNodeAllocator::prepareNodeForMutation(ParseNode *pn) 1.200 +{ 1.201 + if (!pn->isArity(PN_NULLARY)) { 1.202 + /* Put |pn|'s children (but not |pn| itself) on a work stack. */ 1.203 + NodeStack stack; 1.204 + PushNodeChildren(pn, &stack); 1.205 + /* 1.206 + * For each node on the work stack, push its children on the work stack, 1.207 + * and free the node if we can. 1.208 + */ 1.209 + while (!stack.empty()) { 1.210 + pn = stack.pop(); 1.211 + if (PushNodeChildren(pn, &stack)) 1.212 + freeNode(pn); 1.213 + } 1.214 + } 1.215 +} 1.216 + 1.217 +/* 1.218 + * Return the nodes in the subtree |pn| to the parser's free node list, for 1.219 + * reallocation. 1.220 + */ 1.221 +ParseNode * 1.222 +ParseNodeAllocator::freeTree(ParseNode *pn) 1.223 +{ 1.224 + if (!pn) 1.225 + return nullptr; 1.226 + 1.227 + ParseNode *savedNext = pn->pn_next; 1.228 + 1.229 + NodeStack stack; 1.230 + for (;;) { 1.231 + if (PushNodeChildren(pn, &stack)) 1.232 + freeNode(pn); 1.233 + if (stack.empty()) 1.234 + break; 1.235 + pn = stack.pop(); 1.236 + } 1.237 + 1.238 + return savedNext; 1.239 +} 1.240 + 1.241 +/* 1.242 + * Allocate a ParseNode from parser's node freelist or, failing that, from 1.243 + * cx's temporary arena. 1.244 + */ 1.245 +void * 1.246 +ParseNodeAllocator::allocNode() 1.247 +{ 1.248 + if (ParseNode *pn = freelist) { 1.249 + freelist = pn->pn_next; 1.250 + return pn; 1.251 + } 1.252 + 1.253 + void *p = alloc.alloc(sizeof (ParseNode)); 1.254 + if (!p) 1.255 + js_ReportOutOfMemory(cx); 1.256 + return p; 1.257 +} 1.258 + 1.259 +/* used only by static create methods of subclasses */ 1.260 + 1.261 +ParseNode * 1.262 +ParseNode::create(ParseNodeKind kind, ParseNodeArity arity, FullParseHandler *handler) 1.263 +{ 1.264 + const Token &tok = handler->currentToken(); 1.265 + return handler->new_<ParseNode>(kind, JSOP_NOP, arity, tok.pos); 1.266 +} 1.267 + 1.268 +ParseNode * 1.269 +ParseNode::append(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right, 1.270 + FullParseHandler *handler) 1.271 +{ 1.272 + if (!left || !right) 1.273 + return nullptr; 1.274 + 1.275 + JS_ASSERT(left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC)); 1.276 + 1.277 + ListNode *list; 1.278 + if (left->pn_arity == PN_LIST) { 1.279 + list = &left->as<ListNode>(); 1.280 + } else { 1.281 + ParseNode *pn1 = left->pn_left, *pn2 = left->pn_right; 1.282 + list = handler->new_<ListNode>(kind, op, pn1); 1.283 + if (!list) 1.284 + return nullptr; 1.285 + list->append(pn2); 1.286 + } 1.287 + 1.288 + list->append(right); 1.289 + list->pn_pos.end = right->pn_pos.end; 1.290 + 1.291 + return list; 1.292 +} 1.293 + 1.294 +ParseNode * 1.295 +ParseNode::newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right, 1.296 + FullParseHandler *handler, ParseContext<FullParseHandler> *pc, 1.297 + bool foldConstants) 1.298 +{ 1.299 + if (!left || !right) 1.300 + return nullptr; 1.301 + 1.302 + /* 1.303 + * Ensure that the parse tree is faithful to the source when "use asm" (for 1.304 + * the purpose of type checking). 1.305 + */ 1.306 + if (pc->useAsmOrInsideUseAsm()) 1.307 + return handler->new_<BinaryNode>(kind, op, left, right); 1.308 + 1.309 + /* 1.310 + * Flatten a left-associative (left-heavy) tree of a given operator into 1.311 + * a list to reduce js::FoldConstants and js::frontend::EmitTree recursion. 1.312 + */ 1.313 + if (left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC)) 1.314 + return append(kind, op, left, right, handler); 1.315 + 1.316 + return handler->new_<BinaryNode>(kind, op, left, right); 1.317 +} 1.318 + 1.319 +const char * 1.320 +Definition::kindString(Kind kind) 1.321 +{ 1.322 + static const char * const table[] = { 1.323 + "", js_var_str, js_const_str, js_let_str, js_function_str, "argument", "unknown" 1.324 + }; 1.325 + 1.326 + JS_ASSERT(unsigned(kind) <= unsigned(ARG)); 1.327 + return table[kind]; 1.328 +} 1.329 + 1.330 +namespace js { 1.331 +namespace frontend { 1.332 + 1.333 +/* 1.334 + * This function assumes the cloned tree is for use in the same statement and 1.335 + * binding context as the original tree. 1.336 + */ 1.337 +template <> 1.338 +ParseNode * 1.339 +Parser<FullParseHandler>::cloneParseTree(ParseNode *opn) 1.340 +{ 1.341 + JS_CHECK_RECURSION(context, return nullptr); 1.342 + 1.343 + ParseNode *pn = handler.new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(), 1.344 + opn->pn_pos); 1.345 + if (!pn) 1.346 + return nullptr; 1.347 + pn->setInParens(opn->isInParens()); 1.348 + pn->setDefn(opn->isDefn()); 1.349 + pn->setUsed(opn->isUsed()); 1.350 + 1.351 + switch (pn->getArity()) { 1.352 +#define NULLCHECK(e) JS_BEGIN_MACRO if (!(e)) return nullptr; JS_END_MACRO 1.353 + 1.354 + case PN_CODE: 1.355 + NULLCHECK(pn->pn_funbox = newFunctionBox(pn, opn->pn_funbox->function(), pc, 1.356 + Directives(/* strict = */ opn->pn_funbox->strict), 1.357 + opn->pn_funbox->generatorKind())); 1.358 + NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body)); 1.359 + pn->pn_cookie = opn->pn_cookie; 1.360 + pn->pn_dflags = opn->pn_dflags; 1.361 + pn->pn_blockid = opn->pn_blockid; 1.362 + break; 1.363 + 1.364 + case PN_LIST: 1.365 + pn->makeEmpty(); 1.366 + for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) { 1.367 + ParseNode *pn2; 1.368 + NULLCHECK(pn2 = cloneParseTree(opn2)); 1.369 + pn->append(pn2); 1.370 + } 1.371 + pn->pn_xflags = opn->pn_xflags; 1.372 + break; 1.373 + 1.374 + case PN_TERNARY: 1.375 + NULLCHECK(pn->pn_kid1 = cloneParseTree(opn->pn_kid1)); 1.376 + NULLCHECK(pn->pn_kid2 = cloneParseTree(opn->pn_kid2)); 1.377 + NULLCHECK(pn->pn_kid3 = cloneParseTree(opn->pn_kid3)); 1.378 + break; 1.379 + 1.380 + case PN_BINARY: 1.381 + NULLCHECK(pn->pn_left = cloneParseTree(opn->pn_left)); 1.382 + if (opn->pn_right != opn->pn_left) 1.383 + NULLCHECK(pn->pn_right = cloneParseTree(opn->pn_right)); 1.384 + else 1.385 + pn->pn_right = pn->pn_left; 1.386 + pn->pn_iflags = opn->pn_iflags; 1.387 + break; 1.388 + 1.389 + case PN_BINARY_OBJ: 1.390 + NULLCHECK(pn->pn_left = cloneParseTree(opn->pn_left)); 1.391 + if (opn->pn_right != opn->pn_left) 1.392 + NULLCHECK(pn->pn_right = cloneParseTree(opn->pn_right)); 1.393 + else 1.394 + pn->pn_right = pn->pn_left; 1.395 + pn->pn_binary_obj = opn->pn_binary_obj; 1.396 + break; 1.397 + 1.398 + case PN_UNARY: 1.399 + NULLCHECK(pn->pn_kid = cloneParseTree(opn->pn_kid)); 1.400 + break; 1.401 + 1.402 + case PN_NAME: 1.403 + // PN_NAME could mean several arms in pn_u, so copy the whole thing. 1.404 + pn->pn_u = opn->pn_u; 1.405 + if (opn->isUsed()) { 1.406 + /* 1.407 + * The old name is a use of its pn_lexdef. Make the clone also be a 1.408 + * use of that definition. 1.409 + */ 1.410 + Definition *dn = pn->pn_lexdef; 1.411 + 1.412 + pn->pn_link = dn->dn_uses; 1.413 + dn->dn_uses = pn; 1.414 + } else if (opn->pn_expr) { 1.415 + NULLCHECK(pn->pn_expr = cloneParseTree(opn->pn_expr)); 1.416 + 1.417 + /* 1.418 + * If the old name is a definition, the new one has pn_defn set. 1.419 + * Make the old name a use of the new node. 1.420 + */ 1.421 + if (opn->isDefn()) { 1.422 + opn->setDefn(false); 1.423 + handler.linkUseToDef(opn, (Definition *) pn); 1.424 + } 1.425 + } 1.426 + break; 1.427 + 1.428 + case PN_NULLARY: 1.429 + pn->pn_u = opn->pn_u; 1.430 + break; 1.431 + 1.432 +#undef NULLCHECK 1.433 + } 1.434 + return pn; 1.435 +} 1.436 + 1.437 +/* 1.438 + * Used by Parser::forStatement and comprehensionTail to clone the TARGET in 1.439 + * for (var/const/let TARGET in EXPR) 1.440 + * 1.441 + * opn must be the pn_head of a node produced by Parser::variables, so its form 1.442 + * is known to be LHS = NAME | [LHS] | {id:LHS}. 1.443 + * 1.444 + * The cloned tree is for use only in the same statement and binding context as 1.445 + * the original tree. 1.446 + */ 1.447 +template <> 1.448 +ParseNode * 1.449 +Parser<FullParseHandler>::cloneLeftHandSide(ParseNode *opn) 1.450 +{ 1.451 + ParseNode *pn = handler.new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(), 1.452 + opn->pn_pos); 1.453 + if (!pn) 1.454 + return nullptr; 1.455 + pn->setInParens(opn->isInParens()); 1.456 + pn->setDefn(opn->isDefn()); 1.457 + pn->setUsed(opn->isUsed()); 1.458 + 1.459 + if (opn->isArity(PN_LIST)) { 1.460 + JS_ASSERT(opn->isKind(PNK_ARRAY) || opn->isKind(PNK_OBJECT)); 1.461 + pn->makeEmpty(); 1.462 + for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) { 1.463 + ParseNode *pn2; 1.464 + if (opn->isKind(PNK_OBJECT)) { 1.465 + JS_ASSERT(opn2->isArity(PN_BINARY)); 1.466 + JS_ASSERT(opn2->isKind(PNK_COLON)); 1.467 + 1.468 + ParseNode *tag = cloneParseTree(opn2->pn_left); 1.469 + if (!tag) 1.470 + return nullptr; 1.471 + ParseNode *target = cloneLeftHandSide(opn2->pn_right); 1.472 + if (!target) 1.473 + return nullptr; 1.474 + 1.475 + pn2 = handler.new_<BinaryNode>(PNK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target); 1.476 + } else if (opn2->isArity(PN_NULLARY)) { 1.477 + JS_ASSERT(opn2->isKind(PNK_ELISION)); 1.478 + pn2 = cloneParseTree(opn2); 1.479 + } else { 1.480 + pn2 = cloneLeftHandSide(opn2); 1.481 + } 1.482 + 1.483 + if (!pn2) 1.484 + return nullptr; 1.485 + pn->append(pn2); 1.486 + } 1.487 + pn->pn_xflags = opn->pn_xflags; 1.488 + return pn; 1.489 + } 1.490 + 1.491 + JS_ASSERT(opn->isArity(PN_NAME)); 1.492 + JS_ASSERT(opn->isKind(PNK_NAME)); 1.493 + 1.494 + /* If opn is a definition or use, make pn a use. */ 1.495 + pn->pn_u.name = opn->pn_u.name; 1.496 + pn->setOp(JSOP_SETNAME); 1.497 + if (opn->isUsed()) { 1.498 + Definition *dn = pn->pn_lexdef; 1.499 + 1.500 + pn->pn_link = dn->dn_uses; 1.501 + dn->dn_uses = pn; 1.502 + } else { 1.503 + pn->pn_expr = nullptr; 1.504 + if (opn->isDefn()) { 1.505 + /* We copied some definition-specific state into pn. Clear it out. */ 1.506 + pn->pn_cookie.makeFree(); 1.507 + pn->pn_dflags &= ~PND_BOUND; 1.508 + pn->setDefn(false); 1.509 + 1.510 + handler.linkUseToDef(pn, (Definition *) opn); 1.511 + } 1.512 + } 1.513 + return pn; 1.514 +} 1.515 + 1.516 +} /* namespace frontend */ 1.517 +} /* namespace js */ 1.518 + 1.519 +#ifdef DEBUG 1.520 + 1.521 +static const char * const parseNodeNames[] = { 1.522 +#define STRINGIFY(name) #name, 1.523 + FOR_EACH_PARSE_NODE_KIND(STRINGIFY) 1.524 +#undef STRINGIFY 1.525 +}; 1.526 + 1.527 +void 1.528 +frontend::DumpParseTree(ParseNode *pn, int indent) 1.529 +{ 1.530 + if (pn == nullptr) 1.531 + fprintf(stderr, "#NULL"); 1.532 + else 1.533 + pn->dump(indent); 1.534 +} 1.535 + 1.536 +static void 1.537 +IndentNewLine(int indent) 1.538 +{ 1.539 + fputc('\n', stderr); 1.540 + for (int i = 0; i < indent; ++i) 1.541 + fputc(' ', stderr); 1.542 +} 1.543 + 1.544 +void 1.545 +ParseNode::dump() 1.546 +{ 1.547 + dump(0); 1.548 + fputc('\n', stderr); 1.549 +} 1.550 + 1.551 +void 1.552 +ParseNode::dump(int indent) 1.553 +{ 1.554 + switch (pn_arity) { 1.555 + case PN_NULLARY: 1.556 + ((NullaryNode *) this)->dump(); 1.557 + break; 1.558 + case PN_UNARY: 1.559 + ((UnaryNode *) this)->dump(indent); 1.560 + break; 1.561 + case PN_BINARY: 1.562 + ((BinaryNode *) this)->dump(indent); 1.563 + break; 1.564 + case PN_BINARY_OBJ: 1.565 + ((BinaryObjNode *) this)->dump(indent); 1.566 + break; 1.567 + case PN_TERNARY: 1.568 + ((TernaryNode *) this)->dump(indent); 1.569 + break; 1.570 + case PN_CODE: 1.571 + ((CodeNode *) this)->dump(indent); 1.572 + break; 1.573 + case PN_LIST: 1.574 + ((ListNode *) this)->dump(indent); 1.575 + break; 1.576 + case PN_NAME: 1.577 + ((NameNode *) this)->dump(indent); 1.578 + break; 1.579 + default: 1.580 + fprintf(stderr, "#<BAD NODE %p, kind=%u, arity=%u>", 1.581 + (void *) this, unsigned(getKind()), unsigned(pn_arity)); 1.582 + break; 1.583 + } 1.584 +} 1.585 + 1.586 +void 1.587 +NullaryNode::dump() 1.588 +{ 1.589 + switch (getKind()) { 1.590 + case PNK_TRUE: fprintf(stderr, "#true"); break; 1.591 + case PNK_FALSE: fprintf(stderr, "#false"); break; 1.592 + case PNK_NULL: fprintf(stderr, "#null"); break; 1.593 + 1.594 + case PNK_NUMBER: { 1.595 + ToCStringBuf cbuf; 1.596 + const char *cstr = NumberToCString(nullptr, &cbuf, pn_dval); 1.597 + if (!IsFinite(pn_dval)) 1.598 + fputc('#', stderr); 1.599 + if (cstr) 1.600 + fprintf(stderr, "%s", cstr); 1.601 + else 1.602 + fprintf(stderr, "%g", pn_dval); 1.603 + break; 1.604 + } 1.605 + 1.606 + case PNK_STRING: 1.607 + JSString::dumpChars(pn_atom->chars(), pn_atom->length()); 1.608 + break; 1.609 + 1.610 + default: 1.611 + fprintf(stderr, "(%s)", parseNodeNames[getKind()]); 1.612 + } 1.613 +} 1.614 + 1.615 +void 1.616 +UnaryNode::dump(int indent) 1.617 +{ 1.618 + const char *name = parseNodeNames[getKind()]; 1.619 + fprintf(stderr, "(%s ", name); 1.620 + indent += strlen(name) + 2; 1.621 + DumpParseTree(pn_kid, indent); 1.622 + fprintf(stderr, ")"); 1.623 +} 1.624 + 1.625 +void 1.626 +BinaryNode::dump(int indent) 1.627 +{ 1.628 + const char *name = parseNodeNames[getKind()]; 1.629 + fprintf(stderr, "(%s ", name); 1.630 + indent += strlen(name) + 2; 1.631 + DumpParseTree(pn_left, indent); 1.632 + IndentNewLine(indent); 1.633 + DumpParseTree(pn_right, indent); 1.634 + fprintf(stderr, ")"); 1.635 +} 1.636 + 1.637 +void 1.638 +BinaryObjNode::dump(int indent) 1.639 +{ 1.640 + const char *name = parseNodeNames[getKind()]; 1.641 + fprintf(stderr, "(%s ", name); 1.642 + indent += strlen(name) + 2; 1.643 + DumpParseTree(pn_left, indent); 1.644 + IndentNewLine(indent); 1.645 + DumpParseTree(pn_right, indent); 1.646 + fprintf(stderr, ")"); 1.647 +} 1.648 + 1.649 +void 1.650 +TernaryNode::dump(int indent) 1.651 +{ 1.652 + const char *name = parseNodeNames[getKind()]; 1.653 + fprintf(stderr, "(%s ", name); 1.654 + indent += strlen(name) + 2; 1.655 + DumpParseTree(pn_kid1, indent); 1.656 + IndentNewLine(indent); 1.657 + DumpParseTree(pn_kid2, indent); 1.658 + IndentNewLine(indent); 1.659 + DumpParseTree(pn_kid3, indent); 1.660 + fprintf(stderr, ")"); 1.661 +} 1.662 + 1.663 +void 1.664 +CodeNode::dump(int indent) 1.665 +{ 1.666 + const char *name = parseNodeNames[getKind()]; 1.667 + fprintf(stderr, "(%s ", name); 1.668 + indent += strlen(name) + 2; 1.669 + DumpParseTree(pn_body, indent); 1.670 + fprintf(stderr, ")"); 1.671 +} 1.672 + 1.673 +void 1.674 +ListNode::dump(int indent) 1.675 +{ 1.676 + const char *name = parseNodeNames[getKind()]; 1.677 + fprintf(stderr, "(%s [", name); 1.678 + if (pn_head != nullptr) { 1.679 + indent += strlen(name) + 3; 1.680 + DumpParseTree(pn_head, indent); 1.681 + ParseNode *pn = pn_head->pn_next; 1.682 + while (pn != nullptr) { 1.683 + IndentNewLine(indent); 1.684 + DumpParseTree(pn, indent); 1.685 + pn = pn->pn_next; 1.686 + } 1.687 + } 1.688 + fprintf(stderr, "])"); 1.689 +} 1.690 + 1.691 +void 1.692 +NameNode::dump(int indent) 1.693 +{ 1.694 + if (isKind(PNK_NAME) || isKind(PNK_DOT)) { 1.695 + if (isKind(PNK_DOT)) 1.696 + fprintf(stderr, "(."); 1.697 + 1.698 + if (!pn_atom) { 1.699 + fprintf(stderr, "#<null name>"); 1.700 + } else { 1.701 + const jschar *s = pn_atom->chars(); 1.702 + size_t len = pn_atom->length(); 1.703 + if (len == 0) 1.704 + fprintf(stderr, "#<zero-length name>"); 1.705 + for (size_t i = 0; i < len; i++) { 1.706 + if (s[i] > 32 && s[i] < 127) 1.707 + fputc(s[i], stderr); 1.708 + else if (s[i] <= 255) 1.709 + fprintf(stderr, "\\x%02x", (unsigned int) s[i]); 1.710 + else 1.711 + fprintf(stderr, "\\u%04x", (unsigned int) s[i]); 1.712 + } 1.713 + } 1.714 + 1.715 + if (isKind(PNK_DOT)) { 1.716 + fputc(' ', stderr); 1.717 + DumpParseTree(expr(), indent + 2); 1.718 + fputc(')', stderr); 1.719 + } 1.720 + return; 1.721 + } 1.722 + 1.723 + JS_ASSERT(!isUsed()); 1.724 + const char *name = parseNodeNames[getKind()]; 1.725 + if (isUsed()) 1.726 + fprintf(stderr, "(%s)", name); 1.727 + else { 1.728 + fprintf(stderr, "(%s ", name); 1.729 + indent += strlen(name) + 2; 1.730 + DumpParseTree(expr(), indent); 1.731 + fprintf(stderr, ")"); 1.732 + } 1.733 +} 1.734 +#endif 1.735 + 1.736 +ObjectBox::ObjectBox(JSObject *object, ObjectBox* traceLink) 1.737 + : object(object), 1.738 + traceLink(traceLink), 1.739 + emitLink(nullptr) 1.740 +{ 1.741 + JS_ASSERT(!object->is<JSFunction>()); 1.742 +} 1.743 + 1.744 +ObjectBox::ObjectBox(JSFunction *function, ObjectBox* traceLink) 1.745 + : object(function), 1.746 + traceLink(traceLink), 1.747 + emitLink(nullptr) 1.748 +{ 1.749 + JS_ASSERT(object->is<JSFunction>()); 1.750 + JS_ASSERT(asFunctionBox()->function() == function); 1.751 +} 1.752 + 1.753 +FunctionBox * 1.754 +ObjectBox::asFunctionBox() 1.755 +{ 1.756 + JS_ASSERT(isFunctionBox()); 1.757 + return static_cast<FunctionBox *>(this); 1.758 +} 1.759 + 1.760 +void 1.761 +ObjectBox::trace(JSTracer *trc) 1.762 +{ 1.763 + ObjectBox *box = this; 1.764 + while (box) { 1.765 + MarkObjectRoot(trc, &box->object, "parser.object"); 1.766 + if (box->isFunctionBox()) 1.767 + box->asFunctionBox()->bindings.trace(trc); 1.768 + box = box->traceLink; 1.769 + } 1.770 +}