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