Bug 1529448 - Move {hasUsedName,hasUsedNamedeclareFunctionThis,declareFunctionThis,declareFunctionArgumentsObject,declareDotGeneratorName} to ParseContext. r=jorendorff
authorTooru Fujisawa <arai_a@mac.com>
Sun, 24 Feb 2019 03:35:44 +0000
changeset 518666 cfdb566ecbb8003d11536c2e0c8aa20d8945884f
parent 518665 abcf203b0474e1656413771f137cdb6f5dc2161e
child 518667 8c7ac177290e77f95adbbaa99787c193e47f3d82
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1529448
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1529448 - Move {hasUsedName,hasUsedNamedeclareFunctionThis,declareFunctionThis,declareFunctionArgumentsObject,declareDotGeneratorName} to ParseContext. r=jorendorff Differential Revision: https://phabricator.services.mozilla.com/D20779
js/src/frontend/BinASTParser.cpp
js/src/frontend/BinASTParserPerTokenizer.cpp
js/src/frontend/BinASTParserPerTokenizer.h
js/src/frontend/BinSource.yaml
js/src/frontend/ParseContext.cpp
js/src/frontend/ParseContext.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
--- a/js/src/frontend/BinASTParser.cpp
+++ b/js/src/frontend/BinASTParser.cpp
@@ -2509,18 +2509,18 @@ BinASTParser<Tok>::parseInterfaceEagerFu
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
   MOZ_TRY(parseFunctionOrMethodContents(length, &params, &body));
   MOZ_TRY(prependDirectivesToBody(body, directives));
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
-  BINJS_MOZ_TRY_DECL(
-      result, buildFunction(start, kind, name, params, bodyScope, funbox));
+  BINJS_MOZ_TRY_DECL(result,
+                     buildFunction(start, kind, name, params, bodyScope));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerFunctionExpression(
     const size_t start, const BinKind kind, const BinFields& fields) {
   MOZ_ASSERT(kind == BinKind::EagerFunctionExpression);
   BINJS_TRY(CheckRecursionLimit(cx_));
@@ -2572,18 +2572,18 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
   MOZ_TRY(parseFunctionExpressionContents(length, &params, &body));
   MOZ_TRY(prependDirectivesToBody(body, directives));
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(bodyScope, handler_.newLexicalScope(*lexicalScopeData, body));
-  BINJS_MOZ_TRY_DECL(
-      result, buildFunction(start, kind, name, params, bodyScope, funbox));
+  BINJS_MOZ_TRY_DECL(result,
+                     buildFunction(start, kind, name, params, bodyScope));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerGetter(
     const size_t start, const BinKind kind, const BinFields& fields) {
   MOZ_ASSERT(kind == BinKind::EagerGetter);
   BINJS_TRY(CheckRecursionLimit(cx_));
@@ -2624,18 +2624,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
   MOZ_TRY(parseGetterContents(length, &params, &body));
   MOZ_TRY(prependDirectivesToBody(body, directives));
-  BINJS_MOZ_TRY_DECL(method,
-                     buildFunction(start, kind, name, params, body, funbox));
+  BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body));
   BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
                              name, method, accessorType));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerMethod(
     const size_t start, const BinKind kind, const BinFields& fields) {
@@ -2687,18 +2686,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
   MOZ_TRY(parseFunctionOrMethodContents(length, &params, &body));
   MOZ_TRY(prependDirectivesToBody(body, directives));
-  BINJS_MOZ_TRY_DECL(method,
-                     buildFunction(start, kind, name, params, body, funbox));
+  BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body));
   BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
                              name, method, accessorType));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEagerSetter(
     const size_t start, const BinKind kind, const BinFields& fields) {
@@ -2743,18 +2741,17 @@ JS::Result<ParseNode*> BinASTParser<Tok>
   MOZ_ASSERT(pc_->isFunctionBox());
 
   ParseContext::Scope lexicalScope(cx_, pc_, usedNames_);
   BINJS_TRY(lexicalScope.init(pc_));
   ListNode* params;
   ListNode* body;
   MOZ_TRY(parseSetterContents(length, &params, &body));
   MOZ_TRY(prependDirectivesToBody(body, directives));
-  BINJS_MOZ_TRY_DECL(method,
-                     buildFunction(start, kind, name, params, body, funbox));
+  BINJS_MOZ_TRY_DECL(method, buildFunction(start, kind, name, params, body));
   BINJS_TRY_DECL(result, handler_.newObjectMethodOrPropertyDefinition(
                              name, method, accessorType));
   return result;
 }
 
 template <typename Tok>
 JS::Result<ParseNode*> BinASTParser<Tok>::parseInterfaceEmptyStatement(
     const size_t start, const BinKind kind, const BinFields& fields) {
--- a/js/src/frontend/BinASTParserPerTokenizer.cpp
+++ b/js/src/frontend/BinASTParserPerTokenizer.cpp
@@ -193,17 +193,17 @@ JS::Result<FunctionNode*> BinASTParserPe
   MOZ_TRY((asFinalParser()->*parseFunc)(func->nargs(), &params, &tmpBody));
 
   BINJS_TRY_DECL(lexicalScopeData,
                  NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
   BINJS_TRY_DECL(body, handler_.newLexicalScope(*lexicalScopeData, tmpBody));
 
   auto binKind = isExpr ? BinKind::LazyFunctionExpression
                         : BinKind::LazyFunctionDeclaration;
-  return buildFunction(firstOffset, binKind, nullptr, params, body, funbox);
+  return buildFunction(firstOffset, binKind, nullptr, params, body);
 }
 
 template <typename Tok>
 void BinASTParserPerTokenizer<Tok>::forceStrictIfNecessary(
     SharedContext* sc, ListNode* directives) {
   JSAtom* useStrict = cx_->names().useStrict;
 
   for (const ParseNode* directive : directives->contents()) {
@@ -311,100 +311,55 @@ JS::Result<FunctionNode*> BinASTParserPe
   handler_.setFunctionBox(result, funbox);
 
   return result;
 }
 
 template <typename Tok>
 JS::Result<FunctionNode*> BinASTParserPerTokenizer<Tok>::buildFunction(
     const size_t start, const BinKind kind, ParseNode* name, ListNode* params,
-    ParseNode* body, FunctionBox* funbox) {
+    ParseNode* body) {
+  FunctionBox* funbox = pc_->functionBox();
+
   // Set the argument count for building argument packets. Function.length is
   // handled by setting the appropriate funbox field during argument parsing.
   if (!lazyScript_ ||
       lazyScript_->functionNonDelazifying() != funbox->function()) {
     funbox->function()->setArgCount(params ? uint16_t(params->count()) : 0);
   }
 
   // ParseNode represents the body as concatenated after the params.
   params->appendWithoutOrderAssumption(body);
 
   BINJS_MOZ_TRY_DECL(result, makeEmptyFunctionNode(start, kind, funbox));
 
   handler_.setFunctionFormalParametersAndBody(result, params);
 
-  HandlePropertyName dotThis = cx_->names().dotThis;
-  const bool declareThis = hasUsedName(dotThis) ||
-                           funbox->bindingsAccessedDynamically() ||
-                           funbox->isDerivedClassConstructor();
-
-  if (declareThis) {
-    ParseContext::Scope& funScope = pc_->functionScope();
-    ParseContext::Scope::AddDeclaredNamePtr p =
-        funScope.lookupDeclaredNameForAdd(dotThis);
-    MOZ_ASSERT(!p);
-    BINJS_TRY(funScope.addDeclaredName(pc_, p, dotThis, DeclarationKind::Var,
-                                       DeclaredNameInfo::npos));
-    funbox->setHasThisBinding();
-
-    // TODO (efaust): This capture will have to come from encoder side for arrow
-    // functions.
-  }
-
-  // This models PerHandlerParser::declaeFunctionArgumentsObject, with some
-  // subtleties removed, as they don't yet apply to us.
-  HandlePropertyName arguments = cx_->names().arguments;
-  if (hasUsedName(arguments) ||
-      pc_->functionBox()->bindingsAccessedDynamically()) {
-    funbox->usesArguments = true;
+  if (funbox->needsDotGeneratorName()) {
+    BINJS_TRY(pc_->declareDotGeneratorName());
 
-    ParseContext::Scope& funScope = pc_->functionScope();
-    ParseContext::Scope::AddDeclaredNamePtr p =
-        funScope.lookupDeclaredNameForAdd(arguments);
-    if (!p) {
-      BINJS_TRY(funScope.addDeclaredName(
-          pc_, p, arguments, DeclarationKind::Var, DeclaredNameInfo::npos));
-      funbox->declaredArguments = true;
-    } else if (p->value()->kind() != DeclarationKind::Var) {
-      // Lexicals, formal parameters, and body level functions shadow.
-      funbox->usesArguments = false;
-    }
-
-    if (funbox->usesArguments) {
-      funbox->setArgumentsHasLocalBinding();
-
-      if (pc_->sc()->bindingsAccessedDynamically() ||
-          pc_->sc()->hasDebuggerStatement()) {
-        funbox->setDefinitelyNeedsArgsObj();
-      }
-    }
-  }
-
-  if (funbox->needsDotGeneratorName()) {
-    ParseContext::Scope& funScope = pc_->functionScope();
     HandlePropertyName dotGenerator = cx_->names().dotGenerator;
-    ParseContext::Scope::AddDeclaredNamePtr p =
-        funScope.lookupDeclaredNameForAdd(dotGenerator);
-    if (!p) {
-      BINJS_TRY(funScope.addDeclaredName(
-          pc_, p, dotGenerator, DeclarationKind::Var, DeclaredNameInfo::npos));
-    }
-
     BINJS_TRY(usedNames_.noteUse(cx_, dotGenerator, pc_->scriptId(),
                                  pc_->innermostScope()->id()));
 
     BINJS_TRY_DECL(
         dotGen, handler_.newName(dotGenerator,
                                  tokenizer_->pos(tokenizer_->offset()), cx_));
 
     ListNode* stmtList =
         &body->as<LexicalScopeNode>().scopeBody()->as<ListNode>();
     BINJS_TRY(handler_.prependInitialYield(stmtList, dotGen));
   }
 
+  const bool canSkipLazyClosedOverBindings = false;
+  BINJS_TRY(pc_->declareFunctionArgumentsObject(usedNames_,
+                                                canSkipLazyClosedOverBindings));
+  BINJS_TRY(
+      pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings));
+
   // Check all our bindings after maybe adding function metavars.
   MOZ_TRY(checkFunctionClosedVars());
 
   BINJS_TRY_DECL(bindings, NewFunctionScopeData(cx_, pc_->functionScope(),
                                                 /* hasParameterExprs = */ false,
                                                 alloc_, pc_));
 
   funbox->functionScopeBindings().set(*bindings);
--- a/js/src/frontend/BinASTParserPerTokenizer.h
+++ b/js/src/frontend/BinASTParserPerTokenizer.h
@@ -133,20 +133,20 @@ class BinASTParserPerTokenizer : public 
 
   // --- Auxiliary parsing functions
 
   // Build a function object for a function-producing production. Called AFTER
   // creating the scope.
   JS::Result<FunctionNode*> makeEmptyFunctionNode(const size_t start,
                                                   const BinKind kind,
                                                   FunctionBox* funbox);
+
   JS::Result<FunctionNode*> buildFunction(const size_t start,
                                           const BinKind kind, ParseNode* name,
-                                          ListNode* params, ParseNode* body,
-                                          FunctionBox* funbox);
+                                          ListNode* params, ParseNode* body);
   JS::Result<FunctionBox*> buildFunctionBox(GeneratorKind generatorKind,
                                             FunctionAsyncKind functionAsyncKind,
                                             FunctionSyntaxKind syntax,
                                             ParseNode* name);
 
   // Add name to a given scope.
   MOZ_MUST_USE JS::Result<Ok> addScopeName(
       AssertedScopeKind scopeKind, HandleAtom name, ParseContext::Scope* scope,
--- a/js/src/frontend/BinSource.yaml
+++ b/js/src/frontend/BinSource.yaml
@@ -935,18 +935,17 @@ EagerFunctionExpression:
       after: |
         MOZ_TRY(prependDirectivesToBody(body, directives));
   build: |
     BINJS_TRY_DECL(lexicalScopeData,
                    NewLexicalScopeData(cx_, lexicalScope, alloc_, pc_));
     BINJS_TRY_DECL(bodyScope,
                    handler_.newLexicalScope(*lexicalScopeData, body));
     BINJS_MOZ_TRY_DECL(result,
-                       buildFunction(start, kind, name, params, bodyScope,
-                                     funbox));
+                       buildFunction(start, kind, name, params, bodyScope));
 
 LazyFunctionExpression:
   init: |
     const auto syntax = FunctionSyntaxKind::Expression;
   fields:
     isGenerator:
       after: |
         if (isGenerator) {
@@ -1003,17 +1002,17 @@ EagerGetter:
 
 EagerMethod:
   init: |
     const auto syntax = FunctionSyntaxKind::Method;
     const auto accessorType = AccessorType::None;
   inherits: EagerFunctionExpression
   build: |
     BINJS_MOZ_TRY_DECL(method,
-                       buildFunction(start, kind, name, params, body, funbox));
+                       buildFunction(start, kind, name, params, body));
     BINJS_TRY_DECL(result,
                    handler_.newObjectMethodOrPropertyDefinition(name, method,
                                                                 accessorType));
 
 EagerSetter:
   init: |
     const auto syntax = FunctionSyntaxKind::Setter;
     const bool isGenerator = false;
--- a/js/src/frontend/ParseContext.cpp
+++ b/js/src/frontend/ParseContext.cpp
@@ -10,16 +10,17 @@
 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";
@@ -467,11 +468,154 @@ bool ParseContext::tryDeclareVarHelper(H
     *redeclaredKind = isVarRedeclaredInEval(name, kind);
     // We don't have position information at runtime.
     *prevPos = DeclaredNameInfo::npos;
   }
 
   return true;
 }
 
+bool ParseContext::hasUsedName(const UsedNameTracker& usedNames,
+                               HandlePropertyName name) {
+  if (auto p = usedNames.lookup(name)) {
+    return p->value().isUsedInScript(scriptId());
+  }
+  return false;
+}
+
+bool ParseContext::hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
+                                              HandlePropertyName name) {
+  MOZ_ASSERT(name == sc()->cx_->names().arguments ||
+             name == sc()->cx_->names().dotThis);
+  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.
+  FunctionBox* funbox = functionBox();
+  HandlePropertyName dotThis = sc()->cx_->names().dotThis;
+
+  bool declareThis;
+  if (canSkipLazyClosedOverBindings) {
+    declareThis = funbox->function()->lazyScript()->hasThisBinding();
+  } else {
+    declareThis = hasUsedFunctionSpecialName(usedNames, dotThis) ||
+                  funbox->isDerivedClassConstructor();
+  }
+
+  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->setHasThisBinding();
+  }
+
+  return true;
+}
+
+bool ParseContext::declareFunctionArgumentsObject(
+    const UsedNameTracker& usedNames, bool canSkipLazyClosedOverBindings) {
+  FunctionBox* funbox = functionBox();
+  ParseContext::Scope& funScope = functionScope();
+  ParseContext::Scope& _varScope = varScope();
+
+  bool hasExtraBodyVarScope = &funScope != &_varScope;
+
+  // Time to implement the odd semantics of 'arguments'.
+  HandlePropertyName argumentsName = sc()->cx_->names().arguments;
+
+  bool tryDeclareArguments;
+  if (canSkipLazyClosedOverBindings) {
+    tryDeclareArguments =
+        funbox->function()->lazyScript()->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 {
+      funbox->usesArguments = true;
+    }
+  }
+
+  if (tryDeclareArguments) {
+    AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName);
+    if (!p) {
+      if (!funScope.addDeclaredName(this, p, argumentsName,
+                                    DeclarationKind::Var,
+                                    DeclaredNameInfo::npos)) {
+        return false;
+      }
+      funbox->declaredArguments = true;
+      funbox->usesArguments = true;
+    } else if (hasExtraBodyVarScope) {
+      // Formal parameters shadow the arguments object.
+      return true;
+    }
+  }
+
+  // Compute if we need an arguments object.
+  if (funbox->usesArguments) {
+    // There is an 'arguments' binding. Is the arguments object definitely
+    // needed?
+    //
+    // Also see the flags' comments in ContextFlags.
+    funbox->setArgumentsHasLocalBinding();
+
+    // Dynamic scope access destroys all hope of optimization.
+    if (sc()->bindingsAccessedDynamically()) {
+      funbox->setDefinitelyNeedsArgsObj();
+    }
+
+    // If a script contains the debugger statement either directly or
+    // within an inner function, the arguments object should be created
+    // eagerly so the Debugger API may observe bindings.
+    if (sc()->hasDebuggerStatement()) {
+      funbox->setDefinitelyNeedsArgsObj();
+    }
+  }
+
+  return true;
+}
+
+bool ParseContext::declareDotGeneratorName() {
+  // The special '.generator' binding must be on the function scope, as
+  // generators expect to find it on the CallObject.
+  ParseContext::Scope& funScope = functionScope();
+  HandlePropertyName dotGenerator = sc()->cx_->names().dotGenerator;
+  AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator);
+  if (!p &&
+      !funScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
+                                DeclaredNameInfo::npos)) {
+    return false;
+  }
+  return true;
+}
+
 }  // namespace frontend
 
 }  // namespace js
--- a/js/src/frontend/ParseContext.h
+++ b/js/src/frontend/ParseContext.h
@@ -616,16 +616,26 @@ class ParseContext : public Nestable<Par
 
   bool annexBAppliesToLexicalFunctionInInnermostScope(FunctionBox* funbox);
 
   bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind,
                      uint32_t beginPos,
                      mozilla::Maybe<DeclarationKind>* redeclaredKind,
                      uint32_t* prevPos);
 
+  bool hasUsedName(const UsedNameTracker& usedNames, HandlePropertyName name);
+  bool hasUsedFunctionSpecialName(const UsedNameTracker& usedNames,
+                                  HandlePropertyName name);
+
+  bool declareFunctionThis(const UsedNameTracker& usedNames,
+                           bool canSkipLazyClosedOverBindings);
+  bool declareFunctionArgumentsObject(const UsedNameTracker& usedNames,
+                                      bool canSkipLazyClosedOverBindings);
+  bool declareDotGeneratorName();
+
  private:
   mozilla::Maybe<DeclarationKind> isVarRedeclaredInInnermostScope(
       HandlePropertyName name, DeclarationKind kind);
   mozilla::Maybe<DeclarationKind> isVarRedeclaredInEval(HandlePropertyName name,
                                                         DeclarationKind kind);
 
   enum DryRunOption { NotDryRun, DryRunInnermostScopeOnly };
   template <DryRunOption dryRunOption>
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -801,23 +801,16 @@ bool ParserBase::noteUsedNameInternal(Ha
   ParseContext::Scope* scope = pc_->innermostScope();
   if (pc_->sc()->isGlobalContext() && scope == &pc_->varScope()) {
     return true;
   }
 
   return usedNames_.noteUse(cx_, name, pc_->scriptId(), scope->id());
 }
 
-bool ParserSharedBase::hasUsedName(HandlePropertyName name) {
-  if (UsedNamePtr p = usedNames_.lookup(name)) {
-    return p->value().isUsedInScript(pc_->scriptId());
-  }
-  return false;
-}
-
 template <class ParseHandler>
 bool PerHandlerParser<ParseHandler>::
     propagateFreeNamesAndMarkClosedOverBindings(ParseContext::Scope& scope) {
   // Now that we have all the declared names in the scope, check which
   // functions should exhibit Annex B semantics.
   if (!scope.propagateAndMarkAnnexBFunctionBoxes(pc_)) {
     return false;
   }
@@ -1554,56 +1547,16 @@ ModuleNode* Parser<FullParseHandler, Uni
 
 template <typename Unit>
 SyntaxParseHandler::ModuleNodeType Parser<SyntaxParseHandler, Unit>::moduleBody(
     ModuleSharedContext* modulesc) {
   MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
   return SyntaxParseHandler::NodeFailure;
 }
 
-bool ParserBase::hasUsedFunctionSpecialName(HandlePropertyName name) {
-  MOZ_ASSERT(name == cx_->names().arguments || name == cx_->names().dotThis);
-  return hasUsedName(name) || pc_->functionBox()->bindingsAccessedDynamically();
-}
-
-template <class ParseHandler>
-bool PerHandlerParser<ParseHandler>::declareFunctionThis() {
-  // The asm.js validator does all its own symbol-table management so, as an
-  // optimization, avoid doing any work here.
-  if (pc_->useAsmOrInsideUseAsm()) {
-    return true;
-  }
-
-  // Derived class constructors emit JSOP_CHECKRETURN, which requires
-  // '.this' to be bound.
-  FunctionBox* funbox = pc_->functionBox();
-  HandlePropertyName dotThis = cx_->names().dotThis;
-
-  bool declareThis;
-  if (handler_.canSkipLazyClosedOverBindings()) {
-    declareThis = funbox->function()->lazyScript()->hasThisBinding();
-  } else {
-    declareThis = hasUsedFunctionSpecialName(dotThis) ||
-                  funbox->isDerivedClassConstructor();
-  }
-
-  if (declareThis) {
-    ParseContext::Scope& funScope = pc_->functionScope();
-    AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis);
-    MOZ_ASSERT(!p);
-    if (!funScope.addDeclaredName(pc_, p, dotThis, DeclarationKind::Var,
-                                  DeclaredNameInfo::npos)) {
-      return false;
-    }
-    funbox->setHasThisBinding();
-  }
-
-  return true;
-}
-
 template <class ParseHandler>
 typename ParseHandler::NameNodeType
 PerHandlerParser<ParseHandler>::newInternalDotName(HandlePropertyName name) {
   NameNodeType nameNode = newName(name);
   if (!nameNode) {
     return null();
   }
   if (!noteUsedName(name)) {
@@ -1619,30 +1572,16 @@ PerHandlerParser<ParseHandler>::newThisN
 }
 
 template <class ParseHandler>
 typename ParseHandler::NameNodeType
 PerHandlerParser<ParseHandler>::newDotGeneratorName() {
   return newInternalDotName(cx_->names().dotGenerator);
 }
 
-bool ParserBase::declareDotGeneratorName() {
-  // The special '.generator' binding must be on the function scope, as
-  // generators expect to find it on the CallObject.
-  ParseContext::Scope& funScope = pc_->functionScope();
-  HandlePropertyName dotGenerator = cx_->names().dotGenerator;
-  AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator);
-  if (!p &&
-      !funScope.addDeclaredName(pc_, p, dotGenerator, DeclarationKind::Var,
-                                DeclaredNameInfo::npos)) {
-    return false;
-  }
-  return true;
-}
-
 template <class ParseHandler>
 bool PerHandlerParser<ParseHandler>::finishFunctionScopes(
     bool isStandaloneFunction) {
   FunctionBox* funbox = pc_->functionBox();
 
   if (funbox->hasParameterExprs) {
     if (!propagateFreeNamesAndMarkClosedOverBindings(pc_->functionScope())) {
       return false;
@@ -1873,93 +1812,16 @@ FunctionNode* Parser<FullParseHandler, U
 
   if (!this->setSourceMapInfo()) {
     return null();
   }
 
   return funNode;
 }
 
-template <class ParseHandler>
-bool PerHandlerParser<ParseHandler>::declareFunctionArgumentsObject() {
-  FunctionBox* funbox = pc_->functionBox();
-  ParseContext::Scope& funScope = pc_->functionScope();
-  ParseContext::Scope& varScope = pc_->varScope();
-
-  bool hasExtraBodyVarScope = &funScope != &varScope;
-
-  // Time to implement the odd semantics of 'arguments'.
-  HandlePropertyName argumentsName = cx_->names().arguments;
-
-  bool tryDeclareArguments;
-  if (handler_.canSkipLazyClosedOverBindings()) {
-    tryDeclareArguments =
-        funbox->function()->lazyScript()->shouldDeclareArguments();
-  } else {
-    tryDeclareArguments = hasUsedFunctionSpecialName(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 {
-      funbox->usesArguments = true;
-    }
-  }
-
-  if (tryDeclareArguments) {
-    AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName);
-    if (!p) {
-      if (!funScope.addDeclaredName(pc_, p, argumentsName, DeclarationKind::Var,
-                                    DeclaredNameInfo::npos)) {
-        return false;
-      }
-      funbox->declaredArguments = true;
-      funbox->usesArguments = true;
-    } else if (hasExtraBodyVarScope) {
-      // Formal parameters shadow the arguments object.
-      return true;
-    }
-  }
-
-  // Compute if we need an arguments object.
-  if (funbox->usesArguments) {
-    // There is an 'arguments' binding. Is the arguments object definitely
-    // needed?
-    //
-    // Also see the flags' comments in ContextFlags.
-    funbox->setArgumentsHasLocalBinding();
-
-    // Dynamic scope access destroys all hope of optimization.
-    if (pc_->sc()->bindingsAccessedDynamically()) {
-      funbox->setDefinitelyNeedsArgsObj();
-    }
-
-    // If a script contains the debugger statement either directly or
-    // within an inner function, the arguments object should be created
-    // eagerly so the Debugger API may observe bindings.
-    if (pc_->sc()->hasDebuggerStatement()) {
-      funbox->setDefinitelyNeedsArgsObj();
-    }
-  }
-
-  return true;
-}
-
 template <class ParseHandler, typename Unit>
 typename ParseHandler::LexicalScopeNodeType
 GeneralParser<ParseHandler, Unit>::functionBody(InHandling inHandling,
                                                 YieldHandling yieldHandling,
                                                 FunctionSyntaxKind kind,
                                                 FunctionBodyType type) {
   MOZ_ASSERT(pc_->isFunctionBox());
 
@@ -2019,36 +1881,39 @@ GeneralParser<ParseHandler, Unit>::funct
 
   MOZ_ASSERT_IF(!pc_->isGenerator() && !pc_->isAsync(),
                 pc_->lastYieldOffset == startYieldOffset);
   MOZ_ASSERT_IF(pc_->isGenerator(), kind != FunctionSyntaxKind::Arrow);
   MOZ_ASSERT_IF(pc_->isGenerator(), type == StatementListBody);
 
   if (pc_->needsDotGeneratorName()) {
     MOZ_ASSERT_IF(!pc_->isAsync(), type == StatementListBody);
-    if (!declareDotGeneratorName()) {
+    if (!pc_->declareDotGeneratorName()) {
       return null();
     }
     NameNodeType generator = newDotGeneratorName();
     if (!generator) {
       return null();
     }
     if (!handler_.prependInitialYield(handler_.asList(body), generator)) {
       return null();
     }
   }
 
   // Declare the 'arguments' and 'this' bindings if necessary before
   // finishing up the scope so these special bindings get marked as closed
   // over if necessary. Arrow functions don't have these bindings.
   if (kind != FunctionSyntaxKind::Arrow) {
-    if (!declareFunctionArgumentsObject()) {
-      return null();
-    }
-    if (!declareFunctionThis()) {
+    bool canSkipLazyClosedOverBindings =
+        handler_.canSkipLazyClosedOverBindings();
+    if (!pc_->declareFunctionArgumentsObject(usedNames_,
+                                             canSkipLazyClosedOverBindings)) {
+      return null();
+    }
+    if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
       return null();
     }
   }
 
   return finishLexicalScope(pc_->varScope(), body);
 }
 
 JSFunction* AllocNewFunction(JSContext* cx, HandleAtom atom,
@@ -7261,17 +7126,18 @@ GeneralParser<ParseHandler, Unit>::synth
   if (!stmtList) {
     return null();
   }
 
   if (!noteUsedName(cx_->names().dotThis)) {
     return null();
   }
 
-  if (!declareFunctionThis()) {
+  bool canSkipLazyClosedOverBindings = handler_.canSkipLazyClosedOverBindings();
+  if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
     return null();
   }
 
   // Set the function's body to the field assignment.
   auto initializerBody = finishLexicalScope(lexicalScope, stmtList);
   if (!initializerBody) {
     return null();
   }
@@ -7390,17 +7256,18 @@ GeneralParser<ParseHandler, Unit>::field
   AssignmentNodeType initializerAssignment = handler_.newAssignment(
       ParseNodeKind::AssignExpr, propAssignFieldAccess, initializerExpr);
   if (!initializerAssignment) {
     return null();
   }
   handler_.setBeginPosition(initializerAssignment, initializerExpr);
   handler_.setEndPosition(initializerAssignment, initializerExpr);
 
-  if (!declareFunctionThis()) {
+  bool canSkipLazyClosedOverBindings = handler_.canSkipLazyClosedOverBindings();
+  if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
     return null();
   }
 
   // Set the function's body to the field assignment.
   LexicalScopeNodeType initializerBody =
       finishLexicalScope(lexicalScope, initializerAssignment);
   if (!initializerBody) {
     return null();
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -267,19 +267,16 @@ class MOZ_STACK_CLASS ParserSharedBase :
 
  private:
   // This is needed to cast a parser to JS::AutoGCRooter.
   friend void js::frontend::TraceParser(JSTracer* trc,
                                         JS::AutoGCRooter* parser);
   friend void js::frontend::TraceBinParser(JSTracer* trc,
                                            JS::AutoGCRooter* parser);
 
- protected:
-  bool hasUsedName(HandlePropertyName name);
-
  private:
   // Create a new traceable node and store it into the trace list.
   template <typename BoxT, typename ArgT>
   BoxT* newTraceListNode(ArgT* arg);
 
  public:
   // Create a new JSObject and store it into the trace list.
   ObjectBox* newObjectBox(JSObject* obj);
@@ -441,22 +438,19 @@ class MOZ_STACK_CLASS ParserBase : publi
   enum ForInitLocation { InForInit, NotInForInit };
 
   // While on a |let| Name token, examine |next| (which must already be
   // gotten).  Indicate whether |next|, the next token already gotten with
   // modifier TokenStream::None, continues a LexicalDeclaration.
   bool nextTokenContinuesLetDeclaration(TokenKind next);
 
   bool noteUsedNameInternal(HandlePropertyName name);
-  bool hasUsedFunctionSpecialName(HandlePropertyName name);
 
   bool checkAndMarkSuperScope();
 
-  bool declareDotGeneratorName();
-
   bool leaveInnerFunction(ParseContext* outerpc);
 
   JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom);
 
   MOZ_MUST_USE bool setSourceMapInfo();
 };
 
 enum FunctionCallBehavior {
@@ -548,19 +542,16 @@ class MOZ_STACK_CLASS PerHandlerParser :
   // Required on Scope exit.
   bool propagateFreeNamesAndMarkClosedOverBindings(ParseContext::Scope& scope);
 
   bool finishFunctionScopes(bool isStandaloneFunction);
   LexicalScopeNodeType finishLexicalScope(ParseContext::Scope& scope,
                                           Node body);
   bool finishFunction(bool isStandaloneFunction = false);
 
-  bool declareFunctionThis();
-  bool declareFunctionArgumentsObject();
-
   inline NameNodeType newName(PropertyName* name);
   inline NameNodeType newName(PropertyName* name, TokenPos pos);
 
   NameNodeType newInternalDotName(HandlePropertyName name);
   NameNodeType newThisName();
   NameNodeType newDotGeneratorName();
 
   NameNodeType identifierReference(Handle<PropertyName*> name);
@@ -745,17 +736,16 @@ class MOZ_STACK_CLASS GeneralParser : pu
   using Base::parseGoal;
 #if DEBUG
   using Base::checkOptionsCalled_;
 #endif
   using Base::finishFunctionScopes;
   using Base::finishLexicalScope;
   using Base::foldConstants_;
   using Base::getFilename;
-  using Base::hasUsedFunctionSpecialName;
   using Base::hasValidSimpleStrictParameterNames;
   using Base::isUnexpectedEOF_;
   using Base::keepAtoms_;
   using Base::nameIsArgumentsOrEval;
   using Base::newFunction;
   using Base::newFunctionBox;
   using Base::newName;
   using Base::null;
@@ -808,21 +798,17 @@ class MOZ_STACK_CLASS GeneralParser : pu
   using Base::cx_;
   using Base::handler_;
   using Base::isValidSimpleAssignmentTarget;
   using Base::pc_;
   using Base::usedNames_;
 
  private:
   using Base::checkAndMarkSuperScope;
-  using Base::declareDotGeneratorName;
-  using Base::declareFunctionArgumentsObject;
-  using Base::declareFunctionThis;
   using Base::finishFunction;
-  using Base::hasUsedName;
   using Base::identifierReference;
   using Base::leaveInnerFunction;
   using Base::newDotGeneratorName;
   using Base::newInternalDotName;
   using Base::newThisName;
   using Base::nextTokenContinuesLetDeclaration;
   using Base::noSubstitutionTaggedTemplate;
   using Base::noteDestructuredPositionalFormalParameter;