tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ParseContext.cpp (27836B)


      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 
     13 using mozilla::Maybe;
     14 using mozilla::Nothing;
     15 using mozilla::Some;
     16 
     17 namespace js {
     18 namespace frontend {
     19 
     20 using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr;
     21 using DeclaredNamePtr = ParseContext::Scope::DeclaredNamePtr;
     22 
     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";
     62  }
     63 
     64  MOZ_CRASH("Bad DeclarationKind");
     65 }
     66 
     67 bool DeclarationKindIsVar(DeclarationKind kind) {
     68  return kind == DeclarationKind::Var ||
     69         kind == DeclarationKind::BodyLevelFunction ||
     70         kind == DeclarationKind::VarForAnnexBLexicalFunction;
     71 }
     72 
     73 bool DeclarationKindIsParameter(DeclarationKind kind) {
     74  return kind == DeclarationKind::PositionalFormalParameter ||
     75         kind == DeclarationKind::FormalParameter;
     76 }
     77 
     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);
     84 
     85    if (!p->value().noteUsedInScope(scriptId, scopeId)) {
     86      return false;
     87    }
     88  } else {
     89    // We need a token position precisely where we have private visibility.
     90    MOZ_ASSERT(tokenPosition.isSome() ==
     91               (visibility == NameVisibility::Private));
     92 
     93    if (visibility == NameVisibility::Private) {
     94      // We have seen at least one private name
     95      hasPrivateNames_ = true;
     96    }
     97 
     98    UsedNameInfo info(fc, visibility, tokenPosition);
     99 
    100    if (!info.noteUsedInScope(scriptId, scopeId)) {
    101      return false;
    102    }
    103    if (!map_.add(p, name, std::move(info))) {
    104      return false;
    105    }
    106  }
    107 
    108  return true;
    109 }
    110 
    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;
    116  }
    117 
    118  for (auto iter = map_.iter(); !iter.done(); iter.next()) {
    119    // Don't care about public;
    120    if (iter.get().value().isPublic()) {
    121      continue;
    122    }
    123 
    124    // empty list means all bound
    125    if (iter.get().value().empty()) {
    126      continue;
    127    }
    128 
    129    if (!unboundPrivateNames.emplaceBack(iter.get().key(),
    130                                         *iter.get().value().pos())) {
    131      return false;
    132    }
    133  }
    134 
    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;
    138  };
    139  std::sort(unboundPrivateNames.begin(), unboundPrivateNames.end(),
    140            comparePosition);
    141 
    142  return true;
    143 }
    144 
    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;
    150  }
    151 
    152  Vector<UnboundPrivateName, 8> unboundPrivateNames(fc);
    153  if (!getUnboundPrivateNames(unboundPrivateNames)) {
    154    return false;
    155  }
    156 
    157  if (unboundPrivateNames.empty()) {
    158    return true;
    159  }
    160 
    161  // GetUnboundPrivateNames returns the list sorted.
    162  maybeUnboundName.emplace(unboundPrivateNames[0]);
    163  return true;
    164 }
    165 
    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;
    172    }
    173    MOZ_ASSERT(innermost.scriptId >= scriptId);
    174    uses_.popBack();
    175  }
    176 }
    177 
    178 void UsedNameTracker::rewind(RewindToken token) {
    179  scriptCounter_ = token.scriptId;
    180  scopeCounter_ = token.scopeId;
    181 
    182  for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
    183    r.front().value().resetToScope(token.scriptId, token.scopeId);
    184  }
    185 }
    186 
    187 #if defined(DEBUG) || defined(JS_JITSPEW)
    188 void UsedNameTracker::dump(ParserAtomsTable& table) {
    189  js::Fprinter out(stderr);
    190 
    191  out.printf("Used names:\n");
    192 
    193  for (UsedNameMap::Range r = map_.all(); !r.empty(); r.popFront()) {
    194    const auto& item = r.front();
    195 
    196    const auto& name = item.key();
    197    const auto& nameInfo = item.value();
    198 
    199    out.put("  ");
    200    table.dumpCharsNoQuote(out, name);
    201    out.put("\n");
    202 
    203    if (nameInfo.visibility_ == NameVisibility::Private) {
    204      out.put("    visibility: private\n");
    205    }
    206 
    207    if (nameInfo.firstUsePos_) {
    208      const auto& pos = *nameInfo.firstUsePos_;
    209      out.printf("    first use pos: %u\n", pos.begin);
    210    }
    211 
    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(", ");
    220      }
    221      out.printf("%u/%u", use.scriptId, use.scopeId);
    222    }
    223    if (!first) {
    224      out.put(")");
    225    }
    226    out.put("\n");
    227  }
    228 }
    229 #endif
    230 
    231 void ParseContext::Scope::dump(ParseContext* pc, ParserBase* parser) {
    232  fprintf(stdout, "ParseScope %p", this);
    233 
    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;
    241    }
    242    DeclaredNameInfo& info = r.front().value().wrapped;
    243    fprintf(stdout, "    %s %s%s\n", DeclarationKindString(info.kind()),
    244            bytes.get(), info.closedOver() ? " (closed over)" : "");
    245  }
    246 
    247  fprintf(stdout, "\n");
    248 }
    249 
    250 bool ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc,
    251                                                       FunctionBox* funbox) {
    252  if (!possibleAnnexBFunctionBoxes_) {
    253    if (!possibleAnnexBFunctionBoxes_.acquire(pc->sc()->fc_)) {
    254      return false;
    255    }
    256  }
    257 
    258  return maybeReportOOM(pc, possibleAnnexBFunctionBoxes_->append(funbox));
    259 }
    260 
    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;
    267  }
    268 
    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;
    279      }
    280      if (annexBApplies) {
    281        if (!pc->tryDeclareVar(funbox->explicitName(), parser,
    282                               DeclarationKind::VarForAnnexBLexicalFunction,
    283                               DeclaredNameInfo::npos, &redeclaredKind,
    284                               &unused)) {
    285          return false;
    286        }
    287 
    288        MOZ_ASSERT(!redeclaredKind);
    289        funbox->isAnnexB = true;
    290      }
    291    }
    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;
    300      }
    301      if (annexBApplies) {
    302        if (!enclosing()->addPossibleAnnexBFunctionBox(pc, funbox)) {
    303          return false;
    304        }
    305      }
    306    }
    307  }
    308 
    309  return true;
    310 }
    311 
    312 static bool DeclarationKindIsCatchParameter(DeclarationKind kind) {
    313  return kind == DeclarationKind::SimpleCatchParameter ||
    314         kind == DeclarationKind::CatchParameter;
    315 }
    316 
    317 bool ParseContext::Scope::addCatchParameters(ParseContext* pc,
    318                                             Scope& catchParamScope) {
    319  if (pc->useAsmOrInsideUseAsm()) {
    320    return true;
    321  }
    322 
    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;
    333    }
    334  }
    335 
    336  return true;
    337 }
    338 
    339 void ParseContext::Scope::removeCatchParameters(ParseContext* pc,
    340                                                Scope& catchParamScope) {
    341  if (pc->useAsmOrInsideUseAsm()) {
    342    return;
    343  }
    344 
    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);
    350 
    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);
    355    }
    356  }
    357 }
    358 
    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);
    380    }
    381    functionScope_.emplace(fc, parent, compilationState.usedNames);
    382  }
    383 }
    384 
    385 bool ParseContext::init() {
    386  if (scriptId_ == UINT32_MAX) {
    387    errorReporter_.errorNoOffset(JSMSG_NEED_DIET, "script");
    388    return false;
    389  }
    390 
    391  FrontendContext* fc = sc()->fc_;
    392 
    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;
    401      }
    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;
    409      }
    410    }
    411 
    412    if (!functionScope_->init(this)) {
    413      return false;
    414    }
    415 
    416    if (!positionalFormalParameterNames_.acquire(fc)) {
    417      return false;
    418    }
    419  }
    420 
    421  if (!closedOverBindingsForLazy_.acquire(fc)) {
    422    return false;
    423  }
    424 
    425  return true;
    426 }
    427 
    428 bool ParseContext::computeAnnexBAppliesToLexicalFunctionInInnermostScope(
    429    FunctionBox* funbox, ParserBase* parser, bool* annexBApplies) {
    430  MOZ_ASSERT(!sc()->strict());
    431 
    432  TaggedParserAtomIndex name = funbox->explicitName();
    433  Maybe<DeclarationKind> redeclaredKind;
    434  if (!isVarRedeclaredInInnermostScope(
    435          name, parser, DeclarationKind::VarForAnnexBLexicalFunction,
    436          &redeclaredKind)) {
    437    return false;
    438  }
    439 
    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));
    454        }
    455      }
    456    }
    457  }
    458 
    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;
    463 }
    464 
    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);
    471 }
    472 
    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;
    482  }
    483 
    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;
    500  }
    501  return true;
    502 }
    503 
    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);
    510 }
    511 
    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));
    519 
    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:
    523  //
    524  //   { let x; var x; }
    525  //   { { var x; } let x; }
    526  //
    527  // And the following are not:
    528  //
    529  //   { var x; var x; }
    530  //   { { let x; } var x; }
    531 
    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);
    539        }
    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;
    545 
    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();
    551 
    552        if (!annexB35Allowance && !annexB33Allowance) {
    553          *redeclaredKind = Some(declaredKind);
    554          *prevPos = p->value()->pos();
    555          return true;
    556        }
    557      } else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) {
    558        MOZ_ASSERT(DeclarationKindIsParameter(declaredKind));
    559 
    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;
    565      }
    566    } else if (dryRunOption == NotDryRun) {
    567      if (!scope->addDeclaredName(this, p, name, kind, beginPos)) {
    568        return false;
    569      }
    570    }
    571 
    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;
    579    }
    580  }
    581 
    582  if (!sc()->strict() && sc()->isEvalContext() &&
    583      (dryRunOption == NotDryRun || innermostScope() == &varScope())) {
    584    if (!isVarRedeclaredInEval(name, parser, kind, redeclaredKind)) {
    585      return false;
    586    }
    587    // We don't have position information at runtime.
    588    *prevPos = DeclaredNameInfo::npos;
    589  }
    590 
    591  return true;
    592 }
    593 
    594 bool ParseContext::hasUsedName(const UsedNameTracker& usedNames,
    595                               TaggedParserAtomIndex name) {
    596  if (auto p = usedNames.lookup(name)) {
    597    return p->value().isUsedInScript(scriptId());
    598  }
    599  return false;
    600 }
    601 
    602 bool ParseContext::hasClosedOverName(const UsedNameTracker& usedNames,
    603                                     TaggedParserAtomIndex name) {
    604  if (auto p = usedNames.lookup(name)) {
    605    return p->value().isClosedOver(scriptId());
    606  }
    607  return false;
    608 }
    609 
    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();
    617 }
    618 
    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();
    624 }
    625 
    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;
    632  }
    633 
    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_();
    639 
    640  bool declareThis;
    641  if (canSkipLazyClosedOverBindings) {
    642    declareThis = funbox->functionHasThisBinding();
    643  } else {
    644    declareThis = hasUsedFunctionSpecialName(usedNames, dotThis) ||
    645                  funbox->isClassConstructor();
    646  }
    647 
    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;
    655    }
    656    funbox->setFunctionHasThisBinding();
    657  }
    658 
    659  return true;
    660 }
    661 
    662 bool ParseContext::declareFunctionArgumentsObject(
    663    const UsedNameTracker& usedNames, bool canSkipLazyClosedOverBindings) {
    664  FunctionBox* funbox = functionBox();
    665  ParseContext::Scope& funScope = functionScope();
    666  ParseContext::Scope& _varScope = varScope();
    667 
    668  bool hasExtraBodyVarScope = &funScope != &_varScope;
    669 
    670  // Time to implement the odd semantics of 'arguments'.
    671  auto argumentsName = TaggedParserAtomIndex::WellKnown::arguments();
    672 
    673  bool tryDeclareArguments = false;
    674  bool needsArgsObject = false;
    675 
    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;
    688 
    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;
    702    }
    703  }
    704 
    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.
    708  //
    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.
    711  //
    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();
    726      }
    727 
    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;
    731    }
    732  }
    733 
    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;
    741      }
    742      funbox->setShouldDeclareArguments();
    743      if (needsArgsObject) {
    744        funbox->setNeedsArgsObj();
    745      }
    746    }
    747  }
    748  return true;
    749 }
    750 
    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;
    757  }
    758 
    759  FunctionBox* funbox = functionBox();
    760  auto dotNewTarget = TaggedParserAtomIndex::WellKnown::dot_newTarget_();
    761 
    762  bool declareNewTarget;
    763  if (canSkipLazyClosedOverBindings) {
    764    declareNewTarget = funbox->functionHasNewTargetBinding();
    765  } else {
    766    declareNewTarget = hasUsedFunctionSpecialName(usedNames, dotNewTarget);
    767  }
    768 
    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;
    776    }
    777    funbox->setFunctionHasNewTargetBinding();
    778  }
    779 
    780  return true;
    781 }
    782 
    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;
    793    }
    794  }
    795  return true;
    796 }
    797 
    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);
    811 }
    812 
    813 }  // namespace frontend
    814 
    815 }  // namespace js