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/NameFunctions.h"
8 :
9 : #include "mozilla/Sprintf.h"
10 :
11 : #include "jsfun.h"
12 : #include "jsprf.h"
13 :
14 : #include "frontend/BytecodeCompiler.h"
15 : #include "frontend/ParseNode.h"
16 : #include "frontend/SharedContext.h"
17 : #include "vm/StringBuffer.h"
18 :
19 : using namespace js;
20 : using namespace js::frontend;
21 :
22 : namespace {
23 :
24 : class NameResolver
25 : {
26 : static const size_t MaxParents = 100;
27 :
28 : JSContext* cx;
29 : size_t nparents; /* number of parents in the parents array */
30 : ParseNode* parents[MaxParents]; /* history of ParseNodes we've been looking at */
31 : StringBuffer* buf; /* when resolving, buffer to append to */
32 :
33 : /* Test whether a ParseNode represents a function invocation */
34 7622 : bool call(ParseNode* pn) {
35 7622 : return pn && pn->isKind(PNK_CALL);
36 : }
37 :
38 : /*
39 : * Append a reference to a property named |name| to |buf|. If |name| is
40 : * a proper identifier name, then we append '.name'; otherwise, we
41 : * append '["name"]'.
42 : *
43 : * Note that we need the IsIdentifier check for atoms from both
44 : * PNK_NAME nodes and PNK_STRING nodes: given code like a["b c"], the
45 : * front end will produce a PNK_DOT with a PNK_NAME child whose name
46 : * contains spaces.
47 : */
48 180 : bool appendPropertyReference(JSAtom* name) {
49 180 : if (IsIdentifier(name))
50 180 : return buf->append('.') && buf->append(name);
51 :
52 : /* Quote the string as needed. */
53 0 : JSString* source = QuoteString(cx, name, '"');
54 0 : return source && buf->append('[') && buf->append(source) && buf->append(']');
55 : }
56 :
57 : /* Append a number to buf. */
58 0 : bool appendNumber(double n) {
59 : char number[30];
60 0 : int digits = SprintfLiteral(number, "%g", n);
61 0 : return buf->append(number, digits);
62 : }
63 :
64 : /* Append "[<n>]" to buf, referencing a property named by a numeric literal. */
65 0 : bool appendNumericPropertyReference(double n) {
66 0 : return buf->append("[") && appendNumber(n) && buf->append(']');
67 : }
68 :
69 : /*
70 : * Walk over the given ParseNode, attempting to convert it to a stringified
71 : * name that respresents where the function is being assigned to.
72 : *
73 : * |*foundName| is set to true if a name is found for the expression.
74 : */
75 467 : bool nameExpression(ParseNode* n, bool* foundName) {
76 467 : switch (n->getKind()) {
77 : case PNK_DOT:
78 170 : if (!nameExpression(n->expr(), foundName))
79 0 : return false;
80 170 : if (!*foundName)
81 0 : return true;
82 170 : return appendPropertyReference(n->pn_atom);
83 :
84 : case PNK_NAME:
85 233 : *foundName = true;
86 233 : return buf->append(n->pn_atom);
87 :
88 : case PNK_THIS:
89 58 : *foundName = true;
90 58 : return buf->append("this");
91 :
92 : case PNK_ELEM:
93 5 : if (!nameExpression(n->pn_left, foundName))
94 0 : return false;
95 5 : if (!*foundName)
96 0 : return true;
97 5 : if (!buf->append('[') || !nameExpression(n->pn_right, foundName))
98 0 : return false;
99 5 : if (!*foundName)
100 0 : return true;
101 5 : return buf->append(']');
102 :
103 : case PNK_NUMBER:
104 0 : *foundName = true;
105 0 : return appendNumber(n->pn_dval);
106 :
107 : default:
108 : /* We're confused as to what to call this function. */
109 1 : *foundName = false;
110 1 : return true;
111 : }
112 : }
113 :
114 : /*
115 : * When naming an anonymous function, the process works loosely by walking
116 : * up the AST and then translating that to a string. The stringification
117 : * happens from some far-up assignment and then going back down the parse
118 : * tree to the function definition point.
119 : *
120 : * This function will walk up the parse tree, gathering relevant nodes used
121 : * for naming, and return the assignment node if there is one. The provided
122 : * array and size will be filled in, and the returned node could be nullptr
123 : * if no assignment is found. The first element of the array will be the
124 : * innermost node relevant to naming, and the last element will be the
125 : * outermost node.
126 : */
127 912 : ParseNode* gatherNameable(ParseNode** nameable, size_t* size) {
128 912 : *size = 0;
129 :
130 4295 : for (int pos = nparents - 1; pos >= 0; pos--) {
131 4083 : ParseNode* cur = parents[pos];
132 4083 : if (cur->isAssignment())
133 182 : return cur;
134 :
135 3901 : switch (cur->getKind()) {
136 105 : case PNK_NAME: return cur; /* found the initialized declaration */
137 0 : case PNK_THIS: return cur; /* Setting a property of 'this'. */
138 413 : case PNK_FUNCTION: return nullptr; /* won't find an assignment or declaration */
139 :
140 : case PNK_RETURN:
141 : /*
142 : * Normally the relevant parent of a node is its direct parent, but
143 : * sometimes with code like:
144 : *
145 : * var foo = (function() { return function() {}; })();
146 : *
147 : * the outer function is just a helper to create a scope for the
148 : * returned function. Hence the name of the returned function should
149 : * actually be 'foo'. This loop sees if the current node is a
150 : * PNK_RETURN, and if there is a direct function call we skip to
151 : * that.
152 : */
153 1030 : for (int tmp = pos - 1; tmp > 0; tmp--) {
154 905 : if (isDirectCall(tmp, cur)) {
155 0 : pos = tmp;
156 0 : break;
157 905 : } else if (call(cur)) {
158 : /* Don't skip too high in the tree */
159 9 : break;
160 : }
161 896 : cur = parents[tmp];
162 : }
163 134 : break;
164 :
165 : case PNK_COLON:
166 : case PNK_SHORTHAND:
167 : /*
168 : * Record the PNK_COLON/SHORTHAND but skip the PNK_OBJECT so we're not
169 : * flagged as a contributor.
170 : */
171 10 : pos--;
172 : MOZ_FALLTHROUGH;
173 :
174 : default:
175 : /* Save any other nodes we encounter on the way up. */
176 3249 : MOZ_ASSERT(*size < MaxParents);
177 3249 : nameable[(*size)++] = cur;
178 3249 : break;
179 : }
180 : }
181 :
182 212 : return nullptr;
183 : }
184 :
185 : /*
186 : * Resolve the name of a function. If the function already has a name
187 : * listed, then it is skipped. Otherwise an intelligent name is guessed to
188 : * assign to the function's displayAtom field.
189 : */
190 7234 : bool resolveFun(ParseNode* pn, HandleAtom prefix, MutableHandleAtom retAtom) {
191 7234 : MOZ_ASSERT(pn != nullptr);
192 7234 : MOZ_ASSERT(pn->isKind(PNK_FUNCTION));
193 7234 : MOZ_ASSERT(pn->isArity(PN_CODE));
194 14468 : RootedFunction fun(cx, pn->pn_funbox->function());
195 :
196 14468 : StringBuffer buf(cx);
197 7234 : this->buf = &buf;
198 :
199 7234 : retAtom.set(nullptr);
200 :
201 : /* If the function already has a name, use that */
202 7234 : if (fun->displayAtom() != nullptr) {
203 6322 : if (prefix == nullptr) {
204 5921 : retAtom.set(fun->displayAtom());
205 5921 : return true;
206 : }
207 1203 : if (!buf.append(prefix) ||
208 802 : !buf.append('/') ||
209 401 : !buf.append(fun->displayAtom()))
210 0 : return false;
211 401 : retAtom.set(buf.finishAtom());
212 401 : return !!retAtom;
213 : }
214 :
215 : /* If a prefix is specified, then it is a form of namespace */
216 912 : if (prefix != nullptr && (!buf.append(prefix) || !buf.append('/')))
217 0 : return false;
218 :
219 : /* Gather all nodes relevant to naming */
220 : ParseNode* toName[MaxParents];
221 : size_t size;
222 912 : ParseNode* assignment = gatherNameable(toName, &size);
223 :
224 : /* If the function is assigned to something, then that is very relevant */
225 912 : if (assignment) {
226 287 : if (assignment->isAssignment())
227 182 : assignment = assignment->pn_left;
228 287 : bool foundName = false;
229 287 : if (!nameExpression(assignment, &foundName))
230 1 : return false;
231 287 : if (!foundName)
232 1 : return true;
233 : }
234 :
235 : /*
236 : * Other than the actual assignment, other relevant nodes to naming are
237 : * those in object initializers and then particular nodes marking a
238 : * contribution.
239 : */
240 4159 : for (int pos = size - 1; pos >= 0; pos--) {
241 3248 : ParseNode* node = toName[pos];
242 :
243 3248 : if (node->isKind(PNK_COLON) || node->isKind(PNK_SHORTHAND)) {
244 10 : ParseNode* left = node->pn_left;
245 10 : if (left->isKind(PNK_OBJECT_PROPERTY_NAME) || left->isKind(PNK_STRING)) {
246 10 : if (!appendPropertyReference(left->pn_atom))
247 0 : return false;
248 0 : } else if (left->isKind(PNK_NUMBER)) {
249 0 : if (!appendNumericPropertyReference(left->pn_dval))
250 0 : return false;
251 : } else {
252 0 : MOZ_ASSERT(left->isKind(PNK_COMPUTED_NAME));
253 : }
254 : } else {
255 : /*
256 : * Don't have consecutive '<' characters, and also don't start
257 : * with a '<' character.
258 : */
259 3238 : if (!buf.empty() && buf.getChar(buf.length() - 1) != '<' && !buf.append('<'))
260 0 : return false;
261 : }
262 : }
263 :
264 : /*
265 : * functions which are "genuinely anonymous" but are contained in some
266 : * other namespace are rather considered as "contributing" to the outer
267 : * function, so give them a contribution symbol here.
268 : */
269 911 : if (!buf.empty() && buf.getChar(buf.length() - 1) == '/' && !buf.append('<'))
270 0 : return false;
271 :
272 911 : if (buf.empty())
273 228 : return true;
274 :
275 683 : retAtom.set(buf.finishAtom());
276 683 : if (!retAtom)
277 0 : return false;
278 683 : fun->setGuessedAtom(retAtom);
279 683 : return true;
280 : }
281 :
282 : /*
283 : * Tests whether parents[pos] is a function call whose callee is cur.
284 : * This is the case for functions which do things like simply create a scope
285 : * for new variables and then return an anonymous function using this scope.
286 : */
287 8139 : bool isDirectCall(int pos, ParseNode* cur) {
288 8139 : return pos >= 0 && call(parents[pos]) && parents[pos]->pn_head == cur;
289 : }
290 :
291 252 : bool resolveTemplateLiteral(ParseNode* node, HandleAtom prefix) {
292 252 : MOZ_ASSERT(node->isKind(PNK_TEMPLATE_STRING_LIST));
293 252 : ParseNode* element = node->pn_head;
294 602 : while (true) {
295 854 : MOZ_ASSERT(element->isKind(PNK_TEMPLATE_STRING));
296 :
297 854 : element = element->pn_next;
298 854 : if (!element)
299 252 : return true;
300 :
301 602 : if (!resolve(element, prefix))
302 0 : return false;
303 :
304 602 : element = element->pn_next;
305 : }
306 : }
307 :
308 1 : bool resolveTaggedTemplate(ParseNode* node, HandleAtom prefix) {
309 1 : MOZ_ASSERT(node->isKind(PNK_TAGGED_TEMPLATE));
310 :
311 1 : ParseNode* element = node->pn_head;
312 :
313 : // The list head is a leading expression, e.g. |tag| in |tag`foo`|,
314 : // that might contain functions.
315 1 : if (!resolve(element, prefix))
316 0 : return false;
317 :
318 : // Next is the callsite object node. This node only contains
319 : // internal strings or undefined and an array -- no user-controlled
320 : // expressions.
321 1 : element = element->pn_next;
322 : #ifdef DEBUG
323 : {
324 1 : MOZ_ASSERT(element->isKind(PNK_CALLSITEOBJ));
325 1 : ParseNode* array = element->pn_head;
326 1 : MOZ_ASSERT(array->isKind(PNK_ARRAY));
327 4 : for (ParseNode* kid = array->pn_head; kid; kid = kid->pn_next)
328 3 : MOZ_ASSERT(kid->isKind(PNK_TEMPLATE_STRING));
329 4 : for (ParseNode* next = array->pn_next; next; next = next->pn_next)
330 3 : MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING) || next->isKind(PNK_RAW_UNDEFINED));
331 : }
332 : #endif
333 :
334 : // Next come any interpolated expressions in the tagged template.
335 1 : ParseNode* interpolated = element->pn_next;
336 5 : for (; interpolated; interpolated = interpolated->pn_next) {
337 2 : if (!resolve(interpolated, prefix))
338 0 : return false;
339 : }
340 :
341 1 : return true;
342 : }
343 :
344 : public:
345 1691 : explicit NameResolver(JSContext* cx) : cx(cx), nparents(0), buf(nullptr) {}
346 :
347 : /*
348 : * Resolve all names for anonymous functions recursively within the
349 : * ParseNode instance given. The prefix is for each subsequent name, and
350 : * should initially be nullptr.
351 : */
352 389149 : bool resolve(ParseNode* cur, HandleAtom prefixArg = nullptr) {
353 778298 : RootedAtom prefix(cx, prefixArg);
354 389149 : if (cur == nullptr)
355 83907 : return true;
356 :
357 305242 : MOZ_ASSERT((cur->isKind(PNK_FUNCTION) || cur->isKind(PNK_MODULE)) == cur->isArity(PN_CODE));
358 305242 : if (cur->isKind(PNK_FUNCTION)) {
359 14468 : RootedAtom prefix2(cx);
360 7234 : if (!resolveFun(cur, prefix, &prefix2))
361 0 : return false;
362 :
363 : /*
364 : * If a function looks like (function(){})() where the parent node
365 : * of the definition of the function is a call, then it shouldn't
366 : * contribute anything to the namespace, so don't bother updating
367 : * the prefix to whatever was returned.
368 : */
369 7234 : if (!isDirectCall(nparents - 1, cur))
370 7188 : prefix = prefix2;
371 : }
372 305242 : if (nparents >= MaxParents)
373 0 : return true;
374 305242 : parents[nparents++] = cur;
375 :
376 305242 : switch (cur->getKind()) {
377 : // Nodes with no children that might require name resolution need no
378 : // further work.
379 : case PNK_NOP:
380 : case PNK_STRING:
381 : case PNK_TEMPLATE_STRING:
382 : case PNK_REGEXP:
383 : case PNK_TRUE:
384 : case PNK_FALSE:
385 : case PNK_NULL:
386 : case PNK_RAW_UNDEFINED:
387 : case PNK_ELISION:
388 : case PNK_GENERATOR:
389 : case PNK_NUMBER:
390 : case PNK_BREAK:
391 : case PNK_CONTINUE:
392 : case PNK_DEBUGGER:
393 : case PNK_EXPORT_BATCH_SPEC:
394 : case PNK_OBJECT_PROPERTY_NAME:
395 : case PNK_POSHOLDER:
396 37369 : MOZ_ASSERT(cur->isArity(PN_NULLARY));
397 37369 : break;
398 :
399 : case PNK_TYPEOFNAME:
400 : case PNK_SUPERBASE:
401 450 : MOZ_ASSERT(cur->isArity(PN_UNARY));
402 450 : MOZ_ASSERT(cur->pn_kid->isKind(PNK_NAME));
403 450 : MOZ_ASSERT(!cur->pn_kid->expr());
404 450 : break;
405 :
406 : case PNK_NEWTARGET:
407 12 : MOZ_ASSERT(cur->isArity(PN_BINARY));
408 12 : MOZ_ASSERT(cur->pn_left->isKind(PNK_POSHOLDER));
409 12 : MOZ_ASSERT(cur->pn_right->isKind(PNK_POSHOLDER));
410 12 : break;
411 :
412 : // Nodes with a single non-null child requiring name resolution.
413 : case PNK_TYPEOFEXPR:
414 : case PNK_VOID:
415 : case PNK_NOT:
416 : case PNK_BITNOT:
417 : case PNK_THROW:
418 : case PNK_DELETENAME:
419 : case PNK_DELETEPROP:
420 : case PNK_DELETEELEM:
421 : case PNK_DELETEEXPR:
422 : case PNK_NEG:
423 : case PNK_POS:
424 : case PNK_PREINCREMENT:
425 : case PNK_POSTINCREMENT:
426 : case PNK_PREDECREMENT:
427 : case PNK_POSTDECREMENT:
428 : case PNK_COMPUTED_NAME:
429 : case PNK_ARRAYPUSH:
430 : case PNK_SPREAD:
431 : case PNK_MUTATEPROTO:
432 : case PNK_EXPORT:
433 4355 : MOZ_ASSERT(cur->isArity(PN_UNARY));
434 4355 : if (!resolve(cur->pn_kid, prefix))
435 0 : return false;
436 4355 : break;
437 :
438 : // Nodes with a single nullable child.
439 : case PNK_SEMI:
440 : case PNK_THIS:
441 22044 : MOZ_ASSERT(cur->isArity(PN_UNARY));
442 22044 : if (ParseNode* expr = cur->pn_kid) {
443 21295 : if (!resolve(expr, prefix))
444 0 : return false;
445 : }
446 22044 : break;
447 :
448 : // Binary nodes with two non-null children.
449 : case PNK_ASSIGN:
450 : case PNK_ADDASSIGN:
451 : case PNK_SUBASSIGN:
452 : case PNK_BITORASSIGN:
453 : case PNK_BITXORASSIGN:
454 : case PNK_BITANDASSIGN:
455 : case PNK_LSHASSIGN:
456 : case PNK_RSHASSIGN:
457 : case PNK_URSHASSIGN:
458 : case PNK_MULASSIGN:
459 : case PNK_DIVASSIGN:
460 : case PNK_MODASSIGN:
461 : case PNK_POWASSIGN:
462 : case PNK_COLON:
463 : case PNK_SHORTHAND:
464 : case PNK_DOWHILE:
465 : case PNK_WHILE:
466 : case PNK_SWITCH:
467 : case PNK_FOR:
468 : case PNK_COMPREHENSIONFOR:
469 : case PNK_CLASSMETHOD:
470 : case PNK_SETTHIS:
471 16462 : MOZ_ASSERT(cur->isArity(PN_BINARY));
472 16462 : if (!resolve(cur->pn_left, prefix))
473 0 : return false;
474 16462 : if (!resolve(cur->pn_right, prefix))
475 0 : return false;
476 16462 : break;
477 :
478 : case PNK_ELEM:
479 2822 : MOZ_ASSERT(cur->isArity(PN_BINARY));
480 2822 : if (!cur->as<PropertyByValue>().isSuper() && !resolve(cur->pn_left, prefix))
481 0 : return false;
482 2822 : if (!resolve(cur->pn_right, prefix))
483 0 : return false;
484 2822 : break;
485 :
486 : case PNK_WITH:
487 0 : MOZ_ASSERT(cur->isArity(PN_BINARY));
488 0 : if (!resolve(cur->pn_left, prefix))
489 0 : return false;
490 0 : if (!resolve(cur->pn_right, prefix))
491 0 : return false;
492 0 : break;
493 :
494 : case PNK_CASE:
495 1114 : MOZ_ASSERT(cur->isArity(PN_BINARY));
496 1114 : if (ParseNode* caseExpr = cur->pn_left) {
497 1059 : if (!resolve(caseExpr, prefix))
498 0 : return false;
499 : }
500 1114 : if (!resolve(cur->pn_right, prefix))
501 0 : return false;
502 1114 : break;
503 :
504 : case PNK_INITIALYIELD:
505 127 : MOZ_ASSERT(cur->pn_kid->isKind(PNK_ASSIGN) &&
506 : cur->pn_kid->pn_left->isKind(PNK_NAME) &&
507 : cur->pn_kid->pn_right->isKind(PNK_GENERATOR));
508 127 : break;
509 :
510 : case PNK_YIELD_STAR:
511 3 : MOZ_ASSERT(cur->isArity(PN_UNARY));
512 3 : if (!resolve(cur->pn_kid, prefix))
513 0 : return false;
514 3 : break;
515 :
516 : case PNK_YIELD:
517 : case PNK_AWAIT:
518 250 : MOZ_ASSERT(cur->isArity(PN_UNARY));
519 250 : if (cur->pn_kid) {
520 250 : if (!resolve(cur->pn_kid, prefix))
521 0 : return false;
522 : }
523 250 : break;
524 :
525 : case PNK_RETURN:
526 6175 : MOZ_ASSERT(cur->isArity(PN_UNARY));
527 6175 : if (ParseNode* returnValue = cur->pn_kid) {
528 5677 : if (!resolve(returnValue, prefix))
529 0 : return false;
530 : }
531 6175 : break;
532 :
533 : case PNK_IMPORT:
534 : case PNK_EXPORT_FROM:
535 : case PNK_EXPORT_DEFAULT:
536 0 : MOZ_ASSERT(cur->isArity(PN_BINARY));
537 : // The left halves of these nodes don't contain any unconstrained
538 : // expressions, but it's very hard to assert this to safely rely on
539 : // it. So recur anyway.
540 0 : if (!resolve(cur->pn_left, prefix))
541 0 : return false;
542 0 : MOZ_ASSERT_IF(!cur->isKind(PNK_EXPORT_DEFAULT),
543 : cur->pn_right->isKind(PNK_STRING));
544 0 : break;
545 :
546 : // Ternary nodes with three expression children.
547 : case PNK_CONDITIONAL:
548 657 : MOZ_ASSERT(cur->isArity(PN_TERNARY));
549 657 : if (!resolve(cur->pn_kid1, prefix))
550 0 : return false;
551 657 : if (!resolve(cur->pn_kid2, prefix))
552 0 : return false;
553 657 : if (!resolve(cur->pn_kid3, prefix))
554 0 : return false;
555 657 : break;
556 :
557 : // The first part of a for-in/of is the declaration in the loop (or
558 : // null if no declaration). The latter two parts are the location
559 : // assigned each loop and the value being looped over; obviously,
560 : // either might contain functions to name. Declarations may (through
561 : // computed property names, and possibly through [deprecated!]
562 : // initializers) also contain functions to name.
563 : case PNK_FORIN:
564 : case PNK_FOROF:
565 372 : MOZ_ASSERT(cur->isArity(PN_TERNARY));
566 372 : if (ParseNode* decl = cur->pn_kid1) {
567 372 : if (!resolve(decl, prefix))
568 0 : return false;
569 : }
570 372 : if (!resolve(cur->pn_kid2, prefix))
571 0 : return false;
572 372 : if (!resolve(cur->pn_kid3, prefix))
573 0 : return false;
574 372 : break;
575 :
576 : // Every part of a for(;;) head may contain a function needing name
577 : // resolution.
578 : case PNK_FORHEAD:
579 441 : MOZ_ASSERT(cur->isArity(PN_TERNARY));
580 441 : if (ParseNode* init = cur->pn_kid1) {
581 394 : if (!resolve(init, prefix))
582 0 : return false;
583 : }
584 441 : if (ParseNode* cond = cur->pn_kid2) {
585 432 : if (!resolve(cond, prefix))
586 0 : return false;
587 : }
588 441 : if (ParseNode* step = cur->pn_kid3) {
589 432 : if (!resolve(step, prefix))
590 0 : return false;
591 : }
592 441 : break;
593 :
594 : // The first child of a class is a pair of names referring to it,
595 : // inside and outside the class. The second is the class's heritage,
596 : // if any. The third is the class body.
597 : case PNK_CLASS:
598 32 : MOZ_ASSERT(cur->isArity(PN_TERNARY));
599 32 : MOZ_ASSERT_IF(cur->pn_kid1, cur->pn_kid1->isKind(PNK_CLASSNAMES));
600 32 : MOZ_ASSERT_IF(cur->pn_kid1, cur->pn_kid1->isArity(PN_BINARY));
601 32 : MOZ_ASSERT_IF(cur->pn_kid1 && cur->pn_kid1->pn_left,
602 : cur->pn_kid1->pn_left->isKind(PNK_NAME));
603 32 : MOZ_ASSERT_IF(cur->pn_kid1 && cur->pn_kid1->pn_left,
604 : !cur->pn_kid1->pn_left->expr());
605 32 : MOZ_ASSERT_IF(cur->pn_kid1, cur->pn_kid1->pn_right->isKind(PNK_NAME));
606 32 : MOZ_ASSERT_IF(cur->pn_kid1, !cur->pn_kid1->pn_right->expr());
607 32 : if (cur->pn_kid2) {
608 16 : if (!resolve(cur->pn_kid2, prefix))
609 0 : return false;
610 : }
611 32 : if (!resolve(cur->pn_kid3, prefix))
612 0 : return false;
613 32 : break;
614 :
615 : // The condition and consequent are non-optional, but the alternative
616 : // might be omitted.
617 : case PNK_IF:
618 7045 : MOZ_ASSERT(cur->isArity(PN_TERNARY));
619 7045 : if (!resolve(cur->pn_kid1, prefix))
620 0 : return false;
621 7045 : if (!resolve(cur->pn_kid2, prefix))
622 0 : return false;
623 7045 : if (cur->pn_kid3) {
624 925 : if (!resolve(cur->pn_kid3, prefix))
625 0 : return false;
626 : }
627 7045 : break;
628 :
629 : // The statements in the try-block are mandatory. The catch-blocks
630 : // and finally block are optional (but at least one or the other must
631 : // be present).
632 : case PNK_TRY:
633 490 : MOZ_ASSERT(cur->isArity(PN_TERNARY));
634 490 : if (!resolve(cur->pn_kid1, prefix))
635 0 : return false;
636 490 : MOZ_ASSERT(cur->pn_kid2 || cur->pn_kid3);
637 490 : if (ParseNode* catchList = cur->pn_kid2) {
638 468 : MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST));
639 468 : if (!resolve(catchList, prefix))
640 0 : return false;
641 : }
642 490 : if (ParseNode* finallyBlock = cur->pn_kid3) {
643 41 : if (!resolve(finallyBlock, prefix))
644 0 : return false;
645 : }
646 490 : break;
647 :
648 : // The first child, the catch-pattern, may contain functions via
649 : // computed property names. The optional catch-conditions may
650 : // contain any expression. The catch statements, of course, may
651 : // contain arbitrary expressions.
652 : case PNK_CATCH:
653 468 : MOZ_ASSERT(cur->isArity(PN_TERNARY));
654 468 : if (!resolve(cur->pn_kid1, prefix))
655 0 : return false;
656 468 : if (cur->pn_kid2) {
657 0 : if (!resolve(cur->pn_kid2, prefix))
658 0 : return false;
659 : }
660 468 : if (!resolve(cur->pn_kid3, prefix))
661 0 : return false;
662 468 : break;
663 :
664 : // Nodes with arbitrary-expression children.
665 : case PNK_OR:
666 : case PNK_AND:
667 : case PNK_BITOR:
668 : case PNK_BITXOR:
669 : case PNK_BITAND:
670 : case PNK_STRICTEQ:
671 : case PNK_EQ:
672 : case PNK_STRICTNE:
673 : case PNK_NE:
674 : case PNK_LT:
675 : case PNK_LE:
676 : case PNK_GT:
677 : case PNK_GE:
678 : case PNK_INSTANCEOF:
679 : case PNK_IN:
680 : case PNK_LSH:
681 : case PNK_RSH:
682 : case PNK_URSH:
683 : case PNK_ADD:
684 : case PNK_SUB:
685 : case PNK_STAR:
686 : case PNK_DIV:
687 : case PNK_MOD:
688 : case PNK_POW:
689 : case PNK_COMMA:
690 : case PNK_NEW:
691 : case PNK_CALL:
692 : case PNK_SUPERCALL:
693 : case PNK_GENEXP:
694 : case PNK_ARRAY:
695 : case PNK_STATEMENTLIST:
696 : case PNK_PARAMSBODY:
697 : // Initializers for individual variables, and computed property names
698 : // within destructuring patterns, may contain unnamed functions.
699 : case PNK_VAR:
700 : case PNK_CONST:
701 : case PNK_LET:
702 62115 : MOZ_ASSERT(cur->isArity(PN_LIST));
703 206411 : for (ParseNode* element = cur->pn_head; element; element = element->pn_next) {
704 144296 : if (!resolve(element, prefix))
705 0 : return false;
706 : }
707 62115 : break;
708 :
709 : // Array comprehension nodes are lists with a single child:
710 : // PNK_COMPREHENSIONFOR for comprehensions, PNK_LEXICALSCOPE for
711 : // legacy comprehensions. Probably this should be a non-list
712 : // eventually.
713 : case PNK_ARRAYCOMP:
714 0 : MOZ_ASSERT(cur->isArity(PN_LIST));
715 0 : MOZ_ASSERT(cur->pn_count == 1);
716 0 : MOZ_ASSERT(cur->pn_head->isKind(PNK_LEXICALSCOPE) ||
717 : cur->pn_head->isKind(PNK_COMPREHENSIONFOR));
718 0 : if (!resolve(cur->pn_head, prefix))
719 0 : return false;
720 0 : break;
721 :
722 : case PNK_OBJECT:
723 : case PNK_CLASSMETHODLIST:
724 2576 : MOZ_ASSERT(cur->isArity(PN_LIST));
725 11872 : for (ParseNode* element = cur->pn_head; element; element = element->pn_next) {
726 9296 : if (!resolve(element, prefix))
727 0 : return false;
728 : }
729 2576 : break;
730 :
731 : // A template string list's contents alternate raw template string
732 : // contents with expressions interpolated into the overall literal.
733 : case PNK_TEMPLATE_STRING_LIST:
734 252 : MOZ_ASSERT(cur->isArity(PN_LIST));
735 252 : if (!resolveTemplateLiteral(cur, prefix))
736 0 : return false;
737 252 : break;
738 :
739 : case PNK_TAGGED_TEMPLATE:
740 1 : MOZ_ASSERT(cur->isArity(PN_LIST));
741 1 : if (!resolveTaggedTemplate(cur, prefix))
742 0 : return false;
743 1 : break;
744 :
745 : // Import/export spec lists contain import/export specs containing
746 : // only pairs of names. Alternatively, an export spec lists may
747 : // contain a single export batch specifier.
748 : case PNK_EXPORT_SPEC_LIST:
749 : case PNK_IMPORT_SPEC_LIST: {
750 0 : MOZ_ASSERT(cur->isArity(PN_LIST));
751 : #ifdef DEBUG
752 0 : bool isImport = cur->isKind(PNK_IMPORT_SPEC_LIST);
753 0 : ParseNode* item = cur->pn_head;
754 0 : if (!isImport && item && item->isKind(PNK_EXPORT_BATCH_SPEC)) {
755 0 : MOZ_ASSERT(item->isArity(PN_NULLARY));
756 0 : break;
757 : }
758 0 : for (; item; item = item->pn_next) {
759 0 : MOZ_ASSERT(item->isKind(isImport ? PNK_IMPORT_SPEC : PNK_EXPORT_SPEC));
760 0 : MOZ_ASSERT(item->isArity(PN_BINARY));
761 0 : MOZ_ASSERT(item->pn_left->isKind(PNK_NAME));
762 0 : MOZ_ASSERT(!item->pn_left->expr());
763 0 : MOZ_ASSERT(item->pn_right->isKind(PNK_NAME));
764 0 : MOZ_ASSERT(!item->pn_right->expr());
765 : }
766 : #endif
767 0 : break;
768 : }
769 :
770 : case PNK_CATCHLIST: {
771 468 : MOZ_ASSERT(cur->isArity(PN_LIST));
772 936 : for (ParseNode* catchNode = cur->pn_head; catchNode; catchNode = catchNode->pn_next) {
773 468 : MOZ_ASSERT(catchNode->isKind(PNK_LEXICALSCOPE));
774 468 : MOZ_ASSERT(catchNode->scopeBody()->isKind(PNK_CATCH));
775 468 : MOZ_ASSERT(catchNode->scopeBody()->isArity(PN_TERNARY));
776 468 : if (!resolve(catchNode->scopeBody(), prefix))
777 0 : return false;
778 : }
779 468 : break;
780 : }
781 :
782 : case PNK_DOT:
783 28612 : MOZ_ASSERT(cur->isArity(PN_NAME));
784 :
785 : // Super prop nodes do not have a meaningful LHS
786 28612 : if (cur->as<PropertyAccess>().isSuper())
787 13 : break;
788 28599 : if (!resolve(cur->expr(), prefix))
789 0 : return false;
790 28599 : break;
791 :
792 : case PNK_LABEL:
793 0 : MOZ_ASSERT(cur->isArity(PN_NAME));
794 0 : if (!resolve(cur->expr(), prefix))
795 0 : return false;
796 0 : break;
797 :
798 : case PNK_NAME:
799 90826 : MOZ_ASSERT(cur->isArity(PN_NAME));
800 90826 : if (!resolve(cur->expr(), prefix))
801 0 : return false;
802 90826 : break;
803 :
804 : case PNK_LEXICALSCOPE:
805 12470 : MOZ_ASSERT(cur->isArity(PN_SCOPE));
806 12470 : if (!resolve(cur->scopeBody(), prefix))
807 0 : return false;
808 12470 : break;
809 :
810 : case PNK_FUNCTION:
811 : case PNK_MODULE:
812 7234 : MOZ_ASSERT(cur->isArity(PN_CODE));
813 7234 : if (!resolve(cur->pn_body, prefix))
814 0 : return false;
815 7234 : break;
816 :
817 : // Kinds that should be handled by parent node resolution.
818 :
819 : case PNK_IMPORT_SPEC: // by PNK_IMPORT_SPEC_LIST
820 : case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST
821 : case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
822 : case PNK_CLASSNAMES: // by PNK_CLASS
823 0 : MOZ_CRASH("should have been handled by a parent node");
824 :
825 : case PNK_LIMIT: // invalid sentinel value
826 0 : MOZ_CRASH("invalid node kind");
827 : }
828 :
829 305242 : nparents--;
830 305242 : return true;
831 : }
832 : };
833 :
834 : } /* anonymous namespace */
835 :
836 : bool
837 1691 : frontend::NameFunctions(JSContext* cx, ParseNode* pn)
838 : {
839 3382 : AutoTraceLog traceLog(TraceLoggerForCurrentThread(cx), TraceLogger_BytecodeNameFunctions);
840 1691 : NameResolver nr(cx);
841 3382 : return nr.resolve(pn);
842 : }
|