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