EmitterScope.cpp (38903B)
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/EmitterScope.h" 8 9 #include "frontend/AbstractScopePtr.h" 10 #include "frontend/BytecodeControlStructures.h" 11 #include "frontend/BytecodeEmitter.h" 12 #include "frontend/ModuleSharedContext.h" 13 #include "frontend/TDZCheckCache.h" 14 #include "frontend/UsingEmitter.h" 15 #include "js/friend/ErrorMessages.h" // JSMSG_* 16 #include "vm/EnvironmentObject.h" // ClassBodyLexicalEnvironmentObject 17 18 using namespace js; 19 using namespace js::frontend; 20 21 using mozilla::DebugOnly; 22 using mozilla::Maybe; 23 using mozilla::Nothing; 24 using mozilla::Some; 25 26 EmitterScope::EmitterScope(BytecodeEmitter* bce) 27 : Nestable<EmitterScope>(&bce->innermostEmitterScope_), 28 nameCache_(bce->fc->nameCollectionPool()), 29 hasEnvironment_(false), 30 environmentChainLength_(0), 31 nextFrameSlot_(0), 32 scopeIndex_(ScopeNote::NoScopeIndex), 33 noteIndex_(ScopeNote::NoScopeNoteIndex) {} 34 35 bool EmitterScope::ensureCache(BytecodeEmitter* bce) { 36 return nameCache_.acquire(bce->fc); 37 } 38 39 bool EmitterScope::checkSlotLimits(BytecodeEmitter* bce, 40 const ParserBindingIter& bi) { 41 if (bi.nextFrameSlot() >= LOCALNO_LIMIT || 42 bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT) { 43 bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS); 44 return false; 45 } 46 return true; 47 } 48 49 bool EmitterScope::checkEnvironmentChainLength(BytecodeEmitter* bce) { 50 uint32_t hops; 51 if (EmitterScope* emitterScope = enclosing(&bce)) { 52 hops = emitterScope->environmentChainLength_; 53 } else if (!bce->compilationState.input.enclosingScope.isNull()) { 54 hops = 55 bce->compilationState.scopeContext.enclosingScopeEnvironmentChainLength; 56 } else { 57 // If we're compiling module, enclosingScope is nullptr and it means empty 58 // global scope. 59 // See also the assertion in CompilationStencil::instantiateStencils. 60 // 61 // Global script also uses enclosingScope == nullptr, but it shouldn't call 62 // checkEnvironmentChainLength. 63 MOZ_ASSERT(bce->sc->isModule()); 64 hops = ModuleScope::EnclosingEnvironmentChainLength; 65 } 66 67 if (hops >= ENVCOORD_HOPS_LIMIT - 1) { 68 bce->reportError(nullptr, JSMSG_TOO_DEEP, "function"); 69 return false; 70 } 71 72 environmentChainLength_ = mozilla::AssertedCast<uint16_t>(hops + 1); 73 return true; 74 } 75 76 void EmitterScope::updateFrameFixedSlots(BytecodeEmitter* bce, 77 const ParserBindingIter& bi) { 78 nextFrameSlot_ = bi.nextFrameSlot(); 79 if (nextFrameSlot_ > bce->maxFixedSlots) { 80 bce->maxFixedSlots = nextFrameSlot_; 81 } 82 } 83 84 bool EmitterScope::putNameInCache(BytecodeEmitter* bce, 85 TaggedParserAtomIndex name, 86 NameLocation loc) { 87 NameLocationMap& cache = *nameCache_; 88 NameLocationMap::AddPtr p = cache.lookupForAdd(name); 89 MOZ_ASSERT(!p); 90 if (!cache.add(p, name, loc)) { 91 ReportOutOfMemory(bce->fc); 92 return false; 93 } 94 return true; 95 } 96 97 Maybe<NameLocation> EmitterScope::lookupInCache(BytecodeEmitter* bce, 98 TaggedParserAtomIndex name) { 99 if (NameLocationMap::Ptr p = nameCache_->lookup(name)) { 100 return Some(p->value().wrapped); 101 } 102 if (fallbackFreeNameLocation_ && nameCanBeFree(bce, name)) { 103 return fallbackFreeNameLocation_; 104 } 105 return Nothing(); 106 } 107 108 EmitterScope* EmitterScope::enclosing(BytecodeEmitter** bce) const { 109 // There is an enclosing scope with access to the same frame. 110 if (EmitterScope* inFrame = enclosingInFrame()) { 111 return inFrame; 112 } 113 114 // We are currently compiling the enclosing script, look in the 115 // enclosing BCE. 116 if ((*bce)->parent) { 117 *bce = (*bce)->parent; 118 return (*bce)->innermostEmitterScopeNoCheck(); 119 } 120 121 return nullptr; 122 } 123 124 mozilla::Maybe<ScopeIndex> EmitterScope::enclosingScopeIndex( 125 BytecodeEmitter* bce) const { 126 if (EmitterScope* es = enclosing(&bce)) { 127 // NOTE: A value of Nothing for the ScopeIndex will occur when the enclosing 128 // scope is the empty-global-scope. This is only allowed for self-hosting 129 // code. 130 MOZ_ASSERT_IF(es->scopeIndex(bce).isNothing(), 131 bce->emitterMode == BytecodeEmitter::SelfHosting); 132 return es->scopeIndex(bce); 133 } 134 135 // The enclosing script is already compiled or the current script is the 136 // global script. 137 return mozilla::Nothing(); 138 } 139 140 /* static */ 141 bool EmitterScope::nameCanBeFree(BytecodeEmitter* bce, 142 TaggedParserAtomIndex name) { 143 // '.generator' cannot be accessed by name. 144 return name != TaggedParserAtomIndex::WellKnown::dot_generator_(); 145 } 146 147 NameLocation EmitterScope::searchAndCache(BytecodeEmitter* bce, 148 TaggedParserAtomIndex name) { 149 Maybe<NameLocation> loc; 150 uint16_t hops = hasEnvironment() ? 1 : 0; 151 DebugOnly<bool> inCurrentScript = enclosingInFrame(); 152 153 // Start searching in the current compilation. 154 for (EmitterScope* es = enclosing(&bce); es; es = es->enclosing(&bce)) { 155 loc = es->lookupInCache(bce, name); 156 if (loc) { 157 if (loc->kind() == NameLocation::Kind::EnvironmentCoordinate) { 158 *loc = loc->addHops(hops); 159 } 160 break; 161 } 162 163 if (es->hasEnvironment()) { 164 hops++; 165 } 166 167 #ifdef DEBUG 168 if (!es->enclosingInFrame()) { 169 inCurrentScript = false; 170 } 171 #endif 172 } 173 174 // If the name is not found in the current compilation, walk the Scope 175 // chain encompassing the compilation. 176 if (!loc) { 177 MOZ_ASSERT(bce->compilationState.input.target == 178 CompilationInput::CompilationTarget::Delazification || 179 bce->compilationState.input.target == 180 CompilationInput::CompilationTarget::Eval); 181 inCurrentScript = false; 182 loc = Some(bce->compilationState.scopeContext.searchInEnclosingScope( 183 bce->fc, bce->compilationState.input, bce->parserAtoms(), name)); 184 if (loc->kind() == NameLocation::Kind::EnvironmentCoordinate) { 185 *loc = loc->addHops(hops); 186 } 187 } 188 189 // Each script has its own frame. A free name that is accessed 190 // from an inner script must not be a frame slot access. If this 191 // assertion is hit, it is a bug in the free name analysis in the 192 // parser. 193 MOZ_ASSERT_IF(!inCurrentScript, loc->kind() != NameLocation::Kind::FrameSlot); 194 195 // It is always correct to not cache the location. Ignore OOMs to make 196 // lookups infallible. 197 if (!putNameInCache(bce, name, *loc)) { 198 bce->fc->recoverFromOutOfMemory(); 199 } 200 201 return *loc; 202 } 203 204 bool EmitterScope::internEmptyGlobalScopeAsBody(BytecodeEmitter* bce) { 205 // Only the self-hosted top-level script uses this. If this changes, you must 206 // update ScopeStencil::enclosing. 207 MOZ_ASSERT(bce->emitterMode == BytecodeEmitter::SelfHosting); 208 209 hasEnvironment_ = Scope::hasEnvironment(ScopeKind::Global); 210 211 bce->bodyScopeIndex = 212 GCThingIndex(bce->perScriptData().gcThingList().length()); 213 return bce->perScriptData().gcThingList().appendEmptyGlobalScope( 214 &scopeIndex_); 215 } 216 217 bool EmitterScope::internScopeStencil(BytecodeEmitter* bce, 218 ScopeIndex scopeIndex) { 219 ScopeStencil& scope = bce->compilationState.scopeData[scopeIndex.index]; 220 hasEnvironment_ = scope.hasEnvironment(); 221 return bce->perScriptData().gcThingList().append(scopeIndex, &scopeIndex_); 222 } 223 224 bool EmitterScope::internBodyScopeStencil(BytecodeEmitter* bce, 225 ScopeIndex scopeIndex) { 226 MOZ_ASSERT(bce->bodyScopeIndex == ScopeNote::NoScopeIndex, 227 "There can be only one body scope"); 228 bce->bodyScopeIndex = 229 GCThingIndex(bce->perScriptData().gcThingList().length()); 230 return internScopeStencil(bce, scopeIndex); 231 } 232 233 bool EmitterScope::appendScopeNote(BytecodeEmitter* bce) { 234 MOZ_ASSERT(ScopeKindIsInBody(scope(bce).kind()) && enclosingInFrame(), 235 "Scope notes are not needed for body-level scopes."); 236 noteIndex_ = bce->bytecodeSection().scopeNoteList().length(); 237 return bce->bytecodeSection().scopeNoteList().append( 238 index(), bce->bytecodeSection().offset(), 239 enclosingInFrame() ? enclosingInFrame()->noteIndex() 240 : ScopeNote::NoScopeNoteIndex); 241 } 242 243 bool EmitterScope::clearFrameSlotRange(BytecodeEmitter* bce, JSOp opcode, 244 uint32_t slotStart, 245 uint32_t slotEnd) const { 246 MOZ_ASSERT(opcode == JSOp::Uninitialized || opcode == JSOp::Undefined); 247 248 // Lexical bindings throw ReferenceErrors if they are used before 249 // initialization. See ES6 8.1.1.1.6. 250 // 251 // For completeness, lexical bindings are initialized in ES6 by calling 252 // InitializeBinding, after which touching the binding will no longer 253 // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6, 254 // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15. 255 // 256 // This code is also used to reset `var`s to `undefined` when entering an 257 // extra body var scope; and to clear slots when leaving a block, in 258 // generators and async functions, to avoid keeping garbage alive 259 // indefinitely. 260 if (slotStart != slotEnd) { 261 if (!bce->emit1(opcode)) { 262 return false; 263 } 264 for (uint32_t slot = slotStart; slot < slotEnd; slot++) { 265 if (!bce->emitLocalOp(JSOp::InitLexical, slot)) { 266 return false; 267 } 268 } 269 if (!bce->emit1(JSOp::Pop)) { 270 return false; 271 } 272 } 273 274 return true; 275 } 276 277 void EmitterScope::dump(BytecodeEmitter* bce) { 278 fprintf(stdout, "EmitterScope [%s] %p\n", ScopeKindString(scope(bce).kind()), 279 this); 280 281 for (NameLocationMap::Range r = nameCache_->all(); !r.empty(); r.popFront()) { 282 const NameLocation& l = r.front().value(); 283 284 auto atom = r.front().key(); 285 UniqueChars bytes = bce->parserAtoms().toPrintableString(atom); 286 if (!bytes) { 287 ReportOutOfMemory(bce->fc); 288 return; 289 } 290 if (l.kind() != NameLocation::Kind::Dynamic) { 291 fprintf(stdout, " %s %s ", BindingKindString(l.bindingKind()), 292 bytes.get()); 293 } else { 294 fprintf(stdout, " %s ", bytes.get()); 295 } 296 297 switch (l.kind()) { 298 case NameLocation::Kind::Dynamic: 299 fprintf(stdout, "dynamic\n"); 300 break; 301 case NameLocation::Kind::Global: 302 fprintf(stdout, "global\n"); 303 break; 304 case NameLocation::Kind::Intrinsic: 305 fprintf(stdout, "intrinsic\n"); 306 break; 307 case NameLocation::Kind::NamedLambdaCallee: 308 fprintf(stdout, "named lambda callee\n"); 309 break; 310 case NameLocation::Kind::Import: 311 fprintf(stdout, "import\n"); 312 break; 313 case NameLocation::Kind::ArgumentSlot: 314 fprintf(stdout, "arg slot=%u\n", l.argumentSlot()); 315 break; 316 case NameLocation::Kind::FrameSlot: 317 fprintf(stdout, "frame slot=%u\n", l.frameSlot()); 318 break; 319 case NameLocation::Kind::EnvironmentCoordinate: 320 fprintf(stdout, "environment hops=%u slot=%u\n", 321 l.environmentCoordinate().hops(), 322 l.environmentCoordinate().slot()); 323 break; 324 case NameLocation::Kind::DebugEnvironmentCoordinate: 325 fprintf(stdout, "debugEnvironment hops=%u slot=%u\n", 326 l.environmentCoordinate().hops(), 327 l.environmentCoordinate().slot()); 328 break; 329 case NameLocation::Kind::DynamicAnnexBVar: 330 fprintf(stdout, "dynamic annex b var\n"); 331 break; 332 } 333 } 334 335 fprintf(stdout, "\n"); 336 } 337 338 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 339 bool EmitterScope::prepareForDisposableScopeBody(BytecodeEmitter* bce) { 340 if (hasDisposables()) { 341 if (!usingEmitter_->prepareForDisposableScopeBody(blockKind_)) { 342 return false; 343 } 344 } 345 return true; 346 } 347 348 bool EmitterScope::prepareForModuleDisposableScopeBody(BytecodeEmitter* bce) { 349 return prepareForDisposableScopeBody(bce); 350 } 351 352 bool EmitterScope::prepareForDisposableAssignment(UsingHint hint) { 353 MOZ_ASSERT(hasDisposables()); 354 return usingEmitter_->prepareForAssignment(hint); 355 } 356 357 bool EmitterScope::emitDisposableScopeBodyEnd(BytecodeEmitter* bce) { 358 // For-of loops emit the dispose loop in the different place and timing. 359 // (See ForOfEmitter::emitInitialize, 360 // ForOfLoopControl::emitPrepareForNonLocalJumpFromScope and 361 // ForOfLoopControl::emitEndCodeNeedingIteratorClose()) 362 if (hasDisposables() && (blockKind_ != BlockKind::ForOf)) { 363 if (!usingEmitter_->emitEnd()) { 364 return false; 365 } 366 } 367 return true; 368 } 369 370 bool EmitterScope::emitModuleDisposableScopeBodyEnd(BytecodeEmitter* bce) { 371 return emitDisposableScopeBodyEnd(bce); 372 } 373 #endif 374 375 bool EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind, 376 LexicalScope::ParserData* bindings 377 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 378 , 379 BlockKind blockKind 380 #endif 381 ) { 382 MOZ_ASSERT(kind != ScopeKind::NamedLambda && 383 kind != ScopeKind::StrictNamedLambda); 384 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); 385 386 if (!ensureCache(bce)) { 387 return false; 388 } 389 390 // Resolve bindings. 391 TDZCheckCache* tdzCache = bce->innermostTDZCheckCache; 392 uint32_t firstFrameSlot = frameSlotStart(); 393 ParserBindingIter bi(*bindings, firstFrameSlot, /* isNamedLambda = */ false); 394 for (; bi; bi++) { 395 if (!checkSlotLimits(bce, bi)) { 396 return false; 397 } 398 399 NameLocation loc = bi.nameLocation(); 400 if (!putNameInCache(bce, bi.name(), loc)) { 401 return false; 402 } 403 404 if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ)) { 405 return false; 406 } 407 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 408 if (bi.kind() == BindingKind::Using) { 409 setHasDisposables(bce); 410 } 411 #endif 412 } 413 414 updateFrameFixedSlots(bce, bi); 415 416 ScopeIndex scopeIndex; 417 if (!ScopeStencil::createForLexicalScope( 418 bce->fc, bce->compilationState, kind, bindings, firstFrameSlot, 419 enclosingScopeIndex(bce), &scopeIndex)) { 420 return false; 421 } 422 if (!internScopeStencil(bce, scopeIndex)) { 423 return false; 424 } 425 426 if (ScopeKindIsInBody(kind) && hasEnvironment()) { 427 // After interning the VM scope we can get the scope index. 428 if (!bce->emitInternedScopeOp(index(), JSOp::PushLexicalEnv)) { 429 return false; 430 } 431 } 432 433 // Lexical scopes need notes to be mapped from a pc. 434 if (!appendScopeNote(bce)) { 435 return false; 436 } 437 438 // Put frame slots in TDZ. Environment slots are poisoned during 439 // environment creation. 440 // 441 // This must be done after appendScopeNote to be considered in the extent 442 // of the scope. 443 if (!deadZoneFrameSlotRange(bce, firstFrameSlot, frameSlotEnd())) { 444 return false; 445 } 446 447 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 448 MOZ_ASSERT_IF(blockKind_ != BlockKind::Other, kind == ScopeKind::Lexical); 449 MOZ_ASSERT_IF(kind != ScopeKind::Lexical, blockKind_ == BlockKind::Other); 450 451 blockKind_ = blockKind; 452 453 if (!prepareForDisposableScopeBody(bce)) { 454 return false; 455 } 456 #endif 457 458 return checkEnvironmentChainLength(bce); 459 } 460 461 bool EmitterScope::enterClassBody(BytecodeEmitter* bce, ScopeKind kind, 462 ClassBodyScope::ParserData* bindings) { 463 MOZ_ASSERT(kind == ScopeKind::ClassBody); 464 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); 465 466 if (!ensureCache(bce)) { 467 return false; 468 } 469 470 // Resolve bindings. 471 TDZCheckCache* tdzCache = bce->innermostTDZCheckCache; 472 uint32_t firstFrameSlot = frameSlotStart(); 473 ParserBindingIter bi(*bindings, firstFrameSlot); 474 for (; bi; bi++) { 475 if (!checkSlotLimits(bce, bi)) { 476 return false; 477 } 478 479 NameLocation loc = bi.nameLocation(); 480 if (!putNameInCache(bce, bi.name(), loc)) { 481 return false; 482 } 483 484 if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ)) { 485 return false; 486 } 487 } 488 489 updateFrameFixedSlots(bce, bi); 490 491 ScopeIndex scopeIndex; 492 if (!ScopeStencil::createForClassBodyScope( 493 bce->fc, bce->compilationState, kind, bindings, firstFrameSlot, 494 enclosingScopeIndex(bce), &scopeIndex)) { 495 return false; 496 } 497 if (!internScopeStencil(bce, scopeIndex)) { 498 return false; 499 } 500 501 if (ScopeKindIsInBody(kind) && hasEnvironment()) { 502 // After interning the VM scope we can get the scope index. 503 // 504 // ClassBody uses PushClassBodyEnv, however, PopLexicalEnv supports both 505 // cases and doesn't need extra specialization. 506 if (!bce->emitInternedScopeOp(index(), JSOp::PushClassBodyEnv)) { 507 return false; 508 } 509 } 510 511 // Lexical scopes need notes to be mapped from a pc. 512 if (!appendScopeNote(bce)) { 513 return false; 514 } 515 516 return checkEnvironmentChainLength(bce); 517 } 518 519 bool EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox) { 520 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); 521 MOZ_ASSERT(funbox->namedLambdaBindings()); 522 523 if (!ensureCache(bce)) { 524 return false; 525 } 526 527 ParserBindingIter bi(*funbox->namedLambdaBindings(), LOCALNO_LIMIT, 528 /* isNamedLambda = */ true); 529 MOZ_ASSERT(bi.kind() == BindingKind::NamedLambdaCallee); 530 531 // The lambda name, if not closed over, is accessed via JSOp::Callee and 532 // not a frame slot. Do not update frame slot information. 533 NameLocation loc = bi.nameLocation(); 534 if (!putNameInCache(bce, bi.name(), loc)) { 535 return false; 536 } 537 538 bi++; 539 MOZ_ASSERT(!bi, "There should be exactly one binding in a NamedLambda scope"); 540 541 ScopeKind scopeKind = 542 funbox->strict() ? ScopeKind::StrictNamedLambda : ScopeKind::NamedLambda; 543 544 ScopeIndex scopeIndex; 545 if (!ScopeStencil::createForLexicalScope( 546 bce->fc, bce->compilationState, scopeKind, 547 funbox->namedLambdaBindings(), LOCALNO_LIMIT, 548 enclosingScopeIndex(bce), &scopeIndex)) { 549 return false; 550 } 551 if (!internScopeStencil(bce, scopeIndex)) { 552 return false; 553 } 554 555 return checkEnvironmentChainLength(bce); 556 } 557 558 bool EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox) { 559 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); 560 561 // If there are parameter expressions, there is an extra var scope. 562 if (!funbox->functionHasExtraBodyVarScope()) { 563 bce->setVarEmitterScope(this); 564 } 565 566 if (!ensureCache(bce)) { 567 return false; 568 } 569 570 // Resolve body-level bindings, if there are any. 571 auto bindings = funbox->functionScopeBindings(); 572 if (bindings) { 573 NameLocationMap& cache = *nameCache_; 574 575 ParserBindingIter bi(*bindings, funbox->hasParameterExprs); 576 for (; bi; bi++) { 577 if (!checkSlotLimits(bce, bi)) { 578 return false; 579 } 580 581 NameLocation loc = bi.nameLocation(); 582 NameLocationMap::AddPtr p = cache.lookupForAdd(bi.name()); 583 584 // The only duplicate bindings that occur are simple formal 585 // parameters, in which case the last position counts, so update the 586 // location. 587 if (p) { 588 MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter); 589 MOZ_ASSERT(!funbox->hasDestructuringArgs); 590 MOZ_ASSERT(!funbox->hasRest()); 591 p->value() = loc; 592 continue; 593 } 594 595 if (!cache.add(p, bi.name(), loc)) { 596 ReportOutOfMemory(bce->fc); 597 return false; 598 } 599 } 600 601 updateFrameFixedSlots(bce, bi); 602 } else { 603 nextFrameSlot_ = 0; 604 } 605 606 // If the function's scope may be extended at runtime due to sloppy direct 607 // eval, any names beyond the function scope must be accessed dynamically as 608 // we don't know if the name will become a 'var' binding due to direct eval. 609 if (funbox->funHasExtensibleScope()) { 610 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic()); 611 } else if (funbox->isStandalone) { 612 // If the function is standalone, the enclosing scope is either an empty 613 // global or non-syntactic scope, and there's no static bindings. 614 if (bce->compilationState.input.target == 615 CompilationInput::CompilationTarget:: 616 StandaloneFunctionInNonSyntacticScope) { 617 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic()); 618 } else { 619 fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var)); 620 } 621 } 622 623 // In case of parameter expressions, the parameters are lexical 624 // bindings and have TDZ. 625 if (funbox->hasParameterExprs && nextFrameSlot_) { 626 uint32_t paramFrameSlotEnd = 0; 627 for (ParserBindingIter bi(*bindings, true); bi; bi++) { 628 if (!BindingKindIsLexical(bi.kind())) { 629 break; 630 } 631 632 NameLocation loc = bi.nameLocation(); 633 if (loc.kind() == NameLocation::Kind::FrameSlot) { 634 MOZ_ASSERT(paramFrameSlotEnd <= loc.frameSlot()); 635 paramFrameSlotEnd = loc.frameSlot() + 1; 636 } 637 } 638 639 if (!deadZoneFrameSlotRange(bce, 0, paramFrameSlotEnd)) { 640 return false; 641 } 642 } 643 644 ScopeIndex scopeIndex; 645 if (!ScopeStencil::createForFunctionScope( 646 bce->fc, bce->compilationState, funbox->functionScopeBindings(), 647 funbox->hasParameterExprs, 648 funbox->needsCallObjectRegardlessOfBindings(), funbox->index(), 649 funbox->isArrow(), enclosingScopeIndex(bce), &scopeIndex)) { 650 return false; 651 } 652 if (!internBodyScopeStencil(bce, scopeIndex)) { 653 return false; 654 } 655 656 return checkEnvironmentChainLength(bce); 657 } 658 659 bool EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, 660 FunctionBox* funbox) { 661 MOZ_ASSERT(funbox->hasParameterExprs); 662 MOZ_ASSERT(funbox->extraVarScopeBindings() || 663 funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings()); 664 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); 665 666 // The extra var scope is never popped once it's entered. It replaces the 667 // function scope as the var emitter scope. 668 bce->setVarEmitterScope(this); 669 670 if (!ensureCache(bce)) { 671 return false; 672 } 673 674 // Resolve body-level bindings, if there are any. 675 uint32_t firstFrameSlot = frameSlotStart(); 676 if (auto bindings = funbox->extraVarScopeBindings()) { 677 ParserBindingIter bi(*bindings, firstFrameSlot); 678 for (; bi; bi++) { 679 if (!checkSlotLimits(bce, bi)) { 680 return false; 681 } 682 683 NameLocation loc = bi.nameLocation(); 684 MOZ_ASSERT(bi.kind() == BindingKind::Var); 685 if (!putNameInCache(bce, bi.name(), loc)) { 686 return false; 687 } 688 } 689 690 uint32_t priorEnd = bce->maxFixedSlots; 691 updateFrameFixedSlots(bce, bi); 692 693 // If any of the bound slots were previously used, reset them to undefined. 694 // This doesn't break TDZ for let/const/class bindings because there aren't 695 // any in extra body var scopes. We assert above that bi.kind() is Var. 696 uint32_t end = std::min(priorEnd, nextFrameSlot_); 697 if (firstFrameSlot < end) { 698 if (!clearFrameSlotRange(bce, JSOp::Undefined, firstFrameSlot, end)) { 699 return false; 700 } 701 } 702 } else { 703 nextFrameSlot_ = firstFrameSlot; 704 } 705 706 // If the extra var scope may be extended at runtime due to sloppy 707 // direct eval, any names beyond the var scope must be accessed 708 // dynamically as we don't know if the name will become a 'var' binding 709 // due to direct eval. 710 if (funbox->funHasExtensibleScope()) { 711 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic()); 712 } 713 714 // Create and intern the VM scope. 715 ScopeIndex scopeIndex; 716 if (!ScopeStencil::createForVarScope( 717 bce->fc, bce->compilationState, ScopeKind::FunctionBodyVar, 718 funbox->extraVarScopeBindings(), firstFrameSlot, 719 funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings(), 720 enclosingScopeIndex(bce), &scopeIndex)) { 721 return false; 722 } 723 if (!internScopeStencil(bce, scopeIndex)) { 724 return false; 725 } 726 727 if (hasEnvironment()) { 728 if (!bce->emitInternedScopeOp(index(), JSOp::PushVarEnv)) { 729 return false; 730 } 731 } 732 733 // The extra var scope needs a note to be mapped from a pc. 734 if (!appendScopeNote(bce)) { 735 return false; 736 } 737 738 return checkEnvironmentChainLength(bce); 739 } 740 741 bool EmitterScope::enterGlobal(BytecodeEmitter* bce, 742 GlobalSharedContext* globalsc) { 743 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); 744 745 // TODO-Stencil 746 // This is another snapshot-sensitive location. 747 // The incoming atoms from the global scope object should be snapshotted. 748 // For now, converting them to ParserAtoms here individually. 749 750 bce->setVarEmitterScope(this); 751 752 if (!ensureCache(bce)) { 753 return false; 754 } 755 756 if (bce->emitterMode == BytecodeEmitter::SelfHosting) { 757 // In self-hosting, it is incorrect to consult the global scope because 758 // self-hosted scripts are cloned into their target compartments before 759 // they are run. Instead of Global, Intrinsic is used for all names. 760 // 761 // Intrinsic lookups are redirected to the special intrinsics holder 762 // in the global object, into which any missing values are cloned 763 // lazily upon first access. 764 fallbackFreeNameLocation_ = Some(NameLocation::Intrinsic()); 765 766 return internEmptyGlobalScopeAsBody(bce); 767 } 768 769 ScopeIndex scopeIndex; 770 if (!ScopeStencil::createForGlobalScope(bce->fc, bce->compilationState, 771 globalsc->scopeKind(), 772 globalsc->bindings, &scopeIndex)) { 773 return false; 774 } 775 if (!internBodyScopeStencil(bce, scopeIndex)) { 776 return false; 777 } 778 779 // See: JSScript::outermostScope. 780 MOZ_ASSERT(bce->bodyScopeIndex == GCThingIndex::outermostScopeIndex(), 781 "Global scope must be index 0"); 782 783 // Resolve binding names. 784 // 785 // NOTE: BytecodeEmitter::emitDeclarationInstantiation will emit the 786 // redeclaration check and initialize these bindings. 787 if (globalsc->bindings) { 788 for (ParserBindingIter bi(*globalsc->bindings); bi; bi++) { 789 NameLocation loc = bi.nameLocation(); 790 if (!putNameInCache(bce, bi.name(), loc)) { 791 return false; 792 } 793 } 794 } 795 796 // Note that to save space, we don't add free names to the cache for 797 // global scopes. They are assumed to be global vars in the syntactic 798 // global scope, dynamic accesses under non-syntactic global scope. 799 if (globalsc->scopeKind() == ScopeKind::Global) { 800 fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var)); 801 } else { 802 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic()); 803 } 804 805 return true; 806 } 807 808 bool EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc) { 809 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); 810 811 bce->setVarEmitterScope(this); 812 813 if (!ensureCache(bce)) { 814 return false; 815 } 816 817 // Create the `var` scope. Note that there is also a lexical scope, created 818 // separately in emitScript(). 819 ScopeKind scopeKind = 820 evalsc->strict() ? ScopeKind::StrictEval : ScopeKind::Eval; 821 822 ScopeIndex scopeIndex; 823 if (!ScopeStencil::createForEvalScope( 824 bce->fc, bce->compilationState, scopeKind, evalsc->bindings, 825 enclosingScopeIndex(bce), &scopeIndex)) { 826 return false; 827 } 828 if (!internBodyScopeStencil(bce, scopeIndex)) { 829 return false; 830 } 831 832 if (evalsc->strict()) { 833 if (evalsc->bindings) { 834 ParserBindingIter bi(*evalsc->bindings, true); 835 for (; bi; bi++) { 836 if (!checkSlotLimits(bce, bi)) { 837 return false; 838 } 839 840 NameLocation loc = bi.nameLocation(); 841 if (!putNameInCache(bce, bi.name(), loc)) { 842 return false; 843 } 844 } 845 846 updateFrameFixedSlots(bce, bi); 847 } 848 } else { 849 // For simplicity, treat all free name lookups in nonstrict eval scripts as 850 // dynamic. 851 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic()); 852 } 853 854 if (hasEnvironment()) { 855 if (!bce->emitInternedScopeOp(index(), JSOp::PushVarEnv)) { 856 return false; 857 } 858 } else { 859 // NOTE: BytecodeEmitter::emitDeclarationInstantiation will emit the 860 // redeclaration check and initialize these bindings for sloppy 861 // eval. 862 863 // As an optimization, if the eval does not have its own var 864 // environment and is directly enclosed in a global scope, then all 865 // free name lookups are global. 866 if (scope(bce).enclosing().is<GlobalScope>()) { 867 fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var)); 868 } 869 } 870 871 return checkEnvironmentChainLength(bce); 872 } 873 874 bool EmitterScope::enterModule(BytecodeEmitter* bce, 875 ModuleSharedContext* modulesc) { 876 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); 877 878 bce->setVarEmitterScope(this); 879 880 if (!ensureCache(bce)) { 881 return false; 882 } 883 884 // Resolve body-level bindings, if there are any. 885 TDZCheckCache* tdzCache = bce->innermostTDZCheckCache; 886 Maybe<uint32_t> firstLexicalFrameSlot; 887 if (ModuleScope::ParserData* bindings = modulesc->bindings) { 888 ParserBindingIter bi(*bindings); 889 for (; bi; bi++) { 890 if (!checkSlotLimits(bce, bi)) { 891 return false; 892 } 893 894 NameLocation loc = bi.nameLocation(); 895 if (!putNameInCache(bce, bi.name(), loc)) { 896 return false; 897 } 898 899 if (BindingKindIsLexical(bi.kind())) { 900 if (loc.kind() == NameLocation::Kind::FrameSlot && 901 !firstLexicalFrameSlot) { 902 firstLexicalFrameSlot = Some(loc.frameSlot()); 903 } 904 905 if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ)) { 906 return false; 907 } 908 } 909 910 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 911 if (bi.kind() == BindingKind::Using) { 912 setHasDisposables(bce); 913 } 914 #endif 915 } 916 917 updateFrameFixedSlots(bce, bi); 918 } else { 919 nextFrameSlot_ = 0; 920 } 921 922 // Modules are toplevel, so any free names are global. 923 fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var)); 924 925 // Put lexical frame slots in TDZ. Environment slots are poisoned during 926 // environment creation. 927 if (firstLexicalFrameSlot) { 928 if (!deadZoneFrameSlotRange(bce, *firstLexicalFrameSlot, frameSlotEnd())) { 929 return false; 930 } 931 } 932 933 // Create and intern the VM scope creation data. 934 ScopeIndex scopeIndex; 935 if (!ScopeStencil::createForModuleScope( 936 bce->fc, bce->compilationState, modulesc->bindings, 937 enclosingScopeIndex(bce), &scopeIndex)) { 938 return false; 939 } 940 if (!internBodyScopeStencil(bce, scopeIndex)) { 941 return false; 942 } 943 944 return checkEnvironmentChainLength(bce); 945 } 946 947 bool EmitterScope::enterWith(BytecodeEmitter* bce) { 948 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck()); 949 950 if (!ensureCache(bce)) { 951 return false; 952 } 953 954 // 'with' make all accesses dynamic and unanalyzable. 955 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic()); 956 957 ScopeIndex scopeIndex; 958 if (!ScopeStencil::createForWithScope(bce->fc, bce->compilationState, 959 enclosingScopeIndex(bce), 960 &scopeIndex)) { 961 return false; 962 } 963 964 if (!internScopeStencil(bce, scopeIndex)) { 965 return false; 966 } 967 968 if (!bce->emitInternedScopeOp(index(), JSOp::EnterWith)) { 969 return false; 970 } 971 972 if (!appendScopeNote(bce)) { 973 return false; 974 } 975 976 return checkEnvironmentChainLength(bce); 977 } 978 979 bool EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce) const { 980 return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd()); 981 } 982 983 bool EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal) { 984 // If we aren't leaving the scope due to a non-local jump (e.g., break), 985 // we must be the innermost scope. 986 MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck()); 987 988 ScopeKind kind = scope(bce).kind(); 989 switch (kind) { 990 case ScopeKind::Lexical: 991 case ScopeKind::SimpleCatch: 992 case ScopeKind::Catch: 993 case ScopeKind::FunctionLexical: 994 case ScopeKind::ClassBody: 995 996 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 997 if (!nonLocal) { 998 if (!emitDisposableScopeBodyEnd(bce)) { 999 return false; 1000 } 1001 } 1002 #endif 1003 1004 if (bce->sc->isFunctionBox() && 1005 bce->sc->asFunctionBox()->needsClearSlotsOnExit()) { 1006 if (!deadZoneFrameSlots(bce)) { 1007 return false; 1008 } 1009 } 1010 1011 if (!bce->emit1(hasEnvironment() ? JSOp::PopLexicalEnv 1012 : JSOp::DebugLeaveLexicalEnv)) { 1013 return false; 1014 } 1015 break; 1016 1017 case ScopeKind::With: 1018 if (!bce->emit1(JSOp::LeaveWith)) { 1019 return false; 1020 } 1021 break; 1022 1023 case ScopeKind::Function: 1024 case ScopeKind::FunctionBodyVar: 1025 case ScopeKind::NamedLambda: 1026 case ScopeKind::StrictNamedLambda: 1027 case ScopeKind::Eval: 1028 case ScopeKind::StrictEval: 1029 case ScopeKind::Global: 1030 case ScopeKind::NonSyntactic: 1031 case ScopeKind::Module: 1032 break; 1033 1034 case ScopeKind::WasmInstance: 1035 case ScopeKind::WasmFunction: 1036 MOZ_CRASH("No wasm function scopes in JS"); 1037 } 1038 1039 // Finish up the scope if we are leaving it in LIFO fashion. 1040 if (!nonLocal) { 1041 // Popping scopes due to non-local jumps generate additional scope 1042 // notes. See NonLocalExitControl::prepareForNonLocalJump. 1043 if (ScopeKindIsInBody(kind)) { 1044 if (kind == ScopeKind::FunctionBodyVar) { 1045 // The extra function var scope is never popped once it's pushed, 1046 // so its scope note extends until the end of any possible code. 1047 bce->bytecodeSection().scopeNoteList().recordEndFunctionBodyVar( 1048 noteIndex_); 1049 } else { 1050 bce->bytecodeSection().scopeNoteList().recordEnd( 1051 noteIndex_, bce->bytecodeSection().offset()); 1052 } 1053 } 1054 } 1055 1056 return true; 1057 } 1058 1059 AbstractScopePtr EmitterScope::scope(const BytecodeEmitter* bce) const { 1060 return bce->perScriptData().gcThingList().getScope(index()); 1061 } 1062 1063 mozilla::Maybe<ScopeIndex> EmitterScope::scopeIndex( 1064 const BytecodeEmitter* bce) const { 1065 return bce->perScriptData().gcThingList().getScopeIndex(index()); 1066 } 1067 1068 NameLocation EmitterScope::lookup(BytecodeEmitter* bce, 1069 TaggedParserAtomIndex name) { 1070 if (Maybe<NameLocation> loc = lookupInCache(bce, name)) { 1071 return *loc; 1072 } 1073 return searchAndCache(bce, name); 1074 } 1075 1076 /* static */ 1077 uint32_t EmitterScope::CountEnclosingCompilationEnvironments( 1078 BytecodeEmitter* bce, EmitterScope* emitterScope) { 1079 uint32_t environments = emitterScope->hasEnvironment() ? 1 : 0; 1080 while ((emitterScope = emitterScope->enclosing(&bce))) { 1081 if (emitterScope->hasEnvironment()) { 1082 environments++; 1083 } 1084 } 1085 return environments; 1086 } 1087 1088 void EmitterScope::lookupPrivate(BytecodeEmitter* bce, 1089 TaggedParserAtomIndex name, NameLocation& loc, 1090 mozilla::Maybe<NameLocation>& brandLoc) { 1091 loc = lookup(bce, name); 1092 1093 // Private Brand checking relies on the ability to construct a new 1094 // environment coordinate for a name at a fixed offset, which will 1095 // correspond to the private brand for that class. 1096 // 1097 // If our name lookup isn't a fixed location, we must construct a 1098 // new environment coordinate, using information available from our private 1099 // field cache. (See cachePrivateFieldsForEval, and Bug 1638309). 1100 // 1101 // This typically involves a DebugEnvironmentProxy, so we need to use a 1102 // DebugEnvironmentCoordinate. 1103 // 1104 // See also Bug 793345 which argues that we should remove the 1105 // DebugEnvironmentProxy. 1106 if (loc.kind() != NameLocation::Kind::EnvironmentCoordinate && 1107 loc.kind() != NameLocation::Kind::FrameSlot) { 1108 MOZ_ASSERT(loc.kind() == NameLocation::Kind::Dynamic || 1109 loc.kind() == NameLocation::Kind::Global); 1110 // Private fields don't require brand checking and can be correctly 1111 // code-generated with dynamic name lookup bytecode we have today. However, 1112 // for that to happen we first need to figure out if we have a Private 1113 // method or private field, which we cannot disambiguate based on the 1114 // dynamic lookup. 1115 // 1116 // However, this is precisely the case that the private field eval case can 1117 // help us handle. It knows the truth about these private bindings. 1118 mozilla::Maybe<NameLocation> cacheEntry = 1119 bce->compilationState.scopeContext.getPrivateFieldLocation(name); 1120 MOZ_ASSERT(cacheEntry); 1121 1122 if (cacheEntry->bindingKind() == BindingKind::PrivateMethod) { 1123 MOZ_ASSERT(cacheEntry->kind() == 1124 NameLocation::Kind::DebugEnvironmentCoordinate); 1125 // To construct the brand check there are two hop values required: 1126 // 1127 // 1. Compilation Hops: The number of environment hops required to get to 1128 // the compilation enclosing environment. 1129 // 2. "external hops", to get from compilation enclosing debug environment 1130 // to the environment that actually contains our brand. This is 1131 // determined by the cacheEntry. This traversal will bypass a Debug 1132 // environment proxy, which is why need to use 1133 // DebugEnvironmentCoordinate. 1134 1135 uint32_t compilation_hops = 1136 CountEnclosingCompilationEnvironments(bce, this); 1137 1138 uint32_t external_hops = cacheEntry->environmentCoordinate().hops(); 1139 1140 brandLoc = Some(NameLocation::DebugEnvironmentCoordinate( 1141 BindingKind::Synthetic, compilation_hops + external_hops, 1142 ClassBodyLexicalEnvironmentObject::privateBrandSlot())); 1143 } else { 1144 brandLoc = Nothing(); 1145 } 1146 return; 1147 } 1148 1149 if (loc.bindingKind() == BindingKind::PrivateMethod) { 1150 uint32_t hops = 0; 1151 if (loc.kind() == NameLocation::Kind::EnvironmentCoordinate) { 1152 hops = loc.environmentCoordinate().hops(); 1153 } else { 1154 // If we have a FrameSlot, then our innermost emitter scope must be a 1155 // class body scope, and we can generate an environment coordinate with 1156 // hops=0 to find the associated brand location. 1157 MOZ_ASSERT(bce->innermostScope().is<ClassBodyScope>()); 1158 } 1159 1160 brandLoc = Some(NameLocation::EnvironmentCoordinate( 1161 BindingKind::Synthetic, hops, 1162 ClassBodyLexicalEnvironmentObject::privateBrandSlot())); 1163 } else { 1164 brandLoc = Nothing(); 1165 } 1166 } 1167 1168 Maybe<NameLocation> EmitterScope::locationBoundInScope( 1169 TaggedParserAtomIndex name, EmitterScope* target) { 1170 // The target scope must be an intra-frame enclosing scope of this 1171 // one. Count the number of extra hops to reach it. 1172 uint16_t extraHops = 0; 1173 for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) { 1174 if (es->hasEnvironment()) { 1175 extraHops++; 1176 } 1177 } 1178 1179 // Caches are prepopulated with bound names. So if the name is bound in a 1180 // particular scope, it must already be in the cache. Furthermore, don't 1181 // consult the fallback location as we only care about binding names. 1182 Maybe<NameLocation> loc; 1183 if (NameLocationMap::Ptr p = target->nameCache_->lookup(name)) { 1184 NameLocation l = p->value().wrapped; 1185 if (l.kind() == NameLocation::Kind::EnvironmentCoordinate) { 1186 loc = Some(l.addHops(extraHops)); 1187 } else { 1188 loc = Some(l); 1189 } 1190 } 1191 return loc; 1192 }