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