summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/ParseContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/ParseContext.cpp')
-rw-r--r--js/src/frontend/ParseContext.cpp766
1 files changed, 766 insertions, 0 deletions
diff --git a/js/src/frontend/ParseContext.cpp b/js/src/frontend/ParseContext.cpp
new file mode 100644
index 0000000000..ececac705b
--- /dev/null
+++ b/js/src/frontend/ParseContext.cpp
@@ -0,0 +1,766 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "frontend/ParseContext-inl.h"
+
+#include "frontend/CompilationStencil.h" // ScopeContext
+#include "frontend/Parser.h" // ParserBase
+#include "js/friend/ErrorMessages.h" // JSMSG_*
+
+using mozilla::Maybe;
+using mozilla::Nothing;
+using mozilla::Some;
+
+namespace js {
+namespace frontend {
+
+using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
+using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
+
+const char* DeclarationKindString(DeclarationKind kind) {
+ switch (kind) {
+ case DeclarationKind::PositionalFormalParameter:
+ case DeclarationKind::FormalParameter:
+ return "formal parameter";
+ case DeclarationKind::CoverArrowParameter:
+ return "cover arrow parameter";
+ case DeclarationKind::Var:
+ return "var";
+ case DeclarationKind::Let:
+ return "let";
+ case DeclarationKind::Const:
+ return "const";
+ case DeclarationKind::Class:
+ return "class";
+ case DeclarationKind::Import:
+ return "import";
+ case DeclarationKind::BodyLevelFunction:
+ case DeclarationKind::ModuleBodyLevelFunction:
+ case DeclarationKind::LexicalFunction:
+ case DeclarationKind::SloppyLexicalFunction:
+ return "function";
+ case DeclarationKind::VarForAnnexBLexicalFunction:
+ return "annex b var";
+ case DeclarationKind::SimpleCatchParameter:
+ case DeclarationKind::CatchParameter:
+ return "catch parameter";
+ case DeclarationKind::PrivateName:
+ return "private name";
+ case DeclarationKind::Synthetic:
+ return "synthetic";
+ case DeclarationKind::PrivateMethod:
+ return "private method";
+ }
+
+ MOZ_CRASH("Bad DeclarationKind");
+}
+
+bool DeclarationKindIsVar(DeclarationKind kind) {
+ return kind == DeclarationKind::Var ||
+ kind == DeclarationKind::BodyLevelFunction ||
+ kind == DeclarationKind::VarForAnnexBLexicalFunction;
+}
+
+bool DeclarationKindIsParameter(DeclarationKind kind) {
+ return kind == DeclarationKind::PositionalFormalParameter ||
+ kind == DeclarationKind::FormalParameter;
+}
+
+bool UsedNameTracker::noteUse(FrontendContext* fc, TaggedParserAtomIndex name,
+ NameVisibility visibility, uint32_t scriptId,
+ uint32_t scopeId,
+ mozilla::Maybe<TokenPos> tokenPosition) {
+ if (UsedNameMap::AddPtr p = map_.lookupForAdd(name)) {
+ p->value().maybeUpdatePos(tokenPosition);
+
+ if (!p->value().noteUsedInScope(scriptId, scopeId)) {
+ return false;
+ }
+ } else {
+ // We need a token position precisely where we have private visibility.
+ MOZ_ASSERT(tokenPosition.isSome() ==
+ (visibility == NameVisibility::Private));
+
+ if (visibility == NameVisibility::Private) {
+ // We have seen at least one private name
+ hasPrivateNames_ = true;
+ }
+
+ UsedNameInfo info(fc, visibility, tokenPosition);
+
+ if (!info.noteUsedInScope(scriptId, scopeId)) {
+ return false;
+ }
+ if (!map_.add(p, name, std::move(info))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool UsedNameTracker::getUnboundPrivateNames(
+ Vector<UnboundPrivateName, 8>& unboundPrivateNames) {
+ // We never saw any private names, so can just return early
+ if (!hasPrivateNames_) {
+ return true;
+ }
+
+ for (auto iter = map_.iter(); !iter.done(); iter.next()) {
+ // Don't care about public;
+ if (iter.get().value().isPublic()) {
+ continue;
+ }
+
+ // empty list means all bound
+ if (iter.get().value().empty()) {
+ continue;
+ }
+
+ if (!unboundPrivateNames.emplaceBack(iter.get().key(),
+ *iter.get().value().pos())) {
+ return false;
+ }
+ }
+
+ // Return a sorted list in ascendng order of position.
+ auto comparePosition = [](const auto& a, const auto& b) {
+ return a.position < b.position;
+ };
+ std::sort(unboundPrivateNames.begin(), unboundPrivateNames.end(),
+ comparePosition);
+
+ return true;
+}
+
+bool UsedNameTracker::hasUnboundPrivateNames(
+ FrontendContext* fc, mozilla::Maybe<UnboundPrivateName>& maybeUnboundName) {
+ // We never saw any private names, so can just return early
+ if (!hasPrivateNames_) {
+ return true;
+ }
+
+ Vector<UnboundPrivateName, 8> unboundPrivateNames(fc);
+ if (!getUnboundPrivateNames(unboundPrivateNames)) {
+ return false;
+ }
+
+ if (unboundPrivateNames.empty()) {
+ return true;
+ }
+
+ // GetUnboundPrivateNames returns the list sorted.
+ maybeUnboundName.emplace(unboundPrivateNames[0]);
+ return true;
+}
+
+void UsedNameTracker::UsedNameInfo::resetToScope(uint32_t scriptId,
+ uint32_t scopeId) {
+ while (!uses_.empty()) {
+ Use& innermost = uses_.back();
+ if (innermost.scopeId < scopeId) {
+ break;
+ }
+ MOZ_ASSERT(innermost.scriptId >= scriptId);
+ uses_.popBack();
+ }
+}
+
+void UsedNameTracker::rewind(RewindToken token) {
+ scriptCounter_ = token.scriptId;
+ scopeCounter_ = token.scopeId;
+
+ for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
+ r.front().value().resetToScope(token.scriptId, token.scopeId);
+ }
+}
+
+#if defined(DEBUG) || defined(JS_JITSPEW)
+void UsedNameTracker::dump(ParserAtomsTable& table) {
+ js::Fprinter out(stderr);
+
+ out.printf("Used names:\n");
+
+ for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
+ const auto& item = r.front();
+
+ const auto& name = item.key();
+ const auto& nameInfo = item.value();
+
+ out.put(" ");
+ table.dumpCharsNoQuote(out, name);
+ out.put("\n");
+
+ if (nameInfo.visibility_ == NameVisibility::Private) {
+ out.put(" visibility: private\n");
+ }
+
+ if (nameInfo.firstUsePos_) {
+ const auto& pos = *nameInfo.firstUsePos_;
+ out.printf(" first use pos: %u\n", pos.begin);
+ }
+
+ out.printf(" %zu user(s)", nameInfo.uses_.length());
+ bool first = true;
+ for (const auto& use : nameInfo.uses_) {
+ if (first) {
+ first = false;
+ out.put(" (");
+ } else {
+ out.put(", ");
+ }
+ out.printf("%u/%u", use.scriptId, use.scopeId);
+ }
+ if (!first) {
+ out.put(")");
+ }
+ out.put("\n");
+ }
+}
+#endif
+
+void ParseContext::Scope::dump(ParseContext* pc, ParserBase* parser) {
+ fprintf(stdout, "ParseScope %p", this);
+
+ fprintf(stdout, "\n decls:\n");
+ for (DeclaredNameMap::Range r = declared_->all(); !r.empty(); r.popFront()) {
+ auto index = r.front().key();
+ UniqueChars bytes = parser->parserAtoms().toPrintableString(index);
+ if (!bytes) {
+ ReportOutOfMemory(pc->sc()->fc_);
+ return;
+ }
+ DeclaredNameInfo& info = r.front().value().wrapped;
+ fprintf(stdout, " %s %s%s\n", DeclarationKindString(info.kind()),
+ bytes.get(), info.closedOver() ? " (closed over)" : "");
+ }
+
+ fprintf(stdout, "\n");
+}
+
+bool ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc,
+ FunctionBox* funbox) {
+ if (!possibleAnnexBFunctionBoxes_) {
+ if (!possibleAnnexBFunctionBoxes_.acquire(pc->sc()->fc_)) {
+ return false;
+ }
+ }
+
+ return maybeReportOOM(pc, possibleAnnexBFunctionBoxes_->append(funbox));
+}
+
+bool ParseContext::Scope::propagateAndMarkAnnexBFunctionBoxes(
+ ParseContext* pc, ParserBase* parser) {
+ // Strict mode doesn't have wack Annex B function semantics.
+ if (pc->sc()->strict() || !possibleAnnexBFunctionBoxes_ ||
+ possibleAnnexBFunctionBoxes_->empty()) {
+ return true;
+ }
+
+ if (this == &pc->varScope()) {
+ // Base case: actually declare the Annex B vars and mark applicable
+ // function boxes as Annex B.
+ Maybe<DeclarationKind> redeclaredKind;
+ uint32_t unused;
+ for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
+ bool annexBApplies;
+ if (!pc->computeAnnexBAppliesToLexicalFunctionInInnermostScope(
+ funbox, parser, &annexBApplies)) {
+ return false;
+ }
+ if (annexBApplies) {
+ if (!pc->tryDeclareVar(funbox->explicitName(), parser,
+ DeclarationKind::VarForAnnexBLexicalFunction,
+ DeclaredNameInfo::npos, &redeclaredKind,
+ &unused)) {
+ return false;
+ }
+
+ MOZ_ASSERT(!redeclaredKind);
+ funbox->isAnnexB = true;
+ }
+ }
+ } else {
+ // Inner scope case: propagate still applicable function boxes to the
+ // enclosing scope.
+ for (FunctionBox* funbox : *possibleAnnexBFunctionBoxes_) {
+ bool annexBApplies;
+ if (!pc->computeAnnexBAppliesToLexicalFunctionInInnermostScope(
+ funbox, parser, &annexBApplies)) {
+ return false;
+ }
+ if (annexBApplies) {
+ if (!enclosing()->addPossibleAnnexBFunctionBox(pc, funbox)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool DeclarationKindIsCatchParameter(DeclarationKind kind) {
+ return kind == DeclarationKind::SimpleCatchParameter ||
+ kind == DeclarationKind::CatchParameter;
+}
+
+bool ParseContext::Scope::addCatchParameters(ParseContext* pc,
+ Scope& catchParamScope) {
+ if (pc->useAsmOrInsideUseAsm()) {
+ return true;
+ }
+
+ for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
+ r.popFront()) {
+ DeclarationKind kind = r.front().value()->kind();
+ uint32_t pos = r.front().value()->pos();
+ MOZ_ASSERT(DeclarationKindIsCatchParameter(kind));
+ auto name = r.front().key();
+ AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name);
+ MOZ_ASSERT(!p);
+ if (!addDeclaredName(pc, p, name, kind, pos)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ParseContext::Scope::removeCatchParameters(ParseContext* pc,
+ Scope& catchParamScope) {
+ if (pc->useAsmOrInsideUseAsm()) {
+ return;
+ }
+
+ for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty();
+ r.popFront()) {
+ auto name = r.front().key();
+ DeclaredNamePtr p = declared_->lookup(name);
+ MOZ_ASSERT(p);
+
+ // This check is needed because the catch body could have declared
+ // vars, which would have been added to catchParamScope.
+ if (DeclarationKindIsCatchParameter(r.front().value()->kind())) {
+ declared_->remove(p);
+ }
+ }
+}
+
+ParseContext::ParseContext(FrontendContext* fc, ParseContext*& parent,
+ SharedContext* sc, ErrorReporter& errorReporter,
+ CompilationState& compilationState,
+ Directives* newDirectives, bool isFull)
+ : Nestable<ParseContext>(&parent),
+ sc_(sc),
+ errorReporter_(errorReporter),
+ innermostStatement_(nullptr),
+ innermostScope_(nullptr),
+ varScope_(nullptr),
+ positionalFormalParameterNames_(fc->nameCollectionPool()),
+ closedOverBindingsForLazy_(fc->nameCollectionPool()),
+ innerFunctionIndexesForLazy(sc->fc_),
+ newDirectives(newDirectives),
+ lastYieldOffset(NoYieldOffset),
+ lastAwaitOffset(NoAwaitOffset),
+ scriptId_(compilationState.usedNames.nextScriptId()),
+ superScopeNeedsHomeObject_(false) {
+ if (isFunctionBox()) {
+ if (functionBox()->isNamedLambda()) {
+ namedLambdaScope_.emplace(fc, parent, compilationState.usedNames);
+ }
+ functionScope_.emplace(fc, parent, compilationState.usedNames);
+ }
+}
+
+bool ParseContext::init() {
+ if (scriptId_ == UINT32_MAX) {
+ errorReporter_.errorNoOffset(JSMSG_NEED_DIET, "script");
+ return false;
+ }
+
+ FrontendContext* fc = sc()->fc_;
+
+ if (isFunctionBox()) {
+ // Named lambdas always need a binding for their own name. If this
+ // binding is closed over when we finish parsing the function iNn
+ // finishFunctionScopes, the function box needs to be marked as
+ // needing a dynamic DeclEnv object.
+ if (functionBox()->isNamedLambda()) {
+ if (!namedLambdaScope_->init(this)) {
+ return false;
+ }
+ AddDeclaredNamePtr p = namedLambdaScope_->lookupDeclaredNameForAdd(
+ functionBox()->explicitName());
+ MOZ_ASSERT(!p);
+ if (!namedLambdaScope_->addDeclaredName(
+ this, p, functionBox()->explicitName(), DeclarationKind::Const,
+ DeclaredNameInfo::npos)) {
+ return false;
+ }
+ }
+
+ if (!functionScope_->init(this)) {
+ return false;
+ }
+
+ if (!positionalFormalParameterNames_.acquire(fc)) {
+ return false;
+ }
+ }
+
+ if (!closedOverBindingsForLazy_.acquire(fc)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ParseContext::computeAnnexBAppliesToLexicalFunctionInInnermostScope(
+ FunctionBox* funbox, ParserBase* parser, bool* annexBApplies) {
+ MOZ_ASSERT(!sc()->strict());
+
+ TaggedParserAtomIndex name = funbox->explicitName();
+ Maybe<DeclarationKind> redeclaredKind;
+ if (!isVarRedeclaredInInnermostScope(
+ name, parser, DeclarationKind::VarForAnnexBLexicalFunction,
+ &redeclaredKind)) {
+ return false;
+ }
+
+ if (!redeclaredKind && isFunctionBox()) {
+ Scope& funScope = functionScope();
+ if (&funScope != &varScope()) {
+ // Annex B.3.3.1 disallows redeclaring parameter names. In the
+ // presence of parameter expressions, parameter names are on the
+ // function scope, which encloses the var scope. This means the
+ // isVarRedeclaredInInnermostScope call above would not catch this
+ // case, so test it manually.
+ if (DeclaredNamePtr p = funScope.lookupDeclaredName(name)) {
+ DeclarationKind declaredKind = p->value()->kind();
+ if (DeclarationKindIsParameter(declaredKind)) {
+ redeclaredKind = Some(declaredKind);
+ } else {
+ MOZ_ASSERT(FunctionScope::isSpecialName(name));
+ }
+ }
+ }
+ }
+
+ // If an early error would have occurred already, this function should not
+ // exhibit Annex B.3.3 semantics.
+ *annexBApplies = !redeclaredKind;
+ return true;
+}
+
+bool ParseContext::isVarRedeclaredInInnermostScope(
+ TaggedParserAtomIndex name, ParserBase* parser, DeclarationKind kind,
+ mozilla::Maybe<DeclarationKind>* out) {
+ uint32_t unused;
+ return tryDeclareVarHelper<DryRunInnermostScopeOnly>(
+ name, parser, kind, DeclaredNameInfo::npos, out, &unused);
+}
+
+bool ParseContext::isVarRedeclaredInEval(TaggedParserAtomIndex name,
+ ParserBase* parser,
+ DeclarationKind kind,
+ Maybe<DeclarationKind>* out) {
+ auto maybeKind = parser->getCompilationState()
+ .scopeContext.lookupLexicalBindingInEnclosingScope(name);
+ if (!maybeKind) {
+ *out = Nothing();
+ return true;
+ }
+
+ switch (*maybeKind) {
+ case ScopeContext::EnclosingLexicalBindingKind::Let:
+ *out = Some(DeclarationKind::Let);
+ break;
+ case ScopeContext::EnclosingLexicalBindingKind::Const:
+ *out = Some(DeclarationKind::Const);
+ break;
+ case ScopeContext::EnclosingLexicalBindingKind::CatchParameter:
+ *out = Some(DeclarationKind::CatchParameter);
+ break;
+ case ScopeContext::EnclosingLexicalBindingKind::Synthetic:
+ *out = Some(DeclarationKind::Synthetic);
+ break;
+ case ScopeContext::EnclosingLexicalBindingKind::PrivateMethod:
+ *out = Some(DeclarationKind::PrivateMethod);
+ break;
+ }
+ return true;
+}
+
+bool ParseContext::tryDeclareVar(TaggedParserAtomIndex name, ParserBase* parser,
+ DeclarationKind kind, uint32_t beginPos,
+ Maybe<DeclarationKind>* redeclaredKind,
+ uint32_t* prevPos) {
+ return tryDeclareVarHelper<NotDryRun>(name, parser, kind, beginPos,
+ redeclaredKind, prevPos);
+}
+
+template <ParseContext::DryRunOption dryRunOption>
+bool ParseContext::tryDeclareVarHelper(TaggedParserAtomIndex name,
+ ParserBase* parser, DeclarationKind kind,
+ uint32_t beginPos,
+ Maybe<DeclarationKind>* redeclaredKind,
+ uint32_t* prevPos) {
+ MOZ_ASSERT(DeclarationKindIsVar(kind));
+
+ // It is an early error if a 'var' declaration appears inside a
+ // scope contour that has a lexical declaration of the same name. For
+ // example, the following are early errors:
+ //
+ // { let x; var x; }
+ // { { var x; } let x; }
+ //
+ // And the following are not:
+ //
+ // { var x; var x; }
+ // { { let x; } var x; }
+
+ for (ParseContext::Scope* scope = innermostScope();
+ scope != varScope().enclosing(); scope = scope->enclosing()) {
+ if (AddDeclaredNamePtr p = scope->lookupDeclaredNameForAdd(name)) {
+ DeclarationKind declaredKind = p->value()->kind();
+ if (DeclarationKindIsVar(declaredKind)) {
+ if (dryRunOption == NotDryRun) {
+ RedeclareVar(p, kind);
+ }
+ } else if (!DeclarationKindIsParameter(declaredKind)) {
+ // Annex B.3.5 allows redeclaring simple (non-destructured)
+ // catch parameters with var declarations.
+ bool annexB35Allowance =
+ declaredKind == DeclarationKind::SimpleCatchParameter;
+
+ // Annex B.3.3 allows redeclaring functions in the same block.
+ bool annexB33Allowance =
+ declaredKind == DeclarationKind::SloppyLexicalFunction &&
+ kind == DeclarationKind::VarForAnnexBLexicalFunction &&
+ scope == innermostScope();
+
+ if (!annexB35Allowance && !annexB33Allowance) {
+ *redeclaredKind = Some(declaredKind);
+ *prevPos = p->value()->pos();
+ return true;
+ }
+ } else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) {
+ MOZ_ASSERT(DeclarationKindIsParameter(declaredKind));
+
+ // Annex B.3.3.1 disallows redeclaring parameter names.
+ // We don't need to set *prevPos here since this case is not
+ // an error.
+ *redeclaredKind = Some(declaredKind);
+ return true;
+ }
+ } else if (dryRunOption == NotDryRun) {
+ if (!scope->addDeclaredName(this, p, name, kind, beginPos)) {
+ return false;
+ }
+ }
+
+ // DryRunOption is used for propagating Annex B functions: we don't
+ // want to declare the synthesized Annex B vars until we exit the var
+ // scope and know that no early errors would have occurred. In order
+ // to avoid quadratic search, we only check for var redeclarations in
+ // the innermost scope when doing a dry run.
+ if (dryRunOption == DryRunInnermostScopeOnly) {
+ break;
+ }
+ }
+
+ if (!sc()->strict() && sc()->isEvalContext() &&
+ (dryRunOption == NotDryRun || innermostScope() == &varScope())) {
+ if (!isVarRedeclaredInEval(name, parser, kind, redeclaredKind)) {
+ return false;
+ }
+ // We don't have position information at runtime.
+ *prevPos = DeclaredNameInfo::npos;
+ }
+
+ return true;
+}
+
+bool ParseContext::hasUsedName(const UsedNameTracker& usedNames,
+ TaggedParserAtomIndex name) {
+ if (auto p = usedNames.lookup(name)) {
+ return p->value().isUsedInScript(scriptId());
+ }
+ return false;
+}
+
+bool ParseContext::hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
+ TaggedParserAtomIndex name) {
+ MOZ_ASSERT(name == TaggedParserAtomIndex::WellKnown::arguments() ||
+ name == TaggedParserAtomIndex::WellKnown::dot_this_() ||
+ name == TaggedParserAtomIndex::WellKnown::dot_newTarget_());
+ return hasUsedName(usedNames, name) ||
+ functionBox()->bindingsAccessedDynamically();
+}
+
+bool ParseContext::declareFunctionThis(const UsedNameTracker& usedNames,
+ bool canSkipLazyClosedOverBindings) {
+ // The asm.js validator does all its own symbol-table management so, as an
+ // optimization, avoid doing any work here.
+ if (useAsmOrInsideUseAsm()) {
+ return true;
+ }
+
+ // Derived class constructors emit JSOp::CheckReturn, which requires
+ // '.this' to be bound. Class field initializers implicitly read `.this`.
+ // Therefore we unconditionally declare `.this` in all class constructors.
+ FunctionBox* funbox = functionBox();
+ auto dotThis = TaggedParserAtomIndex::WellKnown::dot_this_();
+
+ bool declareThis;
+ if (canSkipLazyClosedOverBindings) {
+ declareThis = funbox->functionHasThisBinding();
+ } else {
+ declareThis = hasUsedFunctionSpecialName(usedNames, dotThis) ||
+ funbox->isClassConstructor();
+ }
+
+ if (declareThis) {
+ ParseContext::Scope& funScope = functionScope();
+ AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis);
+ MOZ_ASSERT(!p);
+ if (!funScope.addDeclaredName(this, p, dotThis, DeclarationKind::Var,
+ DeclaredNameInfo::npos)) {
+ return false;
+ }
+ funbox->setFunctionHasThisBinding();
+ }
+
+ return true;
+}
+
+bool ParseContext::declareFunctionArgumentsObject(
+ const UsedNameTracker& usedNames, bool canSkipLazyClosedOverBindings) {
+ FunctionBox* funbox = functionBox();
+ ParseContext::Scope& funScope = functionScope();
+ ParseContext::Scope& _varScope = varScope();
+
+ bool usesArguments = false;
+ bool hasExtraBodyVarScope = &funScope != &_varScope;
+
+ // Time to implement the odd semantics of 'arguments'.
+ auto argumentsName = TaggedParserAtomIndex::WellKnown::arguments();
+
+ bool tryDeclareArguments;
+ if (canSkipLazyClosedOverBindings) {
+ tryDeclareArguments = funbox->shouldDeclareArguments();
+ } else {
+ tryDeclareArguments = hasUsedFunctionSpecialName(usedNames, argumentsName);
+ }
+
+ // ES 9.2.12 steps 19 and 20 say formal parameters, lexical bindings,
+ // and body-level functions named 'arguments' shadow the arguments
+ // object.
+ //
+ // So even if there wasn't a free use of 'arguments' but there is a var
+ // binding of 'arguments', we still might need the arguments object.
+ //
+ // If we have an extra var scope due to parameter expressions and the body
+ // declared 'var arguments', we still need to declare 'arguments' in the
+ // function scope.
+ DeclaredNamePtr p = _varScope.lookupDeclaredName(argumentsName);
+ if (p && p->value()->kind() == DeclarationKind::Var) {
+ if (hasExtraBodyVarScope) {
+ tryDeclareArguments = true;
+ } else {
+ usesArguments = true;
+ }
+ }
+
+ if (tryDeclareArguments) {
+ AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName);
+ if (!p) {
+ if (!funScope.addDeclaredName(this, p, argumentsName,
+ DeclarationKind::Var,
+ DeclaredNameInfo::npos)) {
+ return false;
+ }
+ funbox->setShouldDeclareArguments();
+ usesArguments = true;
+ } else if (hasExtraBodyVarScope) {
+ // Formal parameters shadow the arguments object.
+ return true;
+ }
+ }
+
+ if (usesArguments) {
+ funbox->setNeedsArgsObj();
+ }
+
+ return true;
+}
+
+bool ParseContext::declareNewTarget(const UsedNameTracker& usedNames,
+ bool canSkipLazyClosedOverBindings) {
+ // The asm.js validator does all its own symbol-table management so, as an
+ // optimization, avoid doing any work here.
+ if (useAsmOrInsideUseAsm()) {
+ return true;
+ }
+
+ FunctionBox* funbox = functionBox();
+ auto dotNewTarget = TaggedParserAtomIndex::WellKnown::dot_newTarget_();
+
+ bool declareNewTarget;
+ if (canSkipLazyClosedOverBindings) {
+ declareNewTarget = funbox->functionHasNewTargetBinding();
+ } else {
+ declareNewTarget = hasUsedFunctionSpecialName(usedNames, dotNewTarget);
+ }
+
+ if (declareNewTarget) {
+ ParseContext::Scope& funScope = functionScope();
+ AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotNewTarget);
+ MOZ_ASSERT(!p);
+ if (!funScope.addDeclaredName(this, p, dotNewTarget, DeclarationKind::Var,
+ DeclaredNameInfo::npos)) {
+ return false;
+ }
+ funbox->setFunctionHasNewTargetBinding();
+ }
+
+ return true;
+}
+
+bool ParseContext::declareDotGeneratorName() {
+ // The special '.generator' binding must be on the function scope, and must
+ // be marked closed-over, as generators expect to find it on the CallObject.
+ ParseContext::Scope& funScope = functionScope();
+ auto dotGenerator = TaggedParserAtomIndex::WellKnown::dot_generator_();
+ AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator);
+ if (!p) {
+ if (!funScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
+ DeclaredNameInfo::npos, ClosedOver::Yes)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ParseContext::declareTopLevelDotGeneratorName() {
+ // Provide a .generator binding on the module scope for compatibility with
+ // generator code, which expect to find it on the CallObject for normal
+ // generators.
+ MOZ_ASSERT(
+ sc()->isModuleContext(),
+ "Tried to declare top level dot generator in a non-module context.");
+ ParseContext::Scope& modScope = varScope();
+ auto dotGenerator = TaggedParserAtomIndex::WellKnown::dot_generator_();
+ AddDeclaredNamePtr p = modScope.lookupDeclaredNameForAdd(dotGenerator);
+ return p ||
+ modScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
+ DeclaredNameInfo::npos, ClosedOver::Yes);
+}
+
+} // namespace frontend
+
+} // namespace js