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