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