Source code

Revision control

Other Tools

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/. */
6
7
/*
8
* JS parser.
9
*
10
* This is a recursive-descent parser for the JavaScript language specified by
11
* "The ECMAScript Language Specification" (Standard ECMA-262). It uses
12
* lexical and semantic feedback to disambiguate non-LL(1) structures. It
13
* generates trees of nodes induced by the recursive parsing (not precise
14
* syntax trees, see Parser.h). After tree construction, it rewrites trees to
15
* fold constants and evaluate compile-time expressions.
16
*
17
* This parser attempts no error recovery.
18
*/
19
20
#include "frontend/Parser.h"
21
22
#include "mozilla/ArrayUtils.h"
23
#include "mozilla/Casting.h"
24
#include "mozilla/Range.h"
25
#include "mozilla/ScopeExit.h"
26
#include "mozilla/Sprintf.h"
27
#include "mozilla/TypeTraits.h"
28
#include "mozilla/Unused.h"
29
#include "mozilla/Utf8.h"
30
#include "mozilla/Variant.h"
31
32
#include <memory>
33
#include <new>
34
35
#include "jsnum.h"
36
#include "jstypes.h"
37
38
#include "builtin/ModuleObject.h"
39
#include "builtin/SelfHostingDefines.h"
40
#include "frontend/BytecodeCompiler.h"
41
#include "frontend/BytecodeSection.h"
42
#include "frontend/FoldConstants.h"
43
#include "frontend/ModuleSharedContext.h"
44
#include "frontend/ParseNode.h"
45
#include "frontend/ParseNodeVerify.h"
46
#include "frontend/TokenStream.h"
47
#include "irregexp/RegExpParser.h"
48
#include "js/RegExpFlags.h" // JS::RegExpFlags
49
#include "vm/BytecodeUtil.h"
50
#include "vm/JSAtom.h"
51
#include "vm/JSContext.h"
52
#include "vm/JSFunction.h"
53
#include "vm/JSScript.h"
54
#include "vm/ModuleBuilder.h" // js::ModuleBuilder
55
#include "vm/RegExpObject.h"
56
#include "vm/SelfHosting.h"
57
#include "vm/StringType.h"
58
#include "wasm/AsmJS.h"
59
60
#include "frontend/ParseContext-inl.h"
61
#include "frontend/SharedContext-inl.h"
62
#include "vm/EnvironmentObject-inl.h"
63
64
using namespace js;
65
66
using mozilla::AssertedCast;
67
using mozilla::AsVariant;
68
using mozilla::Maybe;
69
using mozilla::Nothing;
70
using mozilla::PodCopy;
71
using mozilla::PodZero;
72
using mozilla::PointerRangeSize;
73
using mozilla::Some;
74
using mozilla::Unused;
75
using mozilla::Utf8Unit;
76
77
using JS::AutoGCRooter;
78
using JS::ReadOnlyCompileOptions;
79
using JS::RegExpFlags;
80
81
namespace js {
82
namespace frontend {
83
84
using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
85
using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
86
using BindingIter = ParseContext::Scope::BindingIter;
87
using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
88
89
using BindingNameVector = Vector<BindingName, 6>;
90
91
template <class T, class U>
92
static inline void PropagateTransitiveParseFlags(const T* inner, U* outer) {
93
if (inner->bindingsAccessedDynamically()) {
94
outer->setBindingsAccessedDynamically();
95
}
96
if (inner->hasDirectEval()) {
97
outer->setHasDirectEval();
98
}
99
}
100
101
static bool StatementKindIsBraced(StatementKind kind) {
102
return kind == StatementKind::Block || kind == StatementKind::Switch ||
103
kind == StatementKind::Try || kind == StatementKind::Catch ||
104
kind == StatementKind::Finally || kind == StatementKind::Class;
105
}
106
107
template <class ParseHandler, typename Unit>
108
inline typename GeneralParser<ParseHandler, Unit>::FinalParser*
109
GeneralParser<ParseHandler, Unit>::asFinalParser() {
110
static_assert(
111
mozilla::IsBaseOf<GeneralParser<ParseHandler, Unit>, FinalParser>::value,
112
"inheritance relationship required by the static_cast<> below");
113
114
return static_cast<FinalParser*>(this);
115
}
116
117
template <class ParseHandler, typename Unit>
118
inline const typename GeneralParser<ParseHandler, Unit>::FinalParser*
119
GeneralParser<ParseHandler, Unit>::asFinalParser() const {
120
static_assert(
121
mozilla::IsBaseOf<GeneralParser<ParseHandler, Unit>, FinalParser>::value,
122
"inheritance relationship required by the static_cast<> below");
123
124
return static_cast<const FinalParser*>(this);
125
}
126
127
template <class ParseHandler, typename Unit>
128
template <typename ConditionT, typename ErrorReportT>
129
bool GeneralParser<ParseHandler, Unit>::mustMatchTokenInternal(
130
ConditionT condition, ErrorReportT errorReport) {
131
MOZ_ASSERT(condition(TokenKind::Div) == false);
132
MOZ_ASSERT(condition(TokenKind::DivAssign) == false);
133
MOZ_ASSERT(condition(TokenKind::RegExp) == false);
134
135
TokenKind actual;
136
if (!tokenStream.getToken(&actual, TokenStream::SlashIsInvalid)) {
137
return false;
138
}
139
if (!condition(actual)) {
140
errorReport(actual);
141
return false;
142
}
143
return true;
144
}
145
146
ParserSharedBase::ParserSharedBase(JSContext* cx, ParseInfo& parserInfo,
147
ScriptSourceObject* sourceObject, Kind kind)
148
: JS::AutoGCRooter(
149
cx,
150
#ifdef JS_BUILD_BINAST
151
kind == Kind::Parser ? JS::AutoGCRooter::Tag::Parser
152
: JS::AutoGCRooter::Tag::BinASTParser
153
#else
154
JS::AutoGCRooter::Tag::Parser
155
#endif
156
),
157
cx_(cx),
158
alloc_(parserInfo.allocScope.alloc()),
159
parseInfo_(parserInfo),
160
traceListHead_(nullptr),
161
pc_(nullptr),
162
usedNames_(parserInfo.usedNames),
163
sourceObject_(cx, sourceObject),
164
keepAtoms_(cx) {
165
cx->frontendCollectionPool().addActiveCompilation();
166
}
167
168
// Ensure we don't hold onto any memory via trace list nodes
169
// which may be freed when the lifo alloc dies.
170
void ParserSharedBase::cleanupTraceList() {
171
TraceListNode* elem = traceListHead_;
172
while (elem) {
173
if (elem->isObjectBox()) {
174
ObjectBox* objBox = elem->asObjectBox();
175
176
// FunctionBoxes are LifoAllocated, but the LazyScriptCreationData that
177
// they hold onto have SystemAlloc memory. We need to make sure this gets
178
// cleaned up before the Lifo gets released (in ParseInfo) to ensure that
179
// we don't leak memory.
180
if (objBox->isFunctionBox()) {
181
objBox->asFunctionBox()->cleanupMemory();
182
}
183
}
184
elem = elem->traceLink;
185
}
186
}
187
188
ParserSharedBase::~ParserSharedBase() {
189
cleanupTraceList();
190
cx_->frontendCollectionPool().removeActiveCompilation();
191
}
192
193
ParserBase::ParserBase(JSContext* cx, const ReadOnlyCompileOptions& options,
194
bool foldConstants, ParseInfo& parseInfo,
195
ScriptSourceObject* sourceObject, ParseGoal parseGoal)
196
: ParserSharedBase(cx, parseInfo, sourceObject,
197
ParserSharedBase::Kind::Parser),
198
anyChars(cx, options, this),
199
ss(nullptr),
200
foldConstants_(foldConstants),
201
#ifdef DEBUG
202
checkOptionsCalled_(false),
203
#endif
204
isUnexpectedEOF_(false),
205
awaitHandling_(AwaitIsName),
206
inParametersOfAsyncFunction_(false),
207
parseGoal_(uint8_t(parseGoal)),
208
treeHolder_(parseInfo.treeHolder) {
209
}
210
211
bool ParserBase::checkOptions() {
212
#ifdef DEBUG
213
checkOptionsCalled_ = true;
214
#endif
215
216
return anyChars.checkOptions();
217
}
218
219
ParserBase::~ParserBase() { MOZ_ASSERT(checkOptionsCalled_); }
220
221
template <class ParseHandler>
222
PerHandlerParser<ParseHandler>::PerHandlerParser(
223
JSContext* cx, const ReadOnlyCompileOptions& options, bool foldConstants,
224
ParseInfo& parserInfo, LazyScript* lazyOuterFunction,
225
ScriptSourceObject* sourceObject, ParseGoal parseGoal,
226
void* internalSyntaxParser)
227
: ParserBase(cx, options, foldConstants, parserInfo, sourceObject,
228
parseGoal),
229
handler_(cx, parserInfo.allocScope.alloc(), lazyOuterFunction),
230
internalSyntaxParser_(internalSyntaxParser) {}
231
232
template <class ParseHandler, typename Unit>
233
GeneralParser<ParseHandler, Unit>::GeneralParser(
234
JSContext* cx, const ReadOnlyCompileOptions& options, const Unit* units,
235
size_t length, bool foldConstants, ParseInfo& parserInfo,
236
SyntaxParser* syntaxParser, LazyScript* lazyOuterFunction,
237
ScriptSourceObject* sourceObject, ParseGoal parseGoal)
238
: Base(cx, options, foldConstants, parserInfo, syntaxParser,
239
lazyOuterFunction, sourceObject, parseGoal),
240
tokenStream(cx, options, units, length) {}
241
242
template <typename Unit>
243
void Parser<SyntaxParseHandler, Unit>::setAwaitHandling(
244
AwaitHandling awaitHandling) {
245
this->awaitHandling_ = awaitHandling;
246
}
247
248
template <typename Unit>
249
void Parser<FullParseHandler, Unit>::setAwaitHandling(
250
AwaitHandling awaitHandling) {
251
this->awaitHandling_ = awaitHandling;
252
if (SyntaxParser* syntaxParser = getSyntaxParser()) {
253
syntaxParser->setAwaitHandling(awaitHandling);
254
}
255
}
256
257
template <class ParseHandler, typename Unit>
258
inline void GeneralParser<ParseHandler, Unit>::setAwaitHandling(
259
AwaitHandling awaitHandling) {
260
asFinalParser()->setAwaitHandling(awaitHandling);
261
}
262
263
template <typename Unit>
264
void Parser<SyntaxParseHandler, Unit>::setInParametersOfAsyncFunction(
265
bool inParameters) {
266
this->inParametersOfAsyncFunction_ = inParameters;
267
}
268
269
template <typename Unit>
270
void Parser<FullParseHandler, Unit>::setInParametersOfAsyncFunction(
271
bool inParameters) {
272
this->inParametersOfAsyncFunction_ = inParameters;
273
if (SyntaxParser* syntaxParser = getSyntaxParser()) {
274
syntaxParser->setInParametersOfAsyncFunction(inParameters);
275
}
276
}
277
278
template <class ParseHandler, typename Unit>
279
inline void GeneralParser<ParseHandler, Unit>::setInParametersOfAsyncFunction(
280
bool inParameters) {
281
asFinalParser()->setInParametersOfAsyncFunction(inParameters);
282
}
283
284
template <typename BoxT, typename ArgT>
285
BoxT* ParserSharedBase::newTraceListNode(ArgT* arg) {
286
MOZ_ASSERT(arg);
287
288
/*
289
* We use JSContext.tempLifoAlloc to allocate parsed objects and place them
290
* on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
291
* arenas containing the entries must be alive until we are done with
292
* scanning, parsing and code generation for the whole script or top-level
293
* function.
294
*/
295
296
BoxT* box = alloc_.template new_<BoxT>(arg, traceListHead_);
297
if (!box) {
298
ReportOutOfMemory(cx_);
299
return nullptr;
300
}
301
302
traceListHead_ = box;
303
304
return box;
305
}
306
307
ObjectBox* ParserSharedBase::newObjectBox(JSObject* obj) {
308
return newTraceListNode<ObjectBox, JSObject>(obj);
309
}
310
311
BigIntBox* ParserSharedBase::newBigIntBox(BigInt* val) {
312
return newTraceListNode<BigIntBox, BigInt>(val);
313
}
314
315
template <class ParseHandler>
316
FunctionBox* PerHandlerParser<ParseHandler>::newFunctionBox(
317
FunctionNodeType funNode, JSFunction* fun, uint32_t toStringStart,
318
Directives inheritedDirectives, GeneratorKind generatorKind,
319
FunctionAsyncKind asyncKind) {
320
MOZ_ASSERT(fun);
321
322
/*
323
* We use JSContext.tempLifoAlloc to allocate parsed objects and place them
324
* on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
325
* arenas containing the entries must be alive until we are done with
326
* scanning, parsing and code generation for the whole script or top-level
327
* function.
328
*/
329
FunctionBox* funbox = alloc_.new_<FunctionBox>(
330
cx_, traceListHead_, fun, toStringStart, inheritedDirectives,
331
options().extraWarningsOption, generatorKind, asyncKind);
332
if (!funbox) {
333
ReportOutOfMemory(cx_);
334
return nullptr;
335
}
336
337
traceListHead_ = funbox;
338
if (funNode) {
339
handler_.setFunctionBox(funNode, funbox);
340
}
341
342
return funbox;
343
}
344
345
template <class ParseHandler>
346
FunctionBox* PerHandlerParser<ParseHandler>::newFunctionBox(
347
FunctionNodeType funNode, Handle<FunctionCreationData> fcd,
348
uint32_t toStringStart, Directives inheritedDirectives,
349
GeneratorKind generatorKind, FunctionAsyncKind asyncKind) {
350
/*
351
* We use JSContext.tempLifoAlloc to allocate parsed objects and place them
352
* on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
353
* arenas containing the entries must be alive until we are done with
354
* scanning, parsing and code generation for the whole script or top-level
355
* function.
356
*/
357
358
FunctionBox* funbox;
359
if (getTreeHolder().isDeferred()) {
360
funbox = alloc_.new_<FunctionBox>(
361
cx_, traceListHead_, fcd, toStringStart, inheritedDirectives,
362
options().extraWarningsOption, generatorKind, asyncKind);
363
} else {
364
RootedFunction fun(cx_, AllocNewFunction(cx_, fcd));
365
if (!fun) {
366
ReportOutOfMemory(cx_);
367
return nullptr;
368
}
369
funbox = alloc_.new_<FunctionBox>(
370
cx_, traceListHead_, fun, toStringStart, inheritedDirectives,
371
options().extraWarningsOption, generatorKind, asyncKind);
372
}
373
374
if (!funbox) {
375
ReportOutOfMemory(cx_);
376
return nullptr;
377
}
378
379
traceListHead_ = funbox;
380
if (funNode) {
381
handler_.setFunctionBox(funNode, funbox);
382
}
383
384
return funbox;
385
}
386
387
void ParserBase::trace(JSTracer* trc) {
388
TraceListNode::TraceList(trc, traceListHead_);
389
}
390
391
void TraceParser(JSTracer* trc, AutoGCRooter* parser) {
392
static_cast<ParserBase*>(parser)->trace(trc);
393
}
394
395
bool ParserBase::setSourceMapInfo() {
396
// Not all clients initialize ss. Can't update info to an object that isn't
397
// there.
398
if (!ss) {
399
return true;
400
}
401
402
if (anyChars.hasDisplayURL()) {
403
if (!ss->setDisplayURL(cx_, anyChars.displayURL())) {
404
return false;
405
}
406
}
407
408
if (anyChars.hasSourceMapURL()) {
409
MOZ_ASSERT(!ss->hasSourceMapURL());
410
if (!ss->setSourceMapURL(cx_, anyChars.sourceMapURL())) {
411
return false;
412
}
413
}
414
415
/*
416
* Source map URLs passed as a compile option (usually via a HTTP source map
417
* header) override any source map urls passed as comment pragmas.
418
*/
419
if (options().sourceMapURL()) {
420
// Warn about the replacement, but use the new one.
421
if (ss->hasSourceMapURL()) {
422
if (!warningNoOffset(JSMSG_ALREADY_HAS_PRAGMA, ss->filename(),
423
"//# sourceMappingURL")) {
424
return false;
425
}
426
}
427
428
if (!ss->setSourceMapURL(cx_, options().sourceMapURL())) {
429
return false;
430
}
431
}
432
433
return true;
434
}
435
436
/*
437
* Parse a top-level JS script.
438
*/
439
template <class ParseHandler, typename Unit>
440
typename ParseHandler::ListNodeType GeneralParser<ParseHandler, Unit>::parse() {
441
MOZ_ASSERT(checkOptionsCalled_);
442
443
Directives directives(options().forceStrictMode());
444
GlobalSharedContext globalsc(cx_, ScopeKind::Global, directives,
445
options().extraWarningsOption);
446
SourceParseContext globalpc(this, &globalsc, /* newDirectives = */ nullptr);
447
if (!globalpc.init()) {
448
return null();
449
}
450
451
ParseContext::VarScope varScope(this);
452
if (!varScope.init(pc_)) {
453
return null();
454
}
455
456
ListNodeType stmtList = statementList(YieldIsName);
457
if (!stmtList) {
458
return null();
459
}
460
461
TokenKind tt;
462
if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
463
return null();
464
}
465
if (tt != TokenKind::Eof) {
466
error(JSMSG_GARBAGE_AFTER_INPUT, "script", TokenKindToDesc(tt));
467
return null();
468
}
469
470
if (!CheckParseTree(cx_, alloc_, stmtList)) {
471
return null();
472
}
473
474
if (foldConstants_) {
475
Node node = stmtList;
476
// Don't constant-fold inside "use asm" code, as this could create a parse
477
// tree that doesn't type-check as asm.js.
478
if (!pc_->useAsmOrInsideUseAsm()) {
479
if (!FoldConstants(cx_, &node, &handler_)) {
480
return null();
481
}
482
}
483
stmtList = handler_.asList(node);
484
}
485
486
return stmtList;
487
}
488
489
/*
490
* Strict mode forbids introducing new definitions for 'eval', 'arguments',
491
* 'let', 'static', 'yield', or for any strict mode reserved word.
492
*/
493
bool ParserBase::isValidStrictBinding(PropertyName* name) {
494
TokenKind tt = ReservedWordTokenKind(name);
495
if (tt == TokenKind::Name) {
496
return name != cx_->names().eval && name != cx_->names().arguments;
497
}
498
return tt != TokenKind::Let && tt != TokenKind::Static &&
499
tt != TokenKind::Yield && !TokenKindIsStrictReservedWord(tt);
500
}
501
502
/*
503
* Returns true if all parameter names are valid strict mode binding names and
504
* no duplicate parameter names are present.
505
*/
506
bool ParserBase::hasValidSimpleStrictParameterNames() {
507
MOZ_ASSERT(pc_->isFunctionBox() &&
508
pc_->functionBox()->hasSimpleParameterList());
509
510
if (pc_->functionBox()->hasDuplicateParameters) {
511
return false;
512
}
513
514
for (auto* name : pc_->positionalFormalParameterNames()) {
515
MOZ_ASSERT(name);
516
if (!isValidStrictBinding(name->asPropertyName())) {
517
return false;
518
}
519
}
520
return true;
521
}
522
523
template <class ParseHandler, typename Unit>
524
void GeneralParser<ParseHandler, Unit>::reportMissingClosing(
525
unsigned errorNumber, unsigned noteNumber, uint32_t openedPos) {
526
auto notes = MakeUnique<JSErrorNotes>();
527
if (!notes) {
528
ReportOutOfMemory(pc_->sc()->cx_);
529
return;
530
}
531
532
uint32_t line, column;
533
tokenStream.computeLineAndColumn(openedPos, &line, &column);
534
535
const size_t MaxWidth = sizeof("4294967295");
536
char columnNumber[MaxWidth];
537
SprintfLiteral(columnNumber, "%" PRIu32, column);
538
char lineNumber[MaxWidth];
539
SprintfLiteral(lineNumber, "%" PRIu32, line);
540
541
if (!notes->addNoteASCII(pc_->sc()->cx_, getFilename(), 0, line, column,
542
GetErrorMessage, nullptr, noteNumber, lineNumber,
543
columnNumber)) {
544
return;
545
}
546
547
errorWithNotes(std::move(notes), errorNumber);
548
}
549
550
template <class ParseHandler, typename Unit>
551
void GeneralParser<ParseHandler, Unit>::reportRedeclaration(
552
HandlePropertyName name, DeclarationKind prevKind, TokenPos pos,
553
uint32_t prevPos) {
554
UniqueChars bytes = AtomToPrintableString(cx_, name);
555
if (!bytes) {
556
return;
557
}
558
559
if (prevPos == DeclaredNameInfo::npos) {
560
errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(prevKind),
561
bytes.get());
562
return;
563
}
564
565
auto notes = MakeUnique<JSErrorNotes>();
566
if (!notes) {
567
ReportOutOfMemory(pc_->sc()->cx_);
568
return;
569
}
570
571
uint32_t line, column;
572
tokenStream.computeLineAndColumn(prevPos, &line, &column);
573
574
const size_t MaxWidth = sizeof("4294967295");
575
char columnNumber[MaxWidth];
576
SprintfLiteral(columnNumber, "%" PRIu32, column);
577
char lineNumber[MaxWidth];
578
SprintfLiteral(lineNumber, "%" PRIu32, line);
579
580
if (!notes->addNoteASCII(pc_->sc()->cx_, getFilename(), 0, line, column,
581
GetErrorMessage, nullptr, JSMSG_REDECLARED_PREV,
582
lineNumber, columnNumber)) {
583
return;
584
}
585
586
errorWithNotesAt(std::move(notes), pos.begin, JSMSG_REDECLARED_VAR,
587
DeclarationKindString(prevKind), bytes.get());
588
}
589
590
// notePositionalFormalParameter is called for both the arguments of a regular
591
// function definition and the arguments specified by the Function
592
// constructor.
593
//
594
// The 'disallowDuplicateParams' bool indicates whether the use of another
595
// feature (destructuring or default arguments) disables duplicate arguments.
596
// (ECMA-262 requires us to support duplicate parameter names, but, for newer
597
// features, we consider the code to have "opted in" to higher standards and
598
// forbid duplicates.)
599
template <class ParseHandler, typename Unit>
600
bool GeneralParser<ParseHandler, Unit>::notePositionalFormalParameter(
601
FunctionNodeType funNode, HandlePropertyName name, uint32_t beginPos,
602
bool disallowDuplicateParams, bool* duplicatedParam) {
603
if (AddDeclaredNamePtr p =
604
pc_->functionScope().lookupDeclaredNameForAdd(name)) {
605
if (disallowDuplicateParams) {
606
error(JSMSG_BAD_DUP_ARGS);
607
return false;
608
}
609
610
// Strict-mode disallows duplicate args. We may not know whether we are
611
// in strict mode or not (since the function body hasn't been parsed).
612
// In such cases, report will queue up the potential error and return
613
// 'true'.
614
if (pc_->sc()->needStrictChecks()) {
615
UniqueChars bytes = AtomToPrintableString(cx_, name);
616
if (!bytes) {
617
return false;
618
}
619
if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.get())) {
620
return false;
621
}
622
}
623
624
*duplicatedParam = true;
625
} else {
626
DeclarationKind kind = DeclarationKind::PositionalFormalParameter;
627
if (!pc_->functionScope().addDeclaredName(pc_, p, name, kind, beginPos)) {
628
return false;
629
}
630
}
631
632
if (!pc_->positionalFormalParameterNames().append(name)) {
633
ReportOutOfMemory(cx_);
634
return false;
635
}
636
637
NameNodeType paramNode = newName(name);
638
if (!paramNode) {
639
return false;
640
}
641
642
handler_.addFunctionFormalParameter(funNode, paramNode);
643
return true;
644
}
645
646
template <class ParseHandler>
647
bool PerHandlerParser<ParseHandler>::noteDestructuredPositionalFormalParameter(
648
FunctionNodeType funNode, Node destruct) {
649
// Append an empty name to the positional formals vector to keep track of
650
// argument slots when making FunctionScope::Data.
651
if (!pc_->positionalFormalParameterNames().append(nullptr)) {
652
ReportOutOfMemory(cx_);
653
return false;
654
}
655
656
handler_.addFunctionFormalParameter(funNode, destruct);
657
return true;
658
}
659
660
template <class ParseHandler, typename Unit>
661
bool GeneralParser<ParseHandler, Unit>::
662
checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt,
663
DeclarationKind kind,
664
TokenPos pos) {
665
MOZ_ASSERT(DeclarationKindIsLexical(kind));
666
667
// It is an early error to declare a lexical binding not directly
668
// within a block.
669
if (!StatementKindIsBraced(stmt.kind()) &&
670
stmt.kind() != StatementKind::ForLoopLexicalHead) {
671
errorAt(pos.begin,
672
stmt.kind() == StatementKind::Label
673
? JSMSG_LEXICAL_DECL_LABEL
674
: JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
675
DeclarationKindString(kind));
676
return false;
677
}
678
679
return true;
680
}
681
682
template <class ParseHandler, typename Unit>
683
bool GeneralParser<ParseHandler, Unit>::noteDeclaredName(
684
HandlePropertyName name, DeclarationKind kind, TokenPos pos) {
685
// The asm.js validator does all its own symbol-table management so, as an
686
// optimization, avoid doing any work here.
687
if (pc_->useAsmOrInsideUseAsm()) {
688
return true;
689
}
690
691
switch (kind) {
692
case DeclarationKind::Var:
693
case DeclarationKind::BodyLevelFunction: {
694
Maybe<DeclarationKind> redeclaredKind;
695
uint32_t prevPos;
696
if (!pc_->tryDeclareVar(name, kind, pos.begin, &redeclaredKind,
697
&prevPos)) {
698
return false;
699
}
700
701
if (redeclaredKind) {
702
reportRedeclaration(name, *redeclaredKind, pos, prevPos);
703
return false;
704
}
705
706
break;
707
}
708
709
case DeclarationKind::ModuleBodyLevelFunction: {
710
MOZ_ASSERT(pc_->atModuleLevel());
711
712
AddDeclaredNamePtr p = pc_->varScope().lookupDeclaredNameForAdd(name);
713
if (p) {
714
reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
715
return false;
716
}
717
718
if (!pc_->varScope().addDeclaredName(pc_, p, name, kind, pos.begin)) {
719
return false;
720
}
721
722
// Body-level functions in modules are always closed over.
723
pc_->varScope().lookupDeclaredName(name)->value()->setClosedOver();
724
725
break;
726
}
727
728
case DeclarationKind::FormalParameter: {
729
// It is an early error if any non-positional formal parameter name
730
// (e.g., destructuring formal parameter) is duplicated.
731
732
AddDeclaredNamePtr p =
733
pc_->functionScope().lookupDeclaredNameForAdd(name);
734
if (p) {
735
error(JSMSG_BAD_DUP_ARGS);
736
return false;
737
}
738
739
if (!pc_->functionScope().addDeclaredName(pc_, p, name, kind,
740
pos.begin)) {
741
return false;
742
}
743
744
break;
745
}
746
747
case DeclarationKind::LexicalFunction: {
748
ParseContext::Scope* scope = pc_->innermostScope();
749
AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name);
750
if (p) {
751
reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
752
return false;
753
}
754
755
if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin)) {
756
return false;
757
}
758
759
break;
760
}
761
762
case DeclarationKind::SloppyLexicalFunction: {
763
// Functions in block have complex allowances in sloppy mode for being
764
// labelled that other lexical declarations do not have. Those checks
765
// are more complex than calling checkLexicalDeclarationDirectlyWithin-
766
// Block and are done in checkFunctionDefinition.
767
768
ParseContext::Scope* scope = pc_->innermostScope();
769
if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
770
// It is usually an early error if there is another declaration
771
// with the same name in the same scope.
772
//
773
// Sloppy lexical functions may redeclare other sloppy lexical
774
// functions for web compatibility reasons.
775
if (p->value()->kind() != DeclarationKind::SloppyLexicalFunction) {
776
reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
777
return false;
778
}
779
} else {
780
if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin)) {
781
return false;
782
}
783
}
784
785
break;
786
}
787
788
case DeclarationKind::Let:
789
case DeclarationKind::Const:
790
case DeclarationKind::Class:
791
// The BoundNames of LexicalDeclaration and ForDeclaration must not
792
// contain 'let'. (CatchParameter is the only lexical binding form
793
// without this restriction.)
794
if (name == cx_->names().let) {
795
errorAt(pos.begin, JSMSG_LEXICAL_DECL_DEFINES_LET);
796
return false;
797
}
798
799
MOZ_FALLTHROUGH;
800
801
case DeclarationKind::Import:
802
// Module code is always strict, so 'let' is always a keyword and never a
803
// name.
804
MOZ_ASSERT(name != cx_->names().let);
805
MOZ_FALLTHROUGH;
806
807
case DeclarationKind::SimpleCatchParameter:
808
case DeclarationKind::CatchParameter: {
809
if (ParseContext::Statement* stmt = pc_->innermostStatement()) {
810
if (!checkLexicalDeclarationDirectlyWithinBlock(*stmt, kind, pos)) {
811
return false;
812
}
813
}
814
815
ParseContext::Scope* scope = pc_->innermostScope();
816
817
// For body-level lexically declared names in a function, it is an
818
// early error if there is a formal parameter of the same name. This
819
// needs a special check if there is an extra var scope due to
820
// parameter expressions.
821
if (pc_->isFunctionExtraBodyVarScopeInnermost()) {
822
DeclaredNamePtr p = pc_->functionScope().lookupDeclaredName(name);
823
if (p && DeclarationKindIsParameter(p->value()->kind())) {
824
reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
825
return false;
826
}
827
}
828
829
// It is an early error if there is another declaration with the same
830
// name in the same scope.
831
AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name);
832
if (p) {
833
reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
834
return false;
835
}
836
837
if (!scope->addDeclaredName(pc_, p, name, kind, pos.begin)) {
838
return false;
839
}
840
841
break;
842
}
843
844
case DeclarationKind::CoverArrowParameter:
845
// CoverArrowParameter is only used as a placeholder declaration kind.
846
break;
847
848
case DeclarationKind::PositionalFormalParameter:
849
MOZ_CRASH(
850
"Positional formal parameter names should use "
851
"notePositionalFormalParameter");
852
break;
853
854
case DeclarationKind::VarForAnnexBLexicalFunction:
855
MOZ_CRASH(
856
"Synthesized Annex B vars should go through "
857
"tryDeclareVarForAnnexBLexicalFunction");
858
break;
859
}
860
861
return true;
862
}
863
864
bool ParserBase::noteUsedNameInternal(HandlePropertyName name) {
865
// The asm.js validator does all its own symbol-table management so, as an
866
// optimization, avoid doing any work here.
867
if (pc_->useAsmOrInsideUseAsm()) {
868
return true;
869
}
870
871
// Global bindings are properties and not actual bindings; we don't need
872
// to know if they are closed over. So no need to track used name at the
873
// global scope. It is not incorrect to track them, this is an
874
// optimization.
875
ParseContext::Scope* scope = pc_->innermostScope();
876
if (pc_->sc()->isGlobalContext() && scope == &pc_->varScope()) {
877
return true;
878
}
879
880
return usedNames_.noteUse(cx_, name, pc_->scriptId(), scope->id());
881
}
882
883
template <class ParseHandler>
884
bool PerHandlerParser<ParseHandler>::
885
propagateFreeNamesAndMarkClosedOverBindings(ParseContext::Scope& scope) {
886
// Now that we have all the declared names in the scope, check which
887
// functions should exhibit Annex B semantics.
888
if (!scope.propagateAndMarkAnnexBFunctionBoxes(pc_)) {
889
return false;
890
}
891
892
if (handler_.canSkipLazyClosedOverBindings()) {
893
// Scopes are nullptr-delimited in the LazyScript closed over bindings
894
// array.
895
while (JSAtom* name = handler_.nextLazyClosedOverBinding()) {
896
scope.lookupDeclaredName(name)->value()->setClosedOver();
897
}
898
return true;
899
}
900
901
bool isSyntaxParser =
902
mozilla::IsSame<ParseHandler, SyntaxParseHandler>::value;
903
uint32_t scriptId = pc_->scriptId();
904
uint32_t scopeId = scope.id();
905
906
for (BindingIter bi = scope.bindings(pc_); bi; bi++) {
907
if (UsedNamePtr p = usedNames_.lookup(bi.name())) {
908
bool closedOver;
909
p->value().noteBoundInScope(scriptId, scopeId, &closedOver);
910
if (closedOver) {
911
bi.setClosedOver();
912
913
if (isSyntaxParser &&
914
!pc_->closedOverBindingsForLazy().append(bi.name())) {
915
ReportOutOfMemory(cx_);
916
return false;
917
}
918
}
919
}
920
}
921
922
// Append a nullptr to denote end-of-scope.
923
if (isSyntaxParser && !pc_->closedOverBindingsForLazy().append(nullptr)) {
924
ReportOutOfMemory(cx_);
925
return false;
926
}
927
928
return true;
929
}
930
931
template <typename Unit>
932
bool Parser<FullParseHandler, Unit>::checkStatementsEOF() {
933
// This is designed to be paired with parsing a statement list at the top
934
// level.
935
//
936
// The statementList() call breaks on TokenKind::RightCurly, so make sure
937
// we've reached EOF here.
938
TokenKind tt;
939
if (!tokenStream.peekToken(&tt, TokenStream::SlashIsRegExp)) {
940
return false;
941
}
942
if (tt != TokenKind::Eof) {
943
error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt));
944
return false;
945
}
946
return true;
947
}
948
949
template <typename Scope>
950
typename Scope::Data* NewEmptyBindingData(JSContext* cx, LifoAlloc& alloc,
951
uint32_t numBindings) {
952
using Data = typename Scope::Data;
953
size_t allocSize = SizeOfData<typename Scope::Data>(numBindings);
954
auto* bindings = alloc.newWithSize<Data>(allocSize, numBindings);
955
if (!bindings) {
956
ReportOutOfMemory(cx);
957
}
958
return bindings;
959
}
960
961
namespace detail {
962
963
template <class Data>
964
static MOZ_ALWAYS_INLINE BindingName* InitializeIndexedBindings(
965
Data* data, BindingName* start, BindingName* cursor) {
966
return cursor;
967
}
968
969
template <class Data, typename UnsignedInteger, typename... Step>
970
static MOZ_ALWAYS_INLINE BindingName* InitializeIndexedBindings(
971
Data* data, BindingName* start, BindingName* cursor,
972
UnsignedInteger Data::*field, const BindingNameVector& bindings,
973
Step&&... step) {
974
data->*field = AssertedCast<UnsignedInteger>(PointerRangeSize(start, cursor));
975
976
BindingName* newCursor =
977
std::uninitialized_copy(bindings.begin(), bindings.end(), cursor);
978
979
return InitializeIndexedBindings(data, start, newCursor,
980
std::forward<Step>(step)...);
981
}
982
983
} // namespace detail
984
985
// Initialize |data->trailingNames| bindings, then set |data->length| to the
986
// count of bindings added (which must equal |count|).
987
//
988
// First, |firstBindings| are added to |data->trailingNames|. Then any "steps"
989
// present are performed first to last. Each step is 1) a pointer to a member
990
// of |data| to be set to the current number of bindings added, and 2) a vector
991
// of |BindingName|s to then copy into |data->trailingNames|. (Thus each
992
// |data| member field indicates where the corresponding vector's names start.)
993
template <class Data, typename... Step>
994
static MOZ_ALWAYS_INLINE void InitializeBindingData(
995
Data* data, uint32_t count, const BindingNameVector& firstBindings,
996
Step&&... step) {
997
MOZ_ASSERT(data->length == 0, "data shouldn't be filled yet");
998
999
BindingName* start = data->trailingNames.start();
1000
BindingName* cursor = std::uninitialized_copy(firstBindings.begin(),
1001
firstBindings.end(), start);
1002
1003
#ifdef DEBUG
1004
BindingName* end =
1005
#endif
1006
detail::InitializeIndexedBindings(data, start, cursor,
1007
std::forward<Step>(step)...);
1008
1009
MOZ_ASSERT(PointerRangeSize(start, end) == count);
1010
data->length = count;
1011
}
1012
1013
Maybe<GlobalScope::Data*> NewGlobalScopeData(JSContext* cx,
1014
ParseContext::Scope& scope,
1015
LifoAlloc& alloc,
1016
ParseContext* pc) {
1017
BindingNameVector vars(cx);
1018
BindingNameVector lets(cx);
1019
BindingNameVector consts(cx);
1020
1021
bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
1022
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1023
bool closedOver = allBindingsClosedOver || bi.closedOver();
1024
1025
switch (bi.kind()) {
1026
case BindingKind::Var: {
1027
bool isTopLevelFunction =
1028
bi.declarationKind() == DeclarationKind::BodyLevelFunction;
1029
BindingName binding(bi.name(), closedOver, isTopLevelFunction);
1030
if (!vars.append(binding)) {
1031
return Nothing();
1032
}
1033
break;
1034
}
1035
case BindingKind::Let: {
1036
BindingName binding(bi.name(), closedOver);
1037
if (!lets.append(binding)) {
1038
return Nothing();
1039
}
1040
break;
1041
}
1042
case BindingKind::Const: {
1043
BindingName binding(bi.name(), closedOver);
1044
if (!consts.append(binding)) {
1045
return Nothing();
1046
}
1047
break;
1048
}
1049
default:
1050
MOZ_CRASH("Bad global scope BindingKind");
1051
}
1052
}
1053
1054
GlobalScope::Data* bindings = nullptr;
1055
uint32_t numBindings = vars.length() + lets.length() + consts.length();
1056
1057
if (numBindings > 0) {
1058
bindings = NewEmptyBindingData<GlobalScope>(cx, alloc, numBindings);
1059
if (!bindings) {
1060
return Nothing();
1061
}
1062
1063
// The ordering here is important. See comments in GlobalScope.
1064
InitializeBindingData(bindings, numBindings, vars,
1065
&GlobalScope::Data::letStart, lets,
1066
&GlobalScope::Data::constStart, consts);
1067
}
1068
1069
return Some(bindings);
1070
}
1071
1072
Maybe<GlobalScope::Data*> ParserBase::newGlobalScopeData(
1073
ParseContext::Scope& scope) {
1074
return NewGlobalScopeData(cx_, scope, alloc_, pc_);
1075
}
1076
1077
Maybe<ModuleScope::Data*> NewModuleScopeData(JSContext* cx,
1078
ParseContext::Scope& scope,
1079
LifoAlloc& alloc,
1080
ParseContext* pc) {
1081
BindingNameVector imports(cx);
1082
BindingNameVector vars(cx);
1083
BindingNameVector lets(cx);
1084
BindingNameVector consts(cx);
1085
1086
bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
1087
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1088
// Imports are indirect bindings and must not be given known slots.
1089
BindingName binding(bi.name(), (allBindingsClosedOver || bi.closedOver()) &&
1090
bi.kind() != BindingKind::Import);
1091
switch (bi.kind()) {
1092
case BindingKind::Import:
1093
if (!imports.append(binding)) {
1094
return Nothing();
1095
}
1096
break;
1097
case BindingKind::Var:
1098
if (!vars.append(binding)) {
1099
return Nothing();
1100
}
1101
break;
1102
case BindingKind::Let:
1103
if (!lets.append(binding)) {
1104
return Nothing();
1105
}
1106
break;
1107
case BindingKind::Const:
1108
if (!consts.append(binding)) {
1109
return Nothing();
1110
}
1111
break;
1112
default:
1113
MOZ_CRASH("Bad module scope BindingKind");
1114
}
1115
}
1116
1117
ModuleScope::Data* bindings = nullptr;
1118
uint32_t numBindings =
1119
imports.length() + vars.length() + lets.length() + consts.length();
1120
1121
if (numBindings > 0) {
1122
bindings = NewEmptyBindingData<ModuleScope>(cx, alloc, numBindings);
1123
if (!bindings) {
1124
return Nothing();
1125
}
1126
1127
// The ordering here is important. See comments in ModuleScope.
1128
InitializeBindingData(bindings, numBindings, imports,
1129
&ModuleScope::Data::varStart, vars,
1130
&ModuleScope::Data::letStart, lets,
1131
&ModuleScope::Data::constStart, consts);
1132
}
1133
1134
return Some(bindings);
1135
}
1136
1137
Maybe<ModuleScope::Data*> ParserBase::newModuleScopeData(
1138
ParseContext::Scope& scope) {
1139
return NewModuleScopeData(cx_, scope, alloc_, pc_);
1140
}
1141
1142
Maybe<EvalScope::Data*> NewEvalScopeData(JSContext* cx,
1143
ParseContext::Scope& scope,
1144
LifoAlloc& alloc, ParseContext* pc) {
1145
BindingNameVector vars(cx);
1146
1147
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1148
// Eval scopes only contain 'var' bindings. Make all bindings aliased
1149
// for now.
1150
MOZ_ASSERT(bi.kind() == BindingKind::Var);
1151
bool isTopLevelFunction =
1152
bi.declarationKind() == DeclarationKind::BodyLevelFunction;
1153
BindingName binding(bi.name(), true, isTopLevelFunction);
1154
if (!vars.append(binding)) {
1155
return Nothing();
1156
}
1157
}
1158
1159
EvalScope::Data* bindings = nullptr;
1160
uint32_t numBindings = vars.length();
1161
1162
if (numBindings > 0) {
1163
bindings = NewEmptyBindingData<EvalScope>(cx, alloc, numBindings);
1164
if (!bindings) {
1165
return Nothing();
1166
}
1167
1168
InitializeBindingData(bindings, numBindings, vars);
1169
}
1170
1171
return Some(bindings);
1172
}
1173
1174
Maybe<EvalScope::Data*> ParserBase::newEvalScopeData(
1175
ParseContext::Scope& scope) {
1176
return NewEvalScopeData(cx_, scope, alloc_, pc_);
1177
}
1178
1179
Maybe<FunctionScope::Data*> NewFunctionScopeData(
1180
JSContext* cx, ParseContext::Scope& scope, bool hasParameterExprs,
1181
IsFieldInitializer isFieldInitializer, LifoAlloc& alloc, ParseContext* pc) {
1182
BindingNameVector positionalFormals(cx);
1183
BindingNameVector formals(cx);
1184
BindingNameVector vars(cx);
1185
1186
bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
1187
bool hasDuplicateParams = pc->functionBox()->hasDuplicateParameters;
1188
1189
// Positional parameter names must be added in order of appearance as they are
1190
// referenced using argument slots.
1191
for (size_t i = 0; i < pc->positionalFormalParameterNames().length(); i++) {
1192
JSAtom* name = pc->positionalFormalParameterNames()[i];
1193
1194
BindingName bindName;
1195
if (name) {
1196
DeclaredNamePtr p = scope.lookupDeclaredName(name);
1197
1198
// Do not consider any positional formal parameters closed over if
1199
// there are parameter defaults. It is the binding in the defaults
1200
// scope that is closed over instead.
1201
bool closedOver =
1202
allBindingsClosedOver || (p && p->value()->closedOver());
1203
1204
// If the parameter name has duplicates, only the final parameter
1205
// name should be on the environment, as otherwise the environment
1206
// object would have multiple, same-named properties.
1207
if (hasDuplicateParams) {
1208
for (size_t j = pc->positionalFormalParameterNames().length() - 1;
1209
j > i; j--) {
1210
if (pc->positionalFormalParameterNames()[j] == name) {
1211
closedOver = false;
1212
break;
1213
}
1214
}
1215
}
1216
1217
bindName = BindingName(name, closedOver);
1218
}
1219
1220
if (!positionalFormals.append(bindName)) {
1221
return Nothing();
1222
}
1223
}
1224
1225
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1226
BindingName binding(bi.name(), allBindingsClosedOver || bi.closedOver());
1227
switch (bi.kind()) {
1228
case BindingKind::FormalParameter:
1229
// Positional parameter names are already handled above.
1230
if (bi.declarationKind() == DeclarationKind::FormalParameter) {
1231
if (!formals.append(binding)) {
1232
return Nothing();
1233
}
1234
}
1235
break;
1236
case BindingKind::Var:
1237
// The only vars in the function scope when there are parameter
1238
// exprs, which induces a separate var environment, should be the
1239
// special bindings.
1240
MOZ_ASSERT_IF(hasParameterExprs,
1241
FunctionScope::isSpecialName(cx, bi.name()));
1242
if (!vars.append(binding)) {
1243
return Nothing();
1244
}
1245
break;
1246
default:
1247
break;
1248
}
1249
}
1250
1251
FunctionScope::Data* bindings = nullptr;
1252
uint32_t numBindings =
1253
positionalFormals.length() + formals.length() + vars.length();
1254
1255
if (numBindings > 0) {
1256
bindings = NewEmptyBindingData<FunctionScope>(cx, alloc, numBindings);
1257
if (!bindings) {
1258
return Nothing();
1259
}
1260
1261
bindings->isFieldInitializer = isFieldInitializer;
1262
1263
// The ordering here is important. See comments in FunctionScope.
1264
InitializeBindingData(bindings, numBindings, positionalFormals,
1265
&FunctionScope::Data::nonPositionalFormalStart,
1266
formals, &FunctionScope::Data::varStart, vars);
1267
}
1268
1269
return Some(bindings);
1270
}
1271
1272
Maybe<FunctionScope::Data*> ParserBase::newFunctionScopeData(
1273
ParseContext::Scope& scope, bool hasParameterExprs,
1274
IsFieldInitializer isFieldInitializer) {
1275
return NewFunctionScopeData(cx_, scope, hasParameterExprs, isFieldInitializer,
1276
alloc_, pc_);
1277
}
1278
1279
Maybe<VarScope::Data*> NewVarScopeData(JSContext* cx,
1280
ParseContext::Scope& scope,
1281
LifoAlloc& alloc, ParseContext* pc) {
1282
BindingNameVector vars(cx);
1283
1284
bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
1285
1286
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1287
if (bi.kind() == BindingKind::Var) {
1288
BindingName binding(bi.name(), allBindingsClosedOver || bi.closedOver());
1289
if (!vars.append(binding)) {
1290
return Nothing();
1291
}
1292
}
1293
}
1294
1295
VarScope::Data* bindings = nullptr;
1296
uint32_t numBindings = vars.length();
1297
1298
if (numBindings > 0) {
1299
bindings = NewEmptyBindingData<VarScope>(cx, alloc, numBindings);
1300
if (!bindings) {
1301
return Nothing();
1302
}
1303
1304
InitializeBindingData(bindings, numBindings, vars);
1305
}
1306
1307
return Some(bindings);
1308
}
1309
1310
Maybe<VarScope::Data*> ParserBase::newVarScopeData(ParseContext::Scope& scope) {
1311
return NewVarScopeData(cx_, scope, alloc_, pc_);
1312
}
1313
1314
Maybe<LexicalScope::Data*> NewLexicalScopeData(JSContext* cx,
1315
ParseContext::Scope& scope,
1316
LifoAlloc& alloc,
1317
ParseContext* pc) {
1318
BindingNameVector lets(cx);
1319
BindingNameVector consts(cx);
1320
1321
// Unlike other scopes with bindings which are body-level, it is unknown
1322
// if pc->sc()->allBindingsClosedOver() is correct at the time of
1323
// finishing parsing a lexical scope.
1324
//
1325
// Instead, pc->sc()->allBindingsClosedOver() is checked in
1326
// EmitterScope::enterLexical. Also see comment there.
1327
for (BindingIter bi = scope.bindings(pc); bi; bi++) {
1328
BindingName binding(bi.name(), bi.closedOver());
1329
switch (bi.kind()) {
1330
case BindingKind::Let:
1331
if (!lets.append(binding)) {
1332
return Nothing();
1333
}
1334
break;
1335
case BindingKind::Const:
1336
if (!consts.append(binding)) {
1337
return Nothing();
1338
}
1339
break;
1340
default:
1341
break;
1342
}
1343
}
1344
1345
LexicalScope::Data* bindings = nullptr;
1346
uint32_t numBindings = lets.length() + consts.length();
1347
1348
if (numBindings > 0) {
1349
bindings = NewEmptyBindingData<LexicalScope>(cx, alloc, numBindings);
1350
if (!bindings) {
1351
return Nothing();
1352
}
1353
1354
// The ordering here is important. See comments in LexicalScope.
1355
InitializeBindingData(bindings, numBindings, lets,
1356
&LexicalScope::Data::constStart, consts);
1357
}
1358
1359
return Some(bindings);
1360
}
1361
1362
Maybe<LexicalScope::Data*> ParserBase::newLexicalScopeData(
1363
ParseContext::Scope& scope) {
1364
return NewLexicalScopeData(cx_, scope, alloc_, pc_);
1365
}
1366
1367
template <>
1368
SyntaxParseHandler::LexicalScopeNodeType
1369
PerHandlerParser<SyntaxParseHandler>::finishLexicalScope(
1370
ParseContext::Scope& scope, Node body, ScopeKind kind) {
1371
if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
1372
return null();
1373
}
1374
1375
return handler_.newLexicalScope(body);
1376
}
1377
1378
template <>
1379
LexicalScopeNode* PerHandlerParser<FullParseHandler>::finishLexicalScope(
1380
ParseContext::Scope& scope, ParseNode* body, ScopeKind kind) {
1381
if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) {
1382
return nullptr;
1383
}
1384
1385
Maybe<LexicalScope::Data*> bindings = newLexicalScopeData(scope);
1386
if (!bindings) {
1387
return nullptr;
1388
}
1389
1390
return handler_.newLexicalScope(*bindings, body, kind);
1391
}
1392
1393
template <typename Unit>
1394
LexicalScopeNode* Parser<FullParseHandler, Unit>::evalBody(
1395
EvalSharedContext* evalsc) {
1396
SourceParseContext evalpc(this, evalsc, /* newDirectives = */ nullptr);
1397
if (!evalpc.init()) {
1398
return nullptr;
1399
}
1400
1401
ParseContext::VarScope varScope(this);
1402
if (!varScope.init(pc_)) {
1403
return nullptr;
1404
}
1405
1406
LexicalScopeNode* body;
1407
{
1408
// All evals have an implicit non-extensible lexical scope.
1409
ParseContext::Scope lexicalScope(this);
1410
if (!lexicalScope.init(pc_)) {
1411
return nullptr;
1412
}
1413
1414
ListNode* list = statementList(YieldIsName);
1415
if (!list) {
1416
return nullptr;
1417
}
1418
1419
if (!checkStatementsEOF()) {
1420
return nullptr;
1421
}
1422
1423
body = finishLexicalScope(lexicalScope, list);
1424
if (!body) {
1425
return nullptr;
1426
}
1427
}
1428
1429
#ifdef DEBUG
1430
if (evalpc.superScopeNeedsHomeObject() &&
1431
evalsc->compilationEnclosingScope()) {
1432
// If superScopeNeedsHomeObject_ is set and we are an entry-point
1433
// ParseContext, then we must be emitting an eval script, and the
1434
// outer function must already be marked as needing a home object
1435
// since it contains an eval.
1436
ScopeIter si(evalsc->compilationEnclosingScope());
1437
for (; si; si++) {
1438
if (si.kind() == ScopeKind::Function) {
1439
JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
1440
if (fun->isArrow()) {
1441
continue;
1442
}
1443
MOZ_ASSERT(fun->allowSuperProperty());
1444
MOZ_ASSERT(fun->nonLazyScript()->needsHomeObject());
1445
break;
1446
}
1447
}
1448
MOZ_ASSERT(!si.done(),
1449
"Eval must have found an enclosing function box scope that "
1450
"allows super.property");
1451
}
1452
#endif
1453
1454
if (!CheckParseTree(cx_, alloc_, body)) {
1455
return null();
1456
}
1457
1458
ParseNode* node = body;
1459
// Don't constant-fold inside "use asm" code, as this could create a parse
1460
// tree that doesn't type-check as asm.js.
1461
if (!pc_->useAsmOrInsideUseAsm()) {
1462
if (!FoldConstants(cx_, &node, &handler_)) {
1463
return null();
1464
}
1465
}
1466
body = handler_.asLexicalScope(node);
1467
1468
if (!this->setSourceMapInfo()) {
1469
return nullptr;
1470
}
1471
1472
// For eval scripts, since all bindings are automatically considered
1473
// closed over, we don't need to call propagateFreeNamesAndMarkClosed-
1474
// OverBindings. However, Annex B.3.3 functions still need to be marked.
1475
if (!varScope.propagateAndMarkAnnexBFunctionBoxes(pc_)) {
1476
return nullptr;
1477
}
1478
1479
Maybe<EvalScope::Data*> bindings = newEvalScopeData(pc_->varScope());
1480
if (!bindings) {
1481
return nullptr;
1482
}
1483
evalsc->bindings = *bindings;
1484
1485
return body;
1486
}
1487
1488
template <typename Unit>
1489
ListNode* Parser<FullParseHandler, Unit>::globalBody(
1490
GlobalSharedContext* globalsc) {
1491
SourceParseContext globalpc(this, globalsc, /* newDirectives = */ nullptr);
1492
if (!globalpc.init()) {
1493
return nullptr;
1494
}
1495
1496
ParseContext::VarScope varScope(this);
1497
if (!varScope.init(pc_)) {
1498
return nullptr;
1499
}
1500
1501
ListNode* body = statementList(YieldIsName);
1502
if (!body) {
1503
return nullptr;
1504
}
1505
1506
if (!checkStatementsEOF()) {
1507
return nullptr;
1508
}
1509
1510
if (!CheckParseTree(cx_, alloc_, body)) {
1511
return null();
1512
}
1513
1514
ParseNode* node = body;
1515
// Don't constant-fold inside "use asm" code, as this could create a parse
1516
// tree that doesn't type-check as asm.js.
1517
if (!pc_->useAsmOrInsideUseAsm()) {
1518
if (!FoldConstants(cx_, &node, &handler_)) {
1519
return null();
1520
}
1521
}
1522
body = &node->as<ListNode>();
1523
1524
if (!this->setSourceMapInfo()) {
1525
return nullptr;
1526
}
1527
1528
// For global scripts, whether bindings are closed over or not doesn't
1529
// matter, so no need to call propagateFreeNamesAndMarkClosedOver-
1530
// Bindings. However, Annex B.3.3 functions still need to be marked.
1531
if (!varScope.propagateAndMarkAnnexBFunctionBoxes(pc_)) {
1532
return nullptr;
1533
}
1534
1535
Maybe<GlobalScope::Data*> bindings = newGlobalScopeData(pc_->varScope());
1536
if (!bindings) {
1537
return nullptr;
1538
}
1539
globalsc->bindings = *bindings;
1540
1541
return body;
1542
}
1543
1544
template <typename Unit>
1545
ModuleNode* Parser<FullParseHandler, Unit>::moduleBody(
1546
ModuleSharedContext* modulesc) {
1547
MOZ_ASSERT(checkOptionsCalled_);
1548
1549
SourceParseContext modulepc(this, modulesc, nullptr);
1550
if (!modulepc.init()) {
1551
return null();
1552
}
1553
1554
ParseContext::VarScope varScope(this);
1555
if (!varScope.init(pc_)) {
1556
return nullptr;
1557
}
1558
1559
ModuleNodeType moduleNode = handler_.newModule(pos());
1560
if (!moduleNode) {
1561
return null();
1562
}
1563
1564
AutoAwaitIsKeyword<FullParseHandler, Unit> awaitIsKeyword(
1565
this, AwaitIsModuleKeyword);
1566
ListNode* stmtList = statementList(YieldIsName);
1567
if (!stmtList) {
1568
return null();
1569
}
1570
1571
MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
1572
moduleNode->setBody(&stmtList->as<ListNode>());
1573
1574
TokenKind tt;
1575
if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
1576
return null();
1577
}
1578
if (tt != TokenKind::Eof) {
1579
error(JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt));
1580
return null();
1581
}
1582
1583
if (!modulesc->builder.buildTables()) {
1584
return null();
1585
}
1586
1587
// Check exported local bindings exist and mark them as closed over.
1588
for (auto entry : modulesc->builder.localExportEntries()) {
1589
JSAtom* name = entry->localName();
1590
MOZ_ASSERT(name);
1591
1592
DeclaredNamePtr p = modulepc.varScope().lookupDeclaredName(name);
1593
if (!p) {
1594
UniqueChars str = AtomToPrintableString(cx_, name);
1595
if (!str) {
1596
return null();
1597
}
1598
1599
errorNoOffset(JSMSG_MISSING_EXPORT, str.get());
1600
return null();
1601
}
1602
1603
p->value()->setClosedOver();
1604
}
1605
1606
if (!CheckParseTree(cx_, alloc_, stmtList)) {
1607
return null();
1608
}
1609
1610
ParseNode* node = stmtList;
1611
// Don't constant-fold inside "use asm" code, as this could create a parse
1612
// tree that doesn't type-check as asm.js.
1613
if (!pc_->useAsmOrInsideUseAsm()) {
1614
if (!FoldConstants(cx_, &node, &handler_)) {
1615
return null();
1616
}
1617
}
1618
stmtList = &node->as<ListNode>();
1619
1620
if (!this->setSourceMapInfo()) {
1621
return null();
1622
}
1623
1624
if (!propagateFreeNamesAndMarkClosedOverBindings(modulepc.varScope())) {
1625
return null();
1626
}
1627
1628
Maybe<ModuleScope::Data*> bindings = newModuleScopeData(modulepc.varScope());
1629
if (!bindings) {
1630
return nullptr;
1631
}
1632
1633
modulesc->bindings = *bindings;
1634
return moduleNode;
1635
}
1636
1637
template <typename Unit>
1638
SyntaxParseHandler::ModuleNodeType Parser<SyntaxParseHandler, Unit>::moduleBody(
1639
ModuleSharedContext* modulesc) {
1640
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
1641
return SyntaxParseHandler::NodeFailure;
1642
}
1643
1644
template <class ParseHandler>
1645
typename ParseHandler::NameNodeType
1646
PerHandlerParser<ParseHandler>::newInternalDotName(HandlePropertyName name) {
1647
NameNodeType nameNode = newName(name);
1648
if (!nameNode) {
1649
return null();
1650
}
1651
if (!noteUsedName(name)) {
1652
return null();
1653
}
1654
return nameNode;
1655
}
1656
1657
template <class ParseHandler>
1658
typename ParseHandler::NameNodeType
1659
PerHandlerParser<ParseHandler>::newThisName() {
1660
return newInternalDotName(cx_->names().dotThis);
1661
}
1662
1663
template <class ParseHandler>
1664
typename ParseHandler::NameNodeType
1665
PerHandlerParser<ParseHandler>::newDotGeneratorName() {
1666
return newInternalDotName(cx_->names().dotGenerator);
1667
}
1668
1669
template <class ParseHandler>
1670
bool PerHandlerParser<ParseHandler>::finishFunctionScopes(
1671
bool isStandaloneFunction) {
1672
FunctionBox* funbox = pc_->functionBox();
1673
1674
if (funbox->hasParameterExprs) {
1675
if (!propagateFreeNamesAndMarkClosedOverBindings(pc_->functionScope())) {
1676
return false;
1677
}
1678
}
1679
1680
if (funbox->isNamedLambda() && !isStandaloneFunction) {
1681
if (!propagateFreeNamesAndMarkClosedOverBindings(pc_->namedLambdaScope())) {
1682
return false;
1683
}
1684
}
1685
1686
return true;
1687
}
1688
1689
template <>
1690
bool PerHandlerParser<FullParseHandler>::finishFunction(
1691
bool isStandaloneFunction /* = false */,
1692
IsFieldInitializer isFieldInitializer /* = IsFieldInitializer::No */) {
1693
if (!finishFunctionScopes(isStandaloneFunction)) {
1694
return false;
1695
}
1696
1697
FunctionBox* funbox = pc_->functionBox();
1698
funbox->synchronizeArgCount();
1699
1700
bool hasParameterExprs = funbox->hasParameterExprs;
1701
1702
if (hasParameterExprs) {
1703
Maybe<VarScope::Data*> bindings = newVarScopeData(pc_->varScope());
1704
if (!bindings) {
1705
return false;
1706
}
1707
funbox->extraVarScopeBindings().set(*bindings);
1708
}
1709
1710
{
1711
Maybe<FunctionScope::Data*> bindings = newFunctionScopeData(
1712
pc_->functionScope(), hasParameterExprs, isFieldInitializer);
1713
if (!bindings) {
1714
return false;
1715
}
1716
funbox->functionScopeBindings().set(*bindings);
1717
}
1718
1719
if (funbox->isNamedLambda() && !isStandaloneFunction) {
1720
Maybe<LexicalScope::Data*> bindings =
1721
newLexicalScopeData(pc_->namedLambdaScope());
1722
if (!bindings) {
1723
return false;
1724
}
1725
funbox->namedLambdaBindings().set(*bindings);
1726
}
1727
1728
return true;
1729
}
1730
1731
static bool EmitLazyScript(JSContext* cx, FunctionBox* funbox,
1732
HandleScriptSourceObject, ParseGoal parseGoal);
1733
1734
template <>
1735
bool PerHandlerParser<SyntaxParseHandler>::finishFunction(
1736
bool isStandaloneFunction /* = false */,
1737
IsFieldInitializer isFieldInitializer /* = IsFieldInitializer::Yes */) {
1738
// The LazyScript for a lazily parsed function needs to know its set of
1739
// free variables and inner functions so that when it is fully parsed, we
1740
// can skip over any already syntax parsed inner functions and still
1741
// retain correct scope information.
1742
1743
if (!finishFunctionScopes(isStandaloneFunction)) {
1744
return false;
1745
}
1746
1747
// There are too many bindings or inner functions to be saved into the
1748
// LazyScript. Do a full parse.
1749
if (pc_->closedOverBindingsForLazy().length() >=
1750
LazyScript::NumClosedOverBindingsLimit ||
1751
pc_->innerFunctionBoxesForLazy.length() >=
1752
LazyScript::NumInnerFunctionsLimit) {
1753
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
1754
return false;
1755
}
1756
1757
FunctionBox* funbox = pc_->functionBox();
1758
funbox->synchronizeArgCount();
1759
1760
// Use a ScopeExit to ensure the data is released on eager or error paths.
1761
// The funbox is in a LifoAlloc and will not have it's destructor called so
1762
// we need to be careful about ownership.
1763
auto cleanupGuard =
1764
mozilla::MakeScopeExit([funbox]() { funbox->lazyScriptData().reset(); });
1765
1766
// Emplace the data required for the lazy script here. It will
1767
// be emitted before the rest of script emission.
1768
funbox->lazyScriptData().emplace(cx_);
1769
if (!funbox->lazyScriptData()->init(cx_, pc_->closedOverBindingsForLazy(),
1770
pc_->innerFunctionBoxesForLazy,
1771
pc_->sc()->strict())) {
1772
return false;
1773
}
1774
1775
// If we can defer the LazyScript creation, we are now done.
1776
if (getTreeHolder().isDeferred()) {
1777
cleanupGuard.release();
1778
return true;
1779
}
1780
1781
// Eager Function tree mode, emit the lazy script now.
1782
return EmitLazyScript(cx_, funbox, sourceObject_, parseGoal());
1783
}
1784
1785
bool ParserBase::publishLazyScripts(FunctionTree* root) {
1786
if (root) {
1787
auto visitor = [](ParserBase* parser, FunctionTree* tree) {
1788
FunctionBox* funbox = tree->funbox();
1789
if (!funbox) {
1790
return true;
1791
}
1792
1793
// No lazy script data, so not a lazy function.
1794
if (!funbox->lazyScriptData().isSome()) {
1795
return true;
1796
}
1797
1798
return EmitLazyScript(parser->cx_, funbox, parser->sourceObject_,
1799
parser->parseGoal());
1800
};
1801
return root->visitRecursively(this->cx_, this, visitor);
1802
}
1803
return true;
1804
}
1805
1806
bool ParserBase::publishDeferredFunctions(FunctionTree* root) {
1807
if (root) {