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
#include "frontend/ParseContext-inl.h"
8
#include "vm/EnvironmentObject-inl.h"
9
10
using mozilla::Maybe;
11
using mozilla::Nothing;
12
using mozilla::Some;
13
14
namespace js {
15
namespace frontend {
16
17
using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
18
using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
19
20
const char* DeclarationKindString(DeclarationKind kind) {
21
switch (kind) {
22
case DeclarationKind::PositionalFormalParameter:
23
case DeclarationKind::FormalParameter:
24
return "formal parameter";
25
case DeclarationKind::CoverArrowParameter:
26
return "cover arrow parameter";
27
case DeclarationKind::Var:
28
return "var";
29
case DeclarationKind::Let:
30
return "let";
31
case DeclarationKind::Const:
32
return "const";
33
case DeclarationKind::Class:
34
return "class";
35
case DeclarationKind::Import:
36
return "import";
37
case DeclarationKind::BodyLevelFunction:
38
case DeclarationKind::ModuleBodyLevelFunction:
39
case DeclarationKind::LexicalFunction:
40
case DeclarationKind::SloppyLexicalFunction:
41
return "function";
42
case DeclarationKind::VarForAnnexBLexicalFunction:
43
return "annex b var";
44
case DeclarationKind::SimpleCatchParameter:
45
case DeclarationKind::CatchParameter:
46
return "catch parameter";
47
}
48
49
MOZ_CRASH("Bad DeclarationKind");
50
}
51
52
bool DeclarationKindIsVar(DeclarationKind kind) {
53
return kind == DeclarationKind::Var ||
54
kind == DeclarationKind::BodyLevelFunction ||
55
kind == DeclarationKind::VarForAnnexBLexicalFunction;
56
}
57
58
bool DeclarationKindIsParameter(DeclarationKind kind) {
59
return kind == DeclarationKind::PositionalFormalParameter ||
60
kind == DeclarationKind::FormalParameter;
61
}
62
63
bool UsedNameTracker::noteUse(JSContext* cx, JSAtom* name, uint32_t scriptId,
64
uint32_t scopeId) {
65
if (UsedNameMap::AddPtr p = map_.lookupForAdd(name)) {
66
if (!p->value().noteUsedInScope(scriptId, scopeId)) {
67
return false;
68
}
69
} else {
70
UsedNameInfo info(cx);
71
if (!info.noteUsedInScope(scriptId, scopeId)) {
72
return false;
73
}
74
if (!map_.add(p, name, std::move(info))) {
75
return false;
76
}
77
}
78
79
return true;
80
}
81
82
void UsedNameTracker::UsedNameInfo::resetToScope(uint32_t scriptId,
83
uint32_t scopeId) {
84
while (!uses_.empty()) {
85
Use& innermost = uses_.back();
86
if (innermost.scopeId < scopeId) {
87
break;
88
}
89
MOZ_ASSERT(innermost.scriptId >= scriptId);
90
uses_.popBack();
91
}
92
}
93
94
void UsedNameTracker::rewind(RewindToken token) {
95
scriptCounter_ = token.scriptId;
96
scopeCounter_ = token.scopeId;
97
98
for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
99
r.front().value().resetToScope(token.scriptId, token.scopeId);
100
}
101
}
102
103
void ParseContext::Scope::dump(ParseContext* pc) {
104
JSContext* cx = pc->sc()->cx_;
105
106
fprintf(stdout, "ParseScope %p", this);
107
108
fprintf(stdout, "\n decls:\n");
109
for (DeclaredNameMap::Range r = declared_->all(); !r.empty(); r.popFront()) {
110
UniqueChars bytes = AtomToPrintableString(cx, r.front().key());
111
if (!bytes) {
112
return;
113
}
114
DeclaredNameInfo& info = r.front().value().wrapped;
115
fprintf(stdout, " %s %s%s\n", DeclarationKindString(info.kind()),
116
bytes.get(), info.closedOver() ? " (closed over)" : "");
117
}
118
119
fprintf(stdout, "\n");
120
}
121
122
bool ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc,
123
FunctionBox* funbox) {
124
if (!possibleAnnexBFunctionBoxes_) {
125
if (!possibleAnnexBFunctionBoxes_.acquire(pc->sc()->cx_)) {
126
return false;
127
}
128
}
129
130
return maybeReportOOM(pc, possibleAnnexBFunctionBoxes_->append(funbox));
131
}
132
133
bool ParseContext::Scope::propagateAndMarkAnnexBFunctionBoxes(
134
ParseContext* pc) {
135
// Strict mode doesn't have wack Annex B function semantics.
136
if (pc->sc()->strict() || !possibleAnnexBFunctionBoxes_ ||
137
possibleAnnexBFunctionBoxes_->empty()) {
138
return true;
139
}
140
141
if (this == &pc->varScope()) {
142
// Base case: actually declare the Annex B vars and mark applicable
143
// function boxes as Annex B.
144
RootedPropertyName name(pc->sc()->cx_);
145
Maybe<DeclarationKind> redeclaredKind;
146
uint32_t unused;
147
for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
148
if (pc->annexBAppliesToLexicalFunctionInInnermostScope(funbox)) {
149
name = funbox->explicitName()->asPropertyName();
150
if (!pc->tryDeclareVar(
151
name, DeclarationKind::VarForAnnexBLexicalFunction,
152
DeclaredNameInfo::npos, &redeclaredKind, &unused)) {
153
return false;
154
}
155
156
MOZ_ASSERT(!redeclaredKind);
157
funbox->isAnnexB = true;
158
}
159
}
160
} else {
161
// Inner scope case: propagate still applicable function boxes to the
162
// enclosing scope.
163
for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
164
if (pc->annexBAppliesToLexicalFunctionInInnermostScope(funbox)) {
165
if (!enclosing()->addPossibleAnnexBFunctionBox(pc, funbox)) {
166
return false;
167
}
168
}
169
}
170
}
171
172
return true;
173
}
174
175
static bool DeclarationKindIsCatchParameter(DeclarationKind kind) {
176
return kind == DeclarationKind::SimpleCatchParameter ||
177
kind == DeclarationKind::CatchParameter;
178
}
179
180
bool ParseContext::Scope::addCatchParameters(ParseContext* pc,
181
Scope& catchParamScope) {
182
if (pc->useAsmOrInsideUseAsm()) {
183
return true;
184
}
185
186
for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
187
r.popFront()) {
188
DeclarationKind kind = r.front().value()->kind();
189
uint32_t pos = r.front().value()->pos();
190
MOZ_ASSERT(DeclarationKindIsCatchParameter(kind));
191
JSAtom* name = r.front().key();
192
AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name);
193
MOZ_ASSERT(!p);
194
if (!addDeclaredName(pc, p, name, kind, pos)) {
195
return false;
196
}
197
}
198
199
return true;
200
}
201
202
void ParseContext::Scope::removeCatchParameters(ParseContext* pc,
203
Scope& catchParamScope) {
204
if (pc->useAsmOrInsideUseAsm()) {
205
return;
206
}
207
208
for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
209
r.popFront()) {
210
DeclaredNamePtr p = declared_->lookup(r.front().key());
211
MOZ_ASSERT(p);
212
213
// This check is needed because the catch body could have declared
214
// vars, which would have been added to catchParamScope.
215
if (DeclarationKindIsCatchParameter(r.front().value()->kind())) {
216
declared_->remove(p);
217
}
218
}
219
}
220
221
ParseContext::ParseContext(JSContext* cx, ParseContext*& parent,
222
SharedContext* sc, ErrorReporter& errorReporter,
223
CompilationInfo& compilationInfo,
224
Directives* newDirectives, bool isFull)
225
: Nestable<ParseContext>(&parent),
226
traceLog_(sc->cx_,
227
isFull ? TraceLogger_ParsingFull : TraceLogger_ParsingSyntax,
228
errorReporter),
229
sc_(sc),
230
errorReporter_(errorReporter),
231
innermostStatement_(nullptr),
232
innermostScope_(nullptr),
233
varScope_(nullptr),
234
positionalFormalParameterNames_(cx->frontendCollectionPool()),
235
closedOverBindingsForLazy_(cx->frontendCollectionPool()),
236
innerFunctionIndexesForLazy(cx),
237
newDirectives(newDirectives),
238
lastYieldOffset(NoYieldOffset),
239
lastAwaitOffset(NoAwaitOffset),
240
scriptId_(compilationInfo.usedNames.nextScriptId()),
241
superScopeNeedsHomeObject_(false) {
242
if (isFunctionBox()) {
243
// We exclude ASM bodies because they are always eager, and the
244
// FunctionBoxes that get added to the tree in an AsmJS compilation
245
// don't have a long enough lifespan, as AsmJS marks the lifo allocator
246
// inside the ModuleValidator, and frees it again when that dies.
247
if (!this->functionBox()->useAsmOrInsideUseAsm()) {
248
tree.emplace(compilationInfo.treeHolder);
249
}
250
251
if (functionBox()->isNamedLambda()) {
252
namedLambdaScope_.emplace(cx, parent, compilationInfo.usedNames);
253
}
254
functionScope_.emplace(cx, parent, compilationInfo.usedNames);
255
}
256
}
257
258
bool ParseContext::init() {
259
if (scriptId_ == UINT32_MAX) {
260
errorReporter_.errorNoOffset(JSMSG_NEED_DIET, js_script_str);
261
return false;
262
}
263
264
JSContext* cx = sc()->cx_;
265
266
if (isFunctionBox()) {
267
if (tree) {
268
if (!tree->init(cx, this->functionBox())) {
269
return false;
270
}
271
}
272
// Named lambdas always need a binding for their own name. If this
273
// binding is closed over when we finish parsing the function in
274
// finishFunctionScopes, the function box needs to be marked as
275
// needing a dynamic DeclEnv object.
276
if (functionBox()->isNamedLambda()) {
277
if (!namedLambdaScope_->init(this)) {
278
return false;
279
}
280
AddDeclaredNamePtr p = namedLambdaScope_->lookupDeclaredNameForAdd(
281
functionBox()->explicitName());
282
MOZ_ASSERT(!p);
283
if (!namedLambdaScope_->addDeclaredName(
284
this, p, functionBox()->explicitName(), DeclarationKind::Const,
285
DeclaredNameInfo::npos)) {
286
return false;
287
}
288
}
289
290
if (!functionScope_->init(this)) {
291
return false;
292
}
293
294
if (!positionalFormalParameterNames_.acquire(cx)) {
295
return false;
296
}
297
}
298
299
if (!closedOverBindingsForLazy_.acquire(cx)) {
300
return false;
301
}
302
303
return true;
304
}
305
306
bool ParseContext::annexBAppliesToLexicalFunctionInInnermostScope(
307
FunctionBox* funbox) {
308
MOZ_ASSERT(!sc()->strict());
309
310
RootedPropertyName name(sc()->cx_, funbox->explicitName()->asPropertyName());
311
Maybe<DeclarationKind> redeclaredKind = isVarRedeclaredInInnermostScope(
312
name, DeclarationKind::VarForAnnexBLexicalFunction);
313
314
if (!redeclaredKind && isFunctionBox()) {
315
Scope& funScope = functionScope();
316
if (&funScope != &varScope()) {
317
// Annex B.3.3.1 disallows redeclaring parameter names. In the
318
// presence of parameter expressions, parameter names are on the
319
// function scope, which encloses the var scope. This means the
320
// isVarRedeclaredInInnermostScope call above would not catch this
321
// case, so test it manually.
322
if (DeclaredNamePtr p = funScope.lookupDeclaredName(name)) {
323
DeclarationKind declaredKind = p->value()->kind();
324
if (DeclarationKindIsParameter(declaredKind)) {
325
redeclaredKind = Some(declaredKind);
326
} else {
327
MOZ_ASSERT(FunctionScope::isSpecialName(sc()->cx_, name));
328
}
329
}
330
}
331
}
332
333
// If an early error would have occurred already, this function should not
334
// exhibit Annex B.3.3 semantics.
335
return !redeclaredKind;
336
}
337
338
Maybe<DeclarationKind> ParseContext::isVarRedeclaredInInnermostScope(
339
HandlePropertyName name, DeclarationKind kind) {
340
Maybe<DeclarationKind> redeclaredKind;
341
uint32_t unused;
342
MOZ_ALWAYS_TRUE(tryDeclareVarHelper<DryRunInnermostScopeOnly>(
343
name, kind, DeclaredNameInfo::npos, &redeclaredKind, &unused));
344
return redeclaredKind;
345
}
346
347
Maybe<DeclarationKind> ParseContext::isVarRedeclaredInEval(
348
HandlePropertyName name, DeclarationKind kind) {
349
MOZ_ASSERT(DeclarationKindIsVar(kind));
350
MOZ_ASSERT(sc()->isEvalContext());
351
352
// In the case of eval, we also need to check enclosing VM scopes to see
353
// if the var declaration is allowed in the context.
354
js::Scope* enclosingScope = sc()->compilationEnclosingScope();
355
js::Scope* varScope = EvalScope::nearestVarScopeForDirectEval(enclosingScope);
356
MOZ_ASSERT(varScope);
357
for (ScopeIter si(enclosingScope); si; si++) {
358
for (js::BindingIter bi(si.scope()); bi; bi++) {
359
if (bi.name() != name) {
360
continue;
361
}
362
363
switch (bi.kind()) {
364
case BindingKind::Let: {
365
// Annex B.3.5 allows redeclaring simple (non-destructured)
366
// catch parameters with var declarations.
367
bool annexB35Allowance = si.kind() == ScopeKind::SimpleCatch;
368
if (!annexB35Allowance) {
369
return Some(ScopeKindIsCatch(si.kind())
370
? DeclarationKind::CatchParameter
371
: DeclarationKind::Let);
372
}
373
break;
374
}
375
376
case BindingKind::Const:
377
return Some(DeclarationKind::Const);
378
379
case BindingKind::Import:
380
case BindingKind::FormalParameter:
381
case BindingKind::Var:
382
case BindingKind::NamedLambdaCallee:
383
break;
384
}
385
}
386
387
if (si.scope() == varScope) {
388
break;
389
}
390
}
391
392
return Nothing();
393
}
394
395
bool ParseContext::tryDeclareVar(HandlePropertyName name, DeclarationKind kind,
396
uint32_t beginPos,
397
Maybe<DeclarationKind>* redeclaredKind,
398
uint32_t* prevPos) {
399
return tryDeclareVarHelper<NotDryRun>(name, kind, beginPos, redeclaredKind,
400
prevPos);
401
}
402
403
template <ParseContext::DryRunOption dryRunOption>
404
bool ParseContext::tryDeclareVarHelper(HandlePropertyName name,
405
DeclarationKind kind, uint32_t beginPos,
406
Maybe<DeclarationKind>* redeclaredKind,
407
uint32_t* prevPos) {
408
MOZ_ASSERT(DeclarationKindIsVar(kind));
409
410
// It is an early error if a 'var' declaration appears inside a
411
// scope contour that has a lexical declaration of the same name. For
412
// example, the following are early errors:
413
//
414
// { let x; var x; }
415
// { { var x; } let x; }
416
//
417
// And the following are not:
418
//
419
// { var x; var x; }
420
// { { let x; } var x; }
421
422
for (ParseContext::Scope* scope = innermostScope();
423
scope != varScope().enclosing(); scope = scope->enclosing()) {
424
if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
425
DeclarationKind declaredKind = p->value()->kind();
426
if (DeclarationKindIsVar(declaredKind)) {
427
if (dryRunOption == NotDryRun) {
428
RedeclareVar(p, kind);
429
}
430
} else if (!DeclarationKindIsParameter(declaredKind)) {
431
// Annex B.3.5 allows redeclaring simple (non-destructured)
432
// catch parameters with var declarations.
433
bool annexB35Allowance =
434
declaredKind == DeclarationKind::SimpleCatchParameter;
435
436
// Annex B.3.3 allows redeclaring functions in the same block.
437
bool annexB33Allowance =
438
declaredKind == DeclarationKind::SloppyLexicalFunction &&
439
kind == DeclarationKind::VarForAnnexBLexicalFunction &&
440
scope == innermostScope();
441
442
if (!annexB35Allowance && !annexB33Allowance) {
443
*redeclaredKind = Some(declaredKind);
444
*prevPos = p->value()->pos();
445
return true;
446
}
447
} else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) {
448
MOZ_ASSERT(DeclarationKindIsParameter(declaredKind));
449
450
// Annex B.3.3.1 disallows redeclaring parameter names.
451
// We don't need to set *prevPos here since this case is not
452
// an error.
453
*redeclaredKind = Some(declaredKind);
454
return true;
455
}
456
} else if (dryRunOption == NotDryRun) {
457
if (!scope->addDeclaredName(this, p, name, kind, beginPos)) {
458
return false;
459
}
460
}
461
462
// DryRunOption is used for propagating Annex B functions: we don't
463
// want to declare the synthesized Annex B vars until we exit the var
464
// scope and know that no early errors would have occurred. In order
465
// to avoid quadratic search, we only check for var redeclarations in
466
// the innermost scope when doing a dry run.
467
if (dryRunOption == DryRunInnermostScopeOnly) {
468
break;
469
}
470
}
471
472
if (!sc()->strict() && sc()->isEvalContext() &&
473
(dryRunOption == NotDryRun || innermostScope() == &varScope())) {
474
*redeclaredKind = isVarRedeclaredInEval(name, kind);
475
// We don't have position information at runtime.
476
*prevPos = DeclaredNameInfo::npos;
477
}
478
479
return true;
480
}
481
482
bool ParseContext::hasUsedName(const UsedNameTracker& usedNames,
483
HandlePropertyName name) {
484
if (auto p = usedNames.lookup(name)) {
485
return p->value().isUsedInScript(scriptId());
486
}
487
return false;
488
}
489
490
bool ParseContext::hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
491
HandlePropertyName name) {
492
MOZ_ASSERT(name == sc()->cx_->names().arguments ||
493
name == sc()->cx_->names().dotThis);
494
return hasUsedName(usedNames, name) ||
495
functionBox()->bindingsAccessedDynamically();
496
}
497
498
bool ParseContext::declareFunctionThis(const UsedNameTracker& usedNames,
499
bool canSkipLazyClosedOverBindings) {
500
// The asm.js validator does all its own symbol-table management so, as an
501
// optimization, avoid doing any work here.
502
if (useAsmOrInsideUseAsm()) {
503
return true;
504
}
505
506
// Derived class constructors emit JSOp::CheckReturn, which requires
507
// '.this' to be bound.
508
FunctionBox* funbox = functionBox();
509
HandlePropertyName dotThis = sc()->cx_->names().dotThis;
510
511
bool declareThis;
512
if (canSkipLazyClosedOverBindings) {
513
declareThis = funbox->function()->baseScript()->functionHasThisBinding();
514
} else {
515
declareThis = hasUsedFunctionSpecialName(usedNames, dotThis) ||
516
funbox->isClassConstructor();
517
}
518
519
if (declareThis) {
520
ParseContext::Scope& funScope = functionScope();
521
AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis);
522
MOZ_ASSERT(!p);
523
if (!funScope.addDeclaredName(this, p, dotThis, DeclarationKind::Var,
524
DeclaredNameInfo::npos)) {
525
return false;
526
}
527
funbox->setHasThisBinding();
528
}
529
530
return true;
531
}
532
533
bool ParseContext::declareFunctionArgumentsObject(
534
const UsedNameTracker& usedNames, bool canSkipLazyClosedOverBindings) {
535
FunctionBox* funbox = functionBox();
536
ParseContext::Scope& funScope = functionScope();
537
ParseContext::Scope& _varScope = varScope();
538
539
bool hasExtraBodyVarScope = &funScope != &_varScope;
540
541
// Time to implement the odd semantics of 'arguments'.
542
HandlePropertyName argumentsName = sc()->cx_->names().arguments;
543
544
bool tryDeclareArguments;
545
if (canSkipLazyClosedOverBindings) {
546
tryDeclareArguments =
547
funbox->function()->baseScript()->shouldDeclareArguments();
548
} else {
549
tryDeclareArguments = hasUsedFunctionSpecialName(usedNames, argumentsName);
550
}
551
552
// ES 9.2.12 steps 19 and 20 say formal parameters, lexical bindings,
553
// and body-level functions named 'arguments' shadow the arguments
554
// object.
555
//
556
// So even if there wasn't a free use of 'arguments' but there is a var
557
// binding of 'arguments', we still might need the arguments object.
558
//
559
// If we have an extra var scope due to parameter expressions and the body
560
// declared 'var arguments', we still need to declare 'arguments' in the
561
// function scope.
562
DeclaredNamePtr p = _varScope.lookupDeclaredName(argumentsName);
563
if (p && p->value()->kind() == DeclarationKind::Var) {
564
if (hasExtraBodyVarScope) {
565
tryDeclareArguments = true;
566
} else {
567
funbox->usesArguments = true;
568
}
569
}
570
571
if (tryDeclareArguments) {
572
AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName);
573
if (!p) {
574
if (!funScope.addDeclaredName(this, p, argumentsName,
575
DeclarationKind::Var,
576
DeclaredNameInfo::npos)) {
577
return false;
578
}
579
funbox->setDeclaredArguments();
580
funbox->usesArguments = true;
581
} else if (hasExtraBodyVarScope) {
582
// Formal parameters shadow the arguments object.
583
return true;
584
}
585
}
586
587
// Compute if we need an arguments object.
588
if (funbox->usesArguments) {
589
// There is an 'arguments' binding. Is the arguments object definitely
590
// needed?
591
//
592
// Also see the flags' comments in ContextFlags.
593
funbox->setArgumentsHasVarBinding();
594
595
// Dynamic scope access destroys all hope of optimization.
596
if (sc()->bindingsAccessedDynamically()) {
597
funbox->setAlwaysNeedsArgsObj();
598
}
599
}
600
601
return true;
602
}
603
604
bool ParseContext::declareDotGeneratorName() {
605
// The special '.generator' binding must be on the function scope, as
606
// generators expect to find it on the CallObject.
607
ParseContext::Scope& funScope = functionScope();
608
HandlePropertyName dotGenerator = sc()->cx_->names().dotGenerator;
609
AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator);
610
if (!p &&
611
!funScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
612
DeclaredNameInfo::npos)) {
613
return false;
614
}
615
return true;
616
}
617
618
} // namespace frontend
619
620
} // namespace js