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