Backed out 3 changesets (bug 1901078, bug 1749048) for causing interface related...
[gecko.git] / js / src / frontend / ParseContext.cpp
blobb3dd037d8d370d480d23b6d48863243755085bf8
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/. */
7 #include "frontend/ParseContext-inl.h"
9 #include "frontend/CompilationStencil.h" // ScopeContext
10 #include "frontend/Parser.h" // ParserBase
11 #include "js/friend/ErrorMessages.h" // JSMSG_*
13 using mozilla::Maybe;
14 using mozilla::Nothing;
15 using mozilla::Some;
17 namespace js {
18 namespace frontend {
20 using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
21 using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
23 const char* DeclarationKindString(DeclarationKind kind) {
24 switch (kind) {
25 case DeclarationKind::PositionalFormalParameter:
26 case DeclarationKind::FormalParameter:
27 return "formal parameter";
28 case DeclarationKind::CoverArrowParameter:
29 return "cover arrow parameter";
30 case DeclarationKind::Var:
31 return "var";
32 case DeclarationKind::Let:
33 return "let";
34 case DeclarationKind::Const:
35 return "const";
36 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
37 case DeclarationKind::Using:
38 return "using";
39 case DeclarationKind::AwaitUsing:
40 return "await using";
41 #endif
42 case DeclarationKind::Class:
43 return "class";
44 case DeclarationKind::Import:
45 return "import";
46 case DeclarationKind::BodyLevelFunction:
47 case DeclarationKind::ModuleBodyLevelFunction:
48 case DeclarationKind::LexicalFunction:
49 case DeclarationKind::SloppyLexicalFunction:
50 return "function";
51 case DeclarationKind::VarForAnnexBLexicalFunction:
52 return "annex b var";
53 case DeclarationKind::SimpleCatchParameter:
54 case DeclarationKind::CatchParameter:
55 return "catch parameter";
56 case DeclarationKind::PrivateName:
57 return "private name";
58 case DeclarationKind::Synthetic:
59 return "synthetic";
60 case DeclarationKind::PrivateMethod:
61 return "private method";
64 MOZ_CRASH("Bad DeclarationKind");
67 bool DeclarationKindIsVar(DeclarationKind kind) {
68 return kind == DeclarationKind::Var ||
69 kind == DeclarationKind::BodyLevelFunction ||
70 kind == DeclarationKind::VarForAnnexBLexicalFunction;
73 bool DeclarationKindIsParameter(DeclarationKind kind) {
74 return kind == DeclarationKind::PositionalFormalParameter ||
75 kind == DeclarationKind::FormalParameter;
78 bool UsedNameTracker::noteUse(FrontendContext* fc, TaggedParserAtomIndex name,
79 NameVisibility visibility, uint32_t scriptId,
80 uint32_t scopeId,
81 mozilla::Maybe<TokenPos> tokenPosition) {
82 if (UsedNameMap::AddPtr p = map_.lookupForAdd(name)) {
83 p->value().maybeUpdatePos(tokenPosition);
85 if (!p->value().noteUsedInScope(scriptId, scopeId)) {
86 return false;
88 } else {
89 // We need a token position precisely where we have private visibility.
90 MOZ_ASSERT(tokenPosition.isSome() ==
91 (visibility == NameVisibility::Private));
93 if (visibility == NameVisibility::Private) {
94 // We have seen at least one private name
95 hasPrivateNames_ = true;
98 UsedNameInfo info(fc, visibility, tokenPosition);
100 if (!info.noteUsedInScope(scriptId, scopeId)) {
101 return false;
103 if (!map_.add(p, name, std::move(info))) {
104 return false;
108 return true;
111 bool UsedNameTracker::getUnboundPrivateNames(
112 Vector<UnboundPrivateName, 8>& unboundPrivateNames) {
113 // We never saw any private names, so can just return early
114 if (!hasPrivateNames_) {
115 return true;
118 for (auto iter = map_.iter(); !iter.done(); iter.next()) {
119 // Don't care about public;
120 if (iter.get().value().isPublic()) {
121 continue;
124 // empty list means all bound
125 if (iter.get().value().empty()) {
126 continue;
129 if (!unboundPrivateNames.emplaceBack(iter.get().key(),
130 *iter.get().value().pos())) {
131 return false;
135 // Return a sorted list in ascendng order of position.
136 auto comparePosition = [](const auto& a, const auto& b) {
137 return a.position < b.position;
139 std::sort(unboundPrivateNames.begin(), unboundPrivateNames.end(),
140 comparePosition);
142 return true;
145 bool UsedNameTracker::hasUnboundPrivateNames(
146 FrontendContext* fc, mozilla::Maybe<UnboundPrivateName>& maybeUnboundName) {
147 // We never saw any private names, so can just return early
148 if (!hasPrivateNames_) {
149 return true;
152 Vector<UnboundPrivateName, 8> unboundPrivateNames(fc);
153 if (!getUnboundPrivateNames(unboundPrivateNames)) {
154 return false;
157 if (unboundPrivateNames.empty()) {
158 return true;
161 // GetUnboundPrivateNames returns the list sorted.
162 maybeUnboundName.emplace(unboundPrivateNames[0]);
163 return true;
166 void UsedNameTracker::UsedNameInfo::resetToScope(uint32_t scriptId,
167 uint32_t scopeId) {
168 while (!uses_.empty()) {
169 Use& innermost = uses_.back();
170 if (innermost.scopeId < scopeId) {
171 break;
173 MOZ_ASSERT(innermost.scriptId >= scriptId);
174 uses_.popBack();
178 void UsedNameTracker::rewind(RewindToken token) {
179 scriptCounter_ = token.scriptId;
180 scopeCounter_ = token.scopeId;
182 for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
183 r.front().value().resetToScope(token.scriptId, token.scopeId);
187 #if defined(DEBUG) || defined(JS_JITSPEW)
188 void UsedNameTracker::dump(ParserAtomsTable& table) {
189 js::Fprinter out(stderr);
191 out.printf("Used names:\n");
193 for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
194 const auto& item = r.front();
196 const auto& name = item.key();
197 const auto& nameInfo = item.value();
199 out.put(" ");
200 table.dumpCharsNoQuote(out, name);
201 out.put("\n");
203 if (nameInfo.visibility_ == NameVisibility::Private) {
204 out.put(" visibility: private\n");
207 if (nameInfo.firstUsePos_) {
208 const auto& pos = *nameInfo.firstUsePos_;
209 out.printf(" first use pos: %u\n", pos.begin);
212 out.printf(" %zu user(s)", nameInfo.uses_.length());
213 bool first = true;
214 for (const auto& use : nameInfo.uses_) {
215 if (first) {
216 first = false;
217 out.put(" (");
218 } else {
219 out.put(", ");
221 out.printf("%u/%u", use.scriptId, use.scopeId);
223 if (!first) {
224 out.put(")");
226 out.put("\n");
229 #endif
231 void ParseContext::Scope::dump(ParseContext* pc, ParserBase* parser) {
232 fprintf(stdout, "ParseScope %p", this);
234 fprintf(stdout, "\n decls:\n");
235 for (DeclaredNameMap::Range r = declared_->all(); !r.empty(); r.popFront()) {
236 auto index = r.front().key();
237 UniqueChars bytes = parser->parserAtoms().toPrintableString(index);
238 if (!bytes) {
239 ReportOutOfMemory(pc->sc()->fc_);
240 return;
242 DeclaredNameInfo& info = r.front().value().wrapped;
243 fprintf(stdout, " %s %s%s\n", DeclarationKindString(info.kind()),
244 bytes.get(), info.closedOver() ? " (closed over)" : "");
247 fprintf(stdout, "\n");
250 bool ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc,
251 FunctionBox* funbox) {
252 if (!possibleAnnexBFunctionBoxes_) {
253 if (!possibleAnnexBFunctionBoxes_.acquire(pc->sc()->fc_)) {
254 return false;
258 return maybeReportOOM(pc, possibleAnnexBFunctionBoxes_->append(funbox));
261 bool ParseContext::Scope::propagateAndMarkAnnexBFunctionBoxes(
262 ParseContext* pc, ParserBase* parser) {
263 // Strict mode doesn't have wack Annex B function semantics.
264 if (pc->sc()->strict() || !possibleAnnexBFunctionBoxes_ ||
265 possibleAnnexBFunctionBoxes_->empty()) {
266 return true;
269 if (this == &pc->varScope()) {
270 // Base case: actually declare the Annex B vars and mark applicable
271 // function boxes as Annex B.
272 Maybe<DeclarationKind> redeclaredKind;
273 uint32_t unused;
274 for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
275 bool annexBApplies;
276 if (!pc->computeAnnexBAppliesToLexicalFunctionInInnermostScope(
277 funbox, parser, &annexBApplies)) {
278 return false;
280 if (annexBApplies) {
281 if (!pc->tryDeclareVar(funbox->explicitName(), parser,
282 DeclarationKind::VarForAnnexBLexicalFunction,
283 DeclaredNameInfo::npos, &redeclaredKind,
284 &unused)) {
285 return false;
288 MOZ_ASSERT(!redeclaredKind);
289 funbox->isAnnexB = true;
292 } else {
293 // Inner scope case: propagate still applicable function boxes to the
294 // enclosing scope.
295 for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
296 bool annexBApplies;
297 if (!pc->computeAnnexBAppliesToLexicalFunctionInInnermostScope(
298 funbox, parser, &annexBApplies)) {
299 return false;
301 if (annexBApplies) {
302 if (!enclosing()->addPossibleAnnexBFunctionBox(pc, funbox)) {
303 return false;
309 return true;
312 static bool DeclarationKindIsCatchParameter(DeclarationKind kind) {
313 return kind == DeclarationKind::SimpleCatchParameter ||
314 kind == DeclarationKind::CatchParameter;
317 bool ParseContext::Scope::addCatchParameters(ParseContext* pc,
318 Scope& catchParamScope) {
319 if (pc->useAsmOrInsideUseAsm()) {
320 return true;
323 for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
324 r.popFront()) {
325 DeclarationKind kind = r.front().value()->kind();
326 uint32_t pos = r.front().value()->pos();
327 MOZ_ASSERT(DeclarationKindIsCatchParameter(kind));
328 auto name = r.front().key();
329 AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name);
330 MOZ_ASSERT(!p);
331 if (!addDeclaredName(pc, p, name, kind, pos)) {
332 return false;
336 return true;
339 void ParseContext::Scope::removeCatchParameters(ParseContext* pc,
340 Scope& catchParamScope) {
341 if (pc->useAsmOrInsideUseAsm()) {
342 return;
345 for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
346 r.popFront()) {
347 auto name = r.front().key();
348 DeclaredNamePtr p = declared_->lookup(name);
349 MOZ_ASSERT(p);
351 // This check is needed because the catch body could have declared
352 // vars, which would have been added to catchParamScope.
353 if (DeclarationKindIsCatchParameter(r.front().value()->kind())) {
354 declared_->remove(p);
359 ParseContext::ParseContext(FrontendContext* fc, ParseContext*& parent,
360 SharedContext* sc, ErrorReporter& errorReporter,
361 CompilationState& compilationState,
362 Directives* newDirectives, bool isFull)
363 : Nestable<ParseContext>(&parent),
364 sc_(sc),
365 errorReporter_(errorReporter),
366 innermostStatement_(nullptr),
367 innermostScope_(nullptr),
368 varScope_(nullptr),
369 positionalFormalParameterNames_(fc->nameCollectionPool()),
370 closedOverBindingsForLazy_(fc->nameCollectionPool()),
371 innerFunctionIndexesForLazy(sc->fc_),
372 newDirectives(newDirectives),
373 lastYieldOffset(NoYieldOffset),
374 lastAwaitOffset(NoAwaitOffset),
375 scriptId_(compilationState.usedNames.nextScriptId()),
376 superScopeNeedsHomeObject_(false) {
377 if (isFunctionBox()) {
378 if (functionBox()->isNamedLambda()) {
379 namedLambdaScope_.emplace(fc, parent, compilationState.usedNames);
381 functionScope_.emplace(fc, parent, compilationState.usedNames);
385 bool ParseContext::init() {
386 if (scriptId_ == UINT32_MAX) {
387 errorReporter_.errorNoOffset(JSMSG_NEED_DIET, "script");
388 return false;
391 FrontendContext* fc = sc()->fc_;
393 if (isFunctionBox()) {
394 // Named lambdas always need a binding for their own name. If this
395 // binding is closed over when we finish parsing the function iNn
396 // finishFunctionScopes, the function box needs to be marked as
397 // needing a dynamic DeclEnv object.
398 if (functionBox()->isNamedLambda()) {
399 if (!namedLambdaScope_->init(this)) {
400 return false;
402 AddDeclaredNamePtr p = namedLambdaScope_->lookupDeclaredNameForAdd(
403 functionBox()->explicitName());
404 MOZ_ASSERT(!p);
405 if (!namedLambdaScope_->addDeclaredName(
406 this, p, functionBox()->explicitName(), DeclarationKind::Const,
407 DeclaredNameInfo::npos)) {
408 return false;
412 if (!functionScope_->init(this)) {
413 return false;
416 if (!positionalFormalParameterNames_.acquire(fc)) {
417 return false;
421 if (!closedOverBindingsForLazy_.acquire(fc)) {
422 return false;
425 return true;
428 bool ParseContext::computeAnnexBAppliesToLexicalFunctionInInnermostScope(
429 FunctionBox* funbox, ParserBase* parser, bool* annexBApplies) {
430 MOZ_ASSERT(!sc()->strict());
432 TaggedParserAtomIndex name = funbox->explicitName();
433 Maybe<DeclarationKind> redeclaredKind;
434 if (!isVarRedeclaredInInnermostScope(
435 name, parser, DeclarationKind::VarForAnnexBLexicalFunction,
436 &redeclaredKind)) {
437 return false;
440 if (!redeclaredKind && isFunctionBox()) {
441 Scope& funScope = functionScope();
442 if (&funScope != &varScope()) {
443 // Annex B.3.3.1 disallows redeclaring parameter names. In the
444 // presence of parameter expressions, parameter names are on the
445 // function scope, which encloses the var scope. This means the
446 // isVarRedeclaredInInnermostScope call above would not catch this
447 // case, so test it manually.
448 if (DeclaredNamePtr p = funScope.lookupDeclaredName(name)) {
449 DeclarationKind declaredKind = p->value()->kind();
450 if (DeclarationKindIsParameter(declaredKind)) {
451 redeclaredKind = Some(declaredKind);
452 } else {
453 MOZ_ASSERT(FunctionScope::isSpecialName(name));
459 // If an early error would have occurred already, this function should not
460 // exhibit Annex B.3.3 semantics.
461 *annexBApplies = !redeclaredKind;
462 return true;
465 bool ParseContext::isVarRedeclaredInInnermostScope(
466 TaggedParserAtomIndex name, ParserBase* parser, DeclarationKind kind,
467 mozilla::Maybe<DeclarationKind>* out) {
468 uint32_t unused;
469 return tryDeclareVarHelper<DryRunInnermostScopeOnly>(
470 name, parser, kind, DeclaredNameInfo::npos, out, &unused);
473 bool ParseContext::isVarRedeclaredInEval(TaggedParserAtomIndex name,
474 ParserBase* parser,
475 DeclarationKind kind,
476 Maybe<DeclarationKind>* out) {
477 auto maybeKind = parser->getCompilationState()
478 .scopeContext.lookupLexicalBindingInEnclosingScope(name);
479 if (!maybeKind) {
480 *out = Nothing();
481 return true;
484 switch (*maybeKind) {
485 case ScopeContext::EnclosingLexicalBindingKind::Let:
486 *out = Some(DeclarationKind::Let);
487 break;
488 case ScopeContext::EnclosingLexicalBindingKind::Const:
489 *out = Some(DeclarationKind::Const);
490 break;
491 case ScopeContext::EnclosingLexicalBindingKind::CatchParameter:
492 *out = Some(DeclarationKind::CatchParameter);
493 break;
494 case ScopeContext::EnclosingLexicalBindingKind::Synthetic:
495 *out = Some(DeclarationKind::Synthetic);
496 break;
497 case ScopeContext::EnclosingLexicalBindingKind::PrivateMethod:
498 *out = Some(DeclarationKind::PrivateMethod);
499 break;
501 return true;
504 bool ParseContext::tryDeclareVar(TaggedParserAtomIndex name, ParserBase* parser,
505 DeclarationKind kind, uint32_t beginPos,
506 Maybe<DeclarationKind>* redeclaredKind,
507 uint32_t* prevPos) {
508 return tryDeclareVarHelper<NotDryRun>(name, parser, kind, beginPos,
509 redeclaredKind, prevPos);
512 template <ParseContext::DryRunOption dryRunOption>
513 bool ParseContext::tryDeclareVarHelper(TaggedParserAtomIndex name,
514 ParserBase* parser, DeclarationKind kind,
515 uint32_t beginPos,
516 Maybe<DeclarationKind>* redeclaredKind,
517 uint32_t* prevPos) {
518 MOZ_ASSERT(DeclarationKindIsVar(kind));
520 // It is an early error if a 'var' declaration appears inside a
521 // scope contour that has a lexical declaration of the same name. For
522 // example, the following are early errors:
524 // { let x; var x; }
525 // { { var x; } let x; }
527 // And the following are not:
529 // { var x; var x; }
530 // { { let x; } var x; }
532 for (ParseContext::Scope* scope = innermostScope();
533 scope != varScope().enclosing(); scope = scope->enclosing()) {
534 if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
535 DeclarationKind declaredKind = p->value()->kind();
536 if (DeclarationKindIsVar(declaredKind)) {
537 if (dryRunOption == NotDryRun) {
538 RedeclareVar(p, kind);
540 } else if (!DeclarationKindIsParameter(declaredKind)) {
541 // Annex B.3.5 allows redeclaring simple (non-destructured)
542 // catch parameters with var declarations.
543 bool annexB35Allowance =
544 declaredKind == DeclarationKind::SimpleCatchParameter;
546 // Annex B.3.3 allows redeclaring functions in the same block.
547 bool annexB33Allowance =
548 declaredKind == DeclarationKind::SloppyLexicalFunction &&
549 kind == DeclarationKind::VarForAnnexBLexicalFunction &&
550 scope == innermostScope();
552 if (!annexB35Allowance && !annexB33Allowance) {
553 *redeclaredKind = Some(declaredKind);
554 *prevPos = p->value()->pos();
555 return true;
557 } else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) {
558 MOZ_ASSERT(DeclarationKindIsParameter(declaredKind));
560 // Annex B.3.3.1 disallows redeclaring parameter names.
561 // We don't need to set *prevPos here since this case is not
562 // an error.
563 *redeclaredKind = Some(declaredKind);
564 return true;
566 } else if (dryRunOption == NotDryRun) {
567 if (!scope->addDeclaredName(this, p, name, kind, beginPos)) {
568 return false;
572 // DryRunOption is used for propagating Annex B functions: we don't
573 // want to declare the synthesized Annex B vars until we exit the var
574 // scope and know that no early errors would have occurred. In order
575 // to avoid quadratic search, we only check for var redeclarations in
576 // the innermost scope when doing a dry run.
577 if (dryRunOption == DryRunInnermostScopeOnly) {
578 break;
582 if (!sc()->strict() && sc()->isEvalContext() &&
583 (dryRunOption == NotDryRun || innermostScope() == &varScope())) {
584 if (!isVarRedeclaredInEval(name, parser, kind, redeclaredKind)) {
585 return false;
587 // We don't have position information at runtime.
588 *prevPos = DeclaredNameInfo::npos;
591 return true;
594 bool ParseContext::hasUsedName(const UsedNameTracker& usedNames,
595 TaggedParserAtomIndex name) {
596 if (auto p = usedNames.lookup(name)) {
597 return p->value().isUsedInScript(scriptId());
599 return false;
602 bool ParseContext::hasClosedOverName(const UsedNameTracker& usedNames,
603 TaggedParserAtomIndex name) {
604 if (auto p = usedNames.lookup(name)) {
605 return p->value().isClosedOver(scriptId());
607 return false;
610 bool ParseContext::hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
611 TaggedParserAtomIndex name) {
612 MOZ_ASSERT(name == TaggedParserAtomIndex::WellKnown::arguments() ||
613 name == TaggedParserAtomIndex::WellKnown::dot_this_() ||
614 name == TaggedParserAtomIndex::WellKnown::dot_newTarget_());
615 return hasUsedName(usedNames, name) ||
616 functionBox()->bindingsAccessedDynamically();
619 bool ParseContext::hasClosedOverFunctionSpecialName(
620 const UsedNameTracker& usedNames, TaggedParserAtomIndex name) {
621 MOZ_ASSERT(name == TaggedParserAtomIndex::WellKnown::arguments());
622 return hasClosedOverName(usedNames, name) ||
623 functionBox()->bindingsAccessedDynamically();
626 bool ParseContext::declareFunctionThis(const UsedNameTracker& usedNames,
627 bool canSkipLazyClosedOverBindings) {
628 // The asm.js validator does all its own symbol-table management so, as an
629 // optimization, avoid doing any work here.
630 if (useAsmOrInsideUseAsm()) {
631 return true;
634 // Derived class constructors emit JSOp::CheckReturn, which requires
635 // '.this' to be bound. Class field initializers implicitly read `.this`.
636 // Therefore we unconditionally declare `.this` in all class constructors.
637 FunctionBox* funbox = functionBox();
638 auto dotThis = TaggedParserAtomIndex::WellKnown::dot_this_();
640 bool declareThis;
641 if (canSkipLazyClosedOverBindings) {
642 declareThis = funbox->functionHasThisBinding();
643 } else {
644 declareThis = hasUsedFunctionSpecialName(usedNames, dotThis) ||
645 funbox->isClassConstructor();
648 if (declareThis) {
649 ParseContext::Scope& funScope = functionScope();
650 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis);
651 MOZ_ASSERT(!p);
652 if (!funScope.addDeclaredName(this, p, dotThis, DeclarationKind::Var,
653 DeclaredNameInfo::npos)) {
654 return false;
656 funbox->setFunctionHasThisBinding();
659 return true;
662 bool ParseContext::declareFunctionArgumentsObject(
663 const UsedNameTracker& usedNames, bool canSkipLazyClosedOverBindings) {
664 FunctionBox* funbox = functionBox();
665 ParseContext::Scope& funScope = functionScope();
666 ParseContext::Scope& _varScope = varScope();
668 bool hasExtraBodyVarScope = &funScope != &_varScope;
670 // Time to implement the odd semantics of 'arguments'.
671 auto argumentsName = TaggedParserAtomIndex::WellKnown::arguments();
673 bool tryDeclareArguments = false;
674 bool needsArgsObject = false;
676 // When delazifying simply defer to the function box.
677 if (canSkipLazyClosedOverBindings) {
678 tryDeclareArguments = funbox->shouldDeclareArguments();
679 needsArgsObject = funbox->needsArgsObj();
680 } else {
681 // We cannot compute these values when delazifying, hence why we need to
682 // rely on the function box flags instead.
683 bool bindingClosedOver =
684 hasClosedOverFunctionSpecialName(usedNames, argumentsName);
685 bool bindingUsedOnlyHere =
686 hasUsedFunctionSpecialName(usedNames, argumentsName) &&
687 !bindingClosedOver;
689 // Declare arguments if there's a closed-over consumer of the binding, or if
690 // there is a non-length use and we will reference the binding during
691 // bytecode emission.
692 tryDeclareArguments =
693 !funbox->isEligibleForArgumentsLength() || bindingClosedOver;
694 // If we have a use and the binding isn't closed over, then we will do
695 // bytecode emission with the arguments intrinsic.
696 if (bindingUsedOnlyHere && funbox->isEligibleForArgumentsLength()) {
697 // If we're using the intrinsic we should not be declaring the binding.
698 MOZ_ASSERT(!tryDeclareArguments);
699 funbox->setUsesArgumentsIntrinsics();
700 } else if (tryDeclareArguments) {
701 needsArgsObject = true;
705 // ES 9.2.12 steps 19 and 20 say formal parameters, lexical bindings,
706 // and body-level functions named 'arguments' shadow the arguments
707 // object.
709 // So even if there wasn't a free use of 'arguments' but there is a var
710 // binding of 'arguments', we still might need the arguments object.
712 // If we have an extra var scope due to parameter expressions and the body
713 // declared 'var arguments', we still need to declare 'arguments' in the
714 // function scope.
715 DeclaredNamePtr p = _varScope.lookupDeclaredName(argumentsName);
716 if (p && p->value()->kind() == DeclarationKind::Var) {
717 if (hasExtraBodyVarScope) {
718 // While there is a binding in the var scope, we should declare
719 // the binding in the function scope.
720 tryDeclareArguments = true;
721 } else {
722 // A binding in the function scope (since varScope and functionScope are
723 // the same) exists, so arguments is used.
724 if (needsArgsObject) {
725 funbox->setNeedsArgsObj();
728 // There is no point in continuing on below: We know we already have
729 // a declaration of arguments in the function scope.
730 return true;
734 if (tryDeclareArguments) {
735 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName);
736 if (!p) {
737 if (!funScope.addDeclaredName(this, p, argumentsName,
738 DeclarationKind::Var,
739 DeclaredNameInfo::npos)) {
740 return false;
742 funbox->setShouldDeclareArguments();
743 if (needsArgsObject) {
744 funbox->setNeedsArgsObj();
748 return true;
751 bool ParseContext::declareNewTarget(const UsedNameTracker& usedNames,
752 bool canSkipLazyClosedOverBindings) {
753 // The asm.js validator does all its own symbol-table management so, as an
754 // optimization, avoid doing any work here.
755 if (useAsmOrInsideUseAsm()) {
756 return true;
759 FunctionBox* funbox = functionBox();
760 auto dotNewTarget = TaggedParserAtomIndex::WellKnown::dot_newTarget_();
762 bool declareNewTarget;
763 if (canSkipLazyClosedOverBindings) {
764 declareNewTarget = funbox->functionHasNewTargetBinding();
765 } else {
766 declareNewTarget = hasUsedFunctionSpecialName(usedNames, dotNewTarget);
769 if (declareNewTarget) {
770 ParseContext::Scope& funScope = functionScope();
771 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotNewTarget);
772 MOZ_ASSERT(!p);
773 if (!funScope.addDeclaredName(this, p, dotNewTarget, DeclarationKind::Var,
774 DeclaredNameInfo::npos)) {
775 return false;
777 funbox->setFunctionHasNewTargetBinding();
780 return true;
783 bool ParseContext::declareDotGeneratorName() {
784 // The special '.generator' binding must be on the function scope, and must
785 // be marked closed-over, as generators expect to find it on the CallObject.
786 ParseContext::Scope& funScope = functionScope();
787 auto dotGenerator = TaggedParserAtomIndex::WellKnown::dot_generator_();
788 AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator);
789 if (!p) {
790 if (!funScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
791 DeclaredNameInfo::npos, ClosedOver::Yes)) {
792 return false;
795 return true;
798 bool ParseContext::declareTopLevelDotGeneratorName() {
799 // Provide a .generator binding on the module scope for compatibility with
800 // generator code, which expect to find it on the CallObject for normal
801 // generators.
802 MOZ_ASSERT(
803 sc()->isModuleContext(),
804 "Tried to declare top level dot generator in a non-module context.");
805 ParseContext::Scope& modScope = varScope();
806 auto dotGenerator = TaggedParserAtomIndex::WellKnown::dot_generator_();
807 AddDeclaredNamePtr p = modScope.lookupDeclaredNameForAdd(dotGenerator);
808 return p ||
809 modScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
810 DeclaredNameInfo::npos, ClosedOver::Yes);
813 } // namespace frontend
815 } // namespace js