Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / ParseNode.cpp
blobc61f9c28f56419834856af9eac9f835ee8465ca1
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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.h"
9 #include "mozilla/FloatingPoint.h"
10 #include "mozilla/Try.h" // MOZ_TRY*
12 #include "jsnum.h"
14 #include "frontend/CompilationStencil.h" // ExtensibleCompilationStencil
15 #include "frontend/FullParseHandler.h"
16 #include "frontend/ParseContext.h"
17 #include "frontend/Parser.h" // ParserBase
18 #include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex
19 #include "frontend/SharedContext.h"
20 #include "js/Printer.h"
21 #include "vm/Scope.h" // GetScopeDataTrailingNames
23 using namespace js;
24 using namespace js::frontend;
26 #ifdef DEBUG
27 void ListNode::checkConsistency() const {
28 ParseNode* const* tailNode;
29 uint32_t actualCount = 0;
30 if (const ParseNode* last = head()) {
31 const ParseNode* pn = last;
32 while (pn) {
33 last = pn;
34 pn = pn->pn_next;
35 actualCount++;
38 tailNode = &last->pn_next;
39 } else {
40 tailNode = &head_;
42 MOZ_ASSERT(tail() == tailNode);
43 MOZ_ASSERT(count() == actualCount);
45 #endif
48 * Allocate a ParseNode from parser's node freelist or, failing that, from
49 * cx's temporary arena.
51 void* ParseNodeAllocator::allocNode(size_t size) {
52 LifoAlloc::AutoFallibleScope fallibleAllocator(&alloc);
53 void* p = alloc.alloc(size);
54 if (!p) {
55 ReportOutOfMemory(fc);
57 return p;
60 ParseNodeResult ParseNode::appendOrCreateList(ParseNodeKind kind,
61 ParseNode* left, ParseNode* right,
62 FullParseHandler* handler,
63 ParseContext* pc) {
64 // The asm.js specification is written in ECMAScript grammar terms that
65 // specify *only* a binary tree. It's a royal pain to implement the asm.js
66 // spec to act upon n-ary lists as created below. So for asm.js, form a
67 // binary tree of lists exactly as ECMAScript would by skipping the
68 // following optimization.
69 if (!pc->useAsmOrInsideUseAsm()) {
70 // Left-associative trees of a given operator (e.g. |a + b + c|) are
71 // binary trees in the spec: (+ (+ a b) c) in Lisp terms. Recursively
72 // processing such a tree, exactly implemented that way, would blow the
73 // the stack. We use a list node that uses O(1) stack to represent
74 // such operations: (+ a b c).
76 // (**) is right-associative; per spec |a ** b ** c| parses as
77 // (** a (** b c)). But we treat this the same way, creating a list
78 // node: (** a b c). All consumers must understand that this must be
79 // processed with a right fold, whereas the list (+ a b c) must be
80 // processed with a left fold because (+) is left-associative.
82 if (left->isKind(kind) &&
83 (kind == ParseNodeKind::PowExpr ? !left->isInParens()
84 : left->isBinaryOperation())) {
85 ListNode* list = &left->as<ListNode>();
87 list->append(right);
88 list->pn_pos.end = right->pn_pos.end;
90 return list;
94 ListNode* list;
95 MOZ_TRY_VAR(list, handler->newResult<ListNode>(kind, left));
97 list->append(right);
98 return list;
101 const ParseNode::TypeCode ParseNode::typeCodeTable[] = {
102 #define TYPE_CODE(_name, type) type::classTypeCode(),
103 FOR_EACH_PARSE_NODE_KIND(TYPE_CODE)
104 #undef TYPE_CODE
107 #ifdef DEBUG
109 const size_t ParseNode::sizeTable[] = {
110 # define NODE_SIZE(_name, type) sizeof(type),
111 FOR_EACH_PARSE_NODE_KIND(NODE_SIZE)
112 # undef NODE_SIZE
115 static const char* const parseNodeNames[] = {
116 # define STRINGIFY(name, _type) #name,
117 FOR_EACH_PARSE_NODE_KIND(STRINGIFY)
118 # undef STRINGIFY
121 static void DumpParseTree(const ParserAtomsTable* parserAtoms, ParseNode* pn,
122 GenericPrinter& out, int indent) {
123 if (pn == nullptr) {
124 out.put("#NULL");
125 } else {
126 pn->dump(parserAtoms, out, indent);
130 void frontend::DumpParseTree(ParserBase* parser, ParseNode* pn,
131 GenericPrinter& out, int indent) {
132 ParserAtomsTable* parserAtoms = parser ? &parser->parserAtoms() : nullptr;
133 ::DumpParseTree(parserAtoms, pn, out, indent);
136 static void IndentNewLine(GenericPrinter& out, int indent) {
137 out.putChar('\n');
138 for (int i = 0; i < indent; ++i) {
139 out.putChar(' ');
143 void ParseNode::dump() { dump(nullptr); }
145 void ParseNode::dump(const ParserAtomsTable* parserAtoms) {
146 js::Fprinter out(stderr);
147 dump(parserAtoms, out);
150 void ParseNode::dump(const ParserAtomsTable* parserAtoms, GenericPrinter& out) {
151 dump(parserAtoms, out, 0);
152 out.putChar('\n');
155 void ParseNode::dump(const ParserAtomsTable* parserAtoms, GenericPrinter& out,
156 int indent) {
157 switch (getKind()) {
158 # define DUMP(K, T) \
159 case ParseNodeKind::K: \
160 as<T>().dumpImpl(parserAtoms, out, indent); \
161 break;
162 FOR_EACH_PARSE_NODE_KIND(DUMP)
163 # undef DUMP
164 default:
165 out.printf("#<BAD NODE %p, kind=%u>", (void*)this, unsigned(getKind()));
169 void NullaryNode::dumpImpl(const ParserAtomsTable* parserAtoms,
170 GenericPrinter& out, int indent) {
171 switch (getKind()) {
172 case ParseNodeKind::TrueExpr:
173 out.put("#true");
174 break;
175 case ParseNodeKind::FalseExpr:
176 out.put("#false");
177 break;
178 case ParseNodeKind::NullExpr:
179 out.put("#null");
180 break;
181 case ParseNodeKind::RawUndefinedExpr:
182 out.put("#undefined");
183 break;
185 default:
186 out.printf("(%s)", parseNodeNames[getKindAsIndex()]);
190 void NumericLiteral::dumpImpl(const ParserAtomsTable* parserAtoms,
191 GenericPrinter& out, int indent) {
192 ToCStringBuf cbuf;
193 const char* cstr = NumberToCString(&cbuf, value());
194 MOZ_ASSERT(cstr);
195 if (!std::isfinite(value())) {
196 out.put("#");
198 out.printf("%s", cstr);
201 void BigIntLiteral::dumpImpl(const ParserAtomsTable* parserAtoms,
202 GenericPrinter& out, int indent) {
203 out.printf("(%s)", parseNodeNames[getKindAsIndex()]);
206 void RegExpLiteral::dumpImpl(const ParserAtomsTable* parserAtoms,
207 GenericPrinter& out, int indent) {
208 out.printf("(%s)", parseNodeNames[getKindAsIndex()]);
211 static void DumpCharsNoNewline(const ParserAtomsTable* parserAtoms,
212 TaggedParserAtomIndex index,
213 GenericPrinter& out) {
214 out.put("\"");
215 if (parserAtoms) {
216 parserAtoms->dumpCharsNoQuote(out, index);
217 } else {
218 DumpTaggedParserAtomIndexNoQuote(out, index, nullptr);
220 out.put("\"");
223 void LoopControlStatement::dumpImpl(const ParserAtomsTable* parserAtoms,
224 GenericPrinter& out, int indent) {
225 const char* name = parseNodeNames[getKindAsIndex()];
226 out.printf("(%s", name);
227 if (label_) {
228 out.printf(" ");
229 DumpCharsNoNewline(parserAtoms, label_, out);
231 out.printf(")");
234 void UnaryNode::dumpImpl(const ParserAtomsTable* parserAtoms,
235 GenericPrinter& out, int indent) {
236 const char* name = parseNodeNames[getKindAsIndex()];
237 out.printf("(%s ", name);
238 indent += strlen(name) + 2;
239 ::DumpParseTree(parserAtoms, kid(), out, indent);
240 out.printf(")");
243 void BinaryNode::dumpImpl(const ParserAtomsTable* parserAtoms,
244 GenericPrinter& out, int indent) {
245 if (isKind(ParseNodeKind::DotExpr)) {
246 out.put("(.");
248 ::DumpParseTree(parserAtoms, right(), out, indent + 2);
250 out.putChar(' ');
251 if (as<PropertyAccess>().isSuper()) {
252 out.put("super");
253 } else {
254 ::DumpParseTree(parserAtoms, left(), out, indent + 2);
257 out.printf(")");
258 return;
261 const char* name = parseNodeNames[getKindAsIndex()];
262 out.printf("(%s ", name);
263 indent += strlen(name) + 2;
264 ::DumpParseTree(parserAtoms, left(), out, indent);
265 IndentNewLine(out, indent);
266 ::DumpParseTree(parserAtoms, right(), out, indent);
267 out.printf(")");
270 void TernaryNode::dumpImpl(const ParserAtomsTable* parserAtoms,
271 GenericPrinter& out, int indent) {
272 const char* name = parseNodeNames[getKindAsIndex()];
273 out.printf("(%s ", name);
274 indent += strlen(name) + 2;
275 ::DumpParseTree(parserAtoms, kid1(), out, indent);
276 IndentNewLine(out, indent);
277 ::DumpParseTree(parserAtoms, kid2(), out, indent);
278 IndentNewLine(out, indent);
279 ::DumpParseTree(parserAtoms, kid3(), out, indent);
280 out.printf(")");
283 void FunctionNode::dumpImpl(const ParserAtomsTable* parserAtoms,
284 GenericPrinter& out, int indent) {
285 const char* name = parseNodeNames[getKindAsIndex()];
286 out.printf("(%s ", name);
287 indent += strlen(name) + 2;
288 ::DumpParseTree(parserAtoms, body(), out, indent);
289 out.printf(")");
292 void ModuleNode::dumpImpl(const ParserAtomsTable* parserAtoms,
293 GenericPrinter& out, int indent) {
294 const char* name = parseNodeNames[getKindAsIndex()];
295 out.printf("(%s ", name);
296 indent += strlen(name) + 2;
297 ::DumpParseTree(parserAtoms, body(), out, indent);
298 out.printf(")");
301 void ListNode::dumpImpl(const ParserAtomsTable* parserAtoms,
302 GenericPrinter& out, int indent) {
303 const char* name = parseNodeNames[getKindAsIndex()];
304 out.printf("(%s [", name);
305 if (ParseNode* listHead = head()) {
306 indent += strlen(name) + 3;
307 ::DumpParseTree(parserAtoms, listHead, out, indent);
308 for (ParseNode* item : contentsFrom(listHead->pn_next)) {
309 IndentNewLine(out, indent);
310 ::DumpParseTree(parserAtoms, item, out, indent);
313 out.printf("])");
316 void NameNode::dumpImpl(const ParserAtomsTable* parserAtoms,
317 GenericPrinter& out, int indent) {
318 switch (getKind()) {
319 case ParseNodeKind::StringExpr:
320 case ParseNodeKind::TemplateStringExpr:
321 case ParseNodeKind::ObjectPropertyName:
322 DumpCharsNoNewline(parserAtoms, atom_, out);
323 return;
325 case ParseNodeKind::Name:
326 case ParseNodeKind::PrivateName: // atom() already includes the '#', no
327 // need to specially include it.
328 case ParseNodeKind::PropertyNameExpr:
329 if (!atom_) {
330 out.put("#<null name>");
331 } else if (parserAtoms) {
332 if (atom_ == TaggedParserAtomIndex::WellKnown::empty()) {
333 out.put("#<zero-length name>");
334 } else {
335 parserAtoms->dumpCharsNoQuote(out, atom_);
337 } else {
338 DumpTaggedParserAtomIndexNoQuote(out, atom_, nullptr);
340 return;
342 case ParseNodeKind::LabelStmt: {
343 this->as<LabeledStatement>().dumpImpl(parserAtoms, out, indent);
344 return;
347 default: {
348 const char* name = parseNodeNames[getKindAsIndex()];
349 out.printf("(%s)", name);
350 return;
355 void LabeledStatement::dumpImpl(const ParserAtomsTable* parserAtoms,
356 GenericPrinter& out, int indent) {
357 const char* name = parseNodeNames[getKindAsIndex()];
358 out.printf("(%s ", name);
359 DumpCharsNoNewline(parserAtoms, label(), out);
360 indent += strlen(name) + 2;
361 IndentNewLine(out, indent);
362 ::DumpParseTree(parserAtoms, statement(), out, indent);
363 out.printf(")");
366 template <ParseNodeKind Kind, typename ScopeType>
367 void BaseScopeNode<Kind, ScopeType>::dumpImpl(
368 const ParserAtomsTable* parserAtoms, GenericPrinter& out, int indent) {
369 const char* name = parseNodeNames[getKindAsIndex()];
370 out.printf("(%s [", name);
371 int nameIndent = indent + strlen(name) + 3;
372 if (!isEmptyScope()) {
373 typename ScopeType::ParserData* bindings = scopeBindings();
374 auto names = GetScopeDataTrailingNames(bindings);
375 for (uint32_t i = 0; i < names.size(); i++) {
376 auto index = names[i].name();
377 if (parserAtoms) {
378 if (index == TaggedParserAtomIndex::WellKnown::empty()) {
379 out.put("#<zero-length name>");
380 } else {
381 parserAtoms->dumpCharsNoQuote(out, index);
383 } else {
384 DumpTaggedParserAtomIndexNoQuote(out, index, nullptr);
386 if (i < names.size() - 1) {
387 IndentNewLine(out, nameIndent);
391 out.putChar(']');
392 indent += 2;
393 IndentNewLine(out, indent);
394 ::DumpParseTree(parserAtoms, scopeBody(), out, indent);
395 out.printf(")");
398 # ifdef ENABLE_DECORATORS
399 void ClassMethod::dumpImpl(const ParserAtomsTable* parserAtoms,
400 GenericPrinter& out, int indent) {
401 if (decorators_) {
402 decorators_->dumpImpl(parserAtoms, out, indent);
404 Base::dumpImpl(parserAtoms, out, indent);
407 void ClassField::dumpImpl(const ParserAtomsTable* parserAtoms,
408 GenericPrinter& out, int indent) {
409 if (decorators_) {
410 decorators_->dumpImpl(parserAtoms, out, indent);
411 out.putChar(' ');
413 Base::dumpImpl(parserAtoms, out, indent);
414 IndentNewLine(out, indent + 2);
415 if (accessorGetterNode_) {
416 out.printf("getter: ");
417 accessorGetterNode_->dumpImpl(parserAtoms, out, indent);
419 IndentNewLine(out, indent + 2);
420 if (accessorSetterNode_) {
421 out.printf("setter: ");
422 accessorSetterNode_->dumpImpl(parserAtoms, out, indent);
426 void ClassNode::dumpImpl(const ParserAtomsTable* parserAtoms,
427 GenericPrinter& out, int indent) {
428 if (decorators_) {
429 decorators_->dumpImpl(parserAtoms, out, indent);
431 Base::dumpImpl(parserAtoms, out, indent);
433 # endif
435 #endif
437 TaggedParserAtomIndex NumericLiteral::toAtom(
438 FrontendContext* fc, ParserAtomsTable& parserAtoms) const {
439 return NumberToParserAtom(fc, parserAtoms, value());
442 RegExpObject* RegExpLiteral::create(
443 JSContext* cx, FrontendContext* fc, ParserAtomsTable& parserAtoms,
444 CompilationAtomCache& atomCache,
445 ExtensibleCompilationStencil& stencil) const {
446 return stencil.regExpData[index_].createRegExpAndEnsureAtom(
447 cx, fc, parserAtoms, atomCache);
450 bool js::frontend::IsAnonymousFunctionDefinition(ParseNode* pn) {
451 // ES 2017 draft
452 // 12.15.2 (ArrowFunction, AsyncArrowFunction).
453 // 14.1.12 (FunctionExpression).
454 // 14.4.8 (Generatoression).
455 // 14.6.8 (AsyncFunctionExpression)
456 if (pn->is<FunctionNode>() &&
457 !pn->as<FunctionNode>().funbox()->explicitName()) {
458 return true;
461 // 14.5.8 (ClassExpression)
462 if (pn->is<ClassNode>() && !pn->as<ClassNode>().names()) {
463 return true;
466 return false;