Scope.cpp (60276B)
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 "vm/Scope.h" 8 9 #include <new> 10 11 #include "jsnum.h" 12 13 #include "frontend/CompilationStencil.h" // ScopeStencilRef, CompilationStencil, CompilationState, CompilationAtomCache 14 #include "frontend/ParserAtom.h" // frontend::ParserAtomsTable, frontend::ParserAtom 15 #include "frontend/ScriptIndex.h" // ScriptIndex 16 #include "frontend/Stencil.h" 17 #include "util/StringBuilder.h" 18 #include "vm/EnvironmentObject.h" 19 #include "vm/ErrorReporting.h" // MaybePrintAndClearPendingException 20 #include "vm/JSScript.h" 21 #include "wasm/WasmDebug.h" 22 #include "wasm/WasmInstance.h" 23 24 #include "gc/BufferAllocator-inl.h" 25 #include "gc/GCContext-inl.h" 26 #include "gc/ObjectKind-inl.h" 27 #include "gc/TraceMethods-inl.h" 28 #include "vm/JSContext-inl.h" 29 #include "wasm/WasmInstance-inl.h" 30 31 using namespace js; 32 using namespace js::frontend; 33 34 const char* js::BindingKindString(BindingKind kind) { 35 switch (kind) { 36 case BindingKind::Import: 37 return "import"; 38 case BindingKind::FormalParameter: 39 return "formal parameter"; 40 case BindingKind::Var: 41 return "var"; 42 case BindingKind::Let: 43 return "let"; 44 case BindingKind::Const: 45 return "const"; 46 case BindingKind::NamedLambdaCallee: 47 return "named lambda callee"; 48 case BindingKind::Synthetic: 49 return "synthetic"; 50 case BindingKind::PrivateMethod: 51 return "private method"; 52 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 53 case BindingKind::Using: 54 return "using"; 55 #endif 56 } 57 MOZ_CRASH("Bad BindingKind"); 58 } 59 60 const char* js::ScopeKindString(ScopeKind kind) { 61 switch (kind) { 62 case ScopeKind::Function: 63 return "function"; 64 case ScopeKind::FunctionBodyVar: 65 return "function body var"; 66 case ScopeKind::Lexical: 67 return "lexical"; 68 case ScopeKind::SimpleCatch: 69 case ScopeKind::Catch: 70 return "catch"; 71 case ScopeKind::NamedLambda: 72 return "named lambda"; 73 case ScopeKind::StrictNamedLambda: 74 return "strict named lambda"; 75 case ScopeKind::FunctionLexical: 76 return "function lexical"; 77 case ScopeKind::ClassBody: 78 return "class body"; 79 case ScopeKind::With: 80 return "with"; 81 case ScopeKind::Eval: 82 return "eval"; 83 case ScopeKind::StrictEval: 84 return "strict eval"; 85 case ScopeKind::Global: 86 return "global"; 87 case ScopeKind::NonSyntactic: 88 return "non-syntactic"; 89 case ScopeKind::Module: 90 return "module"; 91 case ScopeKind::WasmInstance: 92 return "wasm instance"; 93 case ScopeKind::WasmFunction: 94 return "wasm function"; 95 } 96 MOZ_CRASH("Bad ScopeKind"); 97 } 98 99 SharedShape* js::EmptyEnvironmentShape(JSContext* cx, const JSClass* cls, 100 uint32_t numSlots, 101 ObjectFlags objectFlags) { 102 // Put as many slots into the object header as possible. 103 uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots)); 104 return SharedShape::getInitialShape( 105 cx, cls, cx->realm(), TaggedProto(nullptr), numFixed, objectFlags); 106 } 107 108 static bool AddToEnvironmentMap(JSContext* cx, const JSClass* clasp, 109 HandleId id, BindingKind bindKind, 110 uint32_t slot, 111 MutableHandle<SharedPropMap*> map, 112 uint32_t* mapLength, ObjectFlags* objectFlags) { 113 PropertyFlags propFlags = {PropertyFlag::Enumerable}; 114 switch (bindKind) { 115 case BindingKind::Const: 116 case BindingKind::NamedLambdaCallee: 117 // Non-writable. 118 break; 119 default: 120 propFlags.setFlag(PropertyFlag::Writable); 121 break; 122 } 123 124 return SharedPropMap::addPropertyWithKnownSlot(cx, clasp, map, mapLength, id, 125 propFlags, slot, objectFlags); 126 } 127 128 SharedShape* js::CreateEnvironmentShape(JSContext* cx, BindingIter& bi, 129 const JSClass* cls, uint32_t numSlots, 130 ObjectFlags objectFlags) { 131 Rooted<SharedPropMap*> map(cx); 132 uint32_t mapLength = 0; 133 134 RootedId id(cx); 135 for (; bi; bi++) { 136 BindingLocation loc = bi.location(); 137 if (loc.kind() == BindingLocation::Kind::Environment) { 138 JSAtom* name = bi.name(); 139 MOZ_ASSERT(AtomIsMarked(cx->zone(), name)); 140 id = NameToId(name->asPropertyName()); 141 if (!AddToEnvironmentMap(cx, cls, id, bi.kind(), loc.slot(), &map, 142 &mapLength, &objectFlags)) { 143 return nullptr; 144 } 145 } 146 } 147 148 uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots)); 149 return SharedShape::getInitialOrPropMapShape(cx, cls, cx->realm(), 150 TaggedProto(nullptr), numFixed, 151 map, mapLength, objectFlags); 152 } 153 154 SharedShape* js::CreateEnvironmentShapeForSyntheticModule( 155 JSContext* cx, const JSClass* cls, uint32_t numSlots, 156 Handle<ModuleObject*> module) { 157 Rooted<SharedPropMap*> map(cx); 158 uint32_t mapLength = 0; 159 160 PropertyFlags propFlags = {PropertyFlag::Enumerable}; 161 ObjectFlags objectFlags = ModuleEnvironmentObject::OBJECT_FLAGS; 162 163 RootedId id(cx); 164 uint32_t slotIndex = numSlots; 165 for (JSAtom* exportName : module->syntheticExportNames()) { 166 id = NameToId(exportName->asPropertyName()); 167 if (!SharedPropMap::addPropertyWithKnownSlot(cx, cls, &map, &mapLength, id, 168 propFlags, slotIndex, 169 &objectFlags)) { 170 return nullptr; 171 } 172 slotIndex++; 173 } 174 175 uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots)); 176 return SharedShape::getInitialOrPropMapShape(cx, cls, cx->realm(), 177 TaggedProto(nullptr), numFixed, 178 map, mapLength, objectFlags); 179 } 180 181 template <class DataT> 182 inline size_t SizeOfAllocatedData(DataT* data) { 183 return SizeOfScopeData<DataT>(data->length); 184 } 185 186 template <typename ConcreteScope> 187 static void MarkParserScopeData(typename ConcreteScope::ParserData* data, 188 frontend::CompilationState& compilationState) { 189 auto names = GetScopeDataTrailingNames(data); 190 for (auto& binding : names) { 191 auto index = binding.name(); 192 if (!index) { 193 continue; 194 } 195 compilationState.parserAtoms.markUsedByStencil( 196 index, frontend::ParserAtom::Atomize::Yes); 197 } 198 } 199 200 template <typename ConcreteScope, typename EnvironmentT> 201 static void PrepareScopeData(ParserBindingIter& bi, 202 typename ConcreteScope::ParserData* data, 203 uint32_t firstFrameSlot, 204 mozilla::Maybe<uint32_t>* envShape) { 205 const JSClass* cls = &EnvironmentT::class_; 206 207 // Iterate through all bindings. This counts the number of environment 208 // slots needed and computes the maximum frame slot. 209 while (bi) { 210 bi++; 211 } 212 data->slotInfo.nextFrameSlot = 213 bi.canHaveFrameSlots() ? bi.nextFrameSlot() : LOCALNO_LIMIT; 214 215 // Make a new environment shape if any environment slots were used. 216 if (bi.nextEnvironmentSlot() != JSSLOT_FREE(cls)) { 217 envShape->emplace(bi.nextEnvironmentSlot()); 218 } 219 } 220 221 template <typename ConcreteScope> 222 static typename ConcreteScope::ParserData* NewEmptyParserScopeData( 223 FrontendContext* fc, LifoAlloc& alloc, uint32_t length = 0) { 224 using Data = typename ConcreteScope::ParserData; 225 226 size_t dataSize = SizeOfScopeData<Data>(length); 227 void* raw = alloc.alloc(dataSize); 228 if (!raw) { 229 js::ReportOutOfMemory(fc); 230 return nullptr; 231 } 232 233 return new (raw) Data(length); 234 } 235 236 template <typename ConcreteScope> 237 static typename ConcreteScope::RuntimeData* NewEmptyScopeData( 238 JSContext* cx, uint32_t length = 0) { 239 using Data = typename ConcreteScope::RuntimeData; 240 241 size_t dataSize = SizeOfScopeData<Data>(length); 242 Data* data = gc::NewBuffer<Data>(cx->zone(), dataSize, false, length); 243 if (!data) { 244 ReportOutOfMemory(cx); 245 return nullptr; 246 } 247 248 return data; 249 } 250 251 template <typename ConcreteScope> 252 static typename ConcreteScope::RuntimeData* LiftParserScopeData( 253 JSContext* cx, frontend::CompilationAtomCache& atomCache, 254 BaseParserScopeData* baseData) { 255 using ConcreteData = typename ConcreteScope::RuntimeData; 256 257 auto* data = static_cast<typename ConcreteScope::ParserData*>(baseData); 258 259 // Convert all scope ParserAtoms to rooted JSAtoms. 260 // Rooting is necessary as conversion can gc. 261 JS::RootedVector<JSAtom*> jsatoms(cx); 262 if (!jsatoms.reserve(data->length)) { 263 return nullptr; 264 } 265 auto names = GetScopeDataTrailingNames(data); 266 for (size_t i = 0; i < names.size(); i++) { 267 JSAtom* jsatom = nullptr; 268 if (names[i].name()) { 269 jsatom = atomCache.getExistingAtomAt(cx, names[i].name()); 270 MOZ_ASSERT(jsatom); 271 } 272 jsatoms.infallibleAppend(jsatom); 273 } 274 275 // Allocate a new scope-data of the right kind. 276 ConcreteData* scopeData = NewEmptyScopeData<ConcreteScope>(cx, data->length); 277 if (!scopeData) { 278 return nullptr; 279 } 280 281 // NOTE: There shouldn't be any fallible operation or GC between setting 282 // `length` and filling `trailingNames`. 283 scopeData->length = data->length; 284 285 memcpy(&scopeData->slotInfo, &data->slotInfo, 286 sizeof(typename ConcreteScope::SlotInfo)); 287 288 // Initialize new scoped names. 289 auto namesOut = GetScopeDataTrailingNames(scopeData); 290 MOZ_ASSERT(data->length == namesOut.size()); 291 for (size_t i = 0; i < namesOut.size(); i++) { 292 namesOut[i] = names[i].copyWithNewAtom(jsatoms[i].get()); 293 } 294 295 return scopeData; 296 } 297 298 /* static */ 299 Scope* Scope::create(JSContext* cx, ScopeKind kind, Handle<Scope*> enclosing, 300 Handle<SharedShape*> envShape) { 301 return cx->newCell<Scope>(kind, enclosing, envShape); 302 } 303 304 template <typename ConcreteScope> 305 /* static */ 306 ConcreteScope* Scope::create( 307 JSContext* cx, ScopeKind kind, Handle<Scope*> enclosing, 308 Handle<SharedShape*> envShape, 309 HandleBuffer<typename ConcreteScope::RuntimeData> data) { 310 Scope* scope = create(cx, kind, enclosing, envShape); 311 if (!scope) { 312 return nullptr; 313 } 314 315 // It is an invariant that all Scopes that have data (currently, all 316 // ScopeKinds except With) must have non-null data. 317 MOZ_ASSERT(data); 318 scope->initData<ConcreteScope>(data); 319 320 return &scope->as<ConcreteScope>(); 321 } 322 323 template <typename ConcreteScope> 324 inline void Scope::initData( 325 HandleBuffer<typename ConcreteScope::RuntimeData> data) { 326 MOZ_ASSERT(is<ConcreteScope>()); 327 MOZ_ASSERT(!rawData()); 328 329 setHeaderPtr(data); 330 } 331 332 void Scope::updateEnvShapeIfRequired(mozilla::Maybe<uint32_t>* envShape, 333 bool needsEnvironment) { 334 if (envShape->isNothing() && needsEnvironment) { 335 uint32_t numSlots = 0; 336 envShape->emplace(numSlots); 337 } 338 } 339 340 uint32_t Scope::firstFrameSlot() const { 341 switch (kind()) { 342 case ScopeKind::Lexical: 343 case ScopeKind::SimpleCatch: 344 case ScopeKind::Catch: 345 case ScopeKind::FunctionLexical: 346 // For intra-frame scopes, find the enclosing scope's next frame slot. 347 MOZ_ASSERT(is<LexicalScope>()); 348 return LexicalScope::nextFrameSlot(enclosing()); 349 350 case ScopeKind::NamedLambda: 351 case ScopeKind::StrictNamedLambda: 352 // Named lambda scopes cannot have frame slots. 353 return LOCALNO_LIMIT; 354 355 case ScopeKind::ClassBody: 356 MOZ_ASSERT(is<ClassBodyScope>()); 357 return ClassBodyScope::nextFrameSlot(enclosing()); 358 359 case ScopeKind::FunctionBodyVar: 360 if (enclosing()->is<FunctionScope>()) { 361 return enclosing()->as<FunctionScope>().nextFrameSlot(); 362 } 363 break; 364 365 default: 366 break; 367 } 368 return 0; 369 } 370 371 uint32_t Scope::chainLength() const { 372 uint32_t length = 0; 373 for (ScopeIter si(const_cast<Scope*>(this)); si; si++) { 374 length++; 375 } 376 return length; 377 } 378 379 uint32_t Scope::environmentChainLength() const { 380 uint32_t length = 0; 381 for (ScopeIter si(const_cast<Scope*>(this)); si; si++) { 382 if (si.hasSyntacticEnvironment()) { 383 length++; 384 } 385 } 386 return length; 387 } 388 389 size_t Scope::sizeOfExcludingThis() const { 390 if (rawData()) { 391 return gc::GetAllocSize(zone(), rawData()); 392 } 393 return 0; 394 } 395 396 void Scope::dump() { 397 JSContext* cx = TlsContext.get(); 398 if (!cx) { 399 fprintf(stderr, "*** can't get JSContext for current thread\n"); 400 return; 401 } 402 for (Rooted<ScopeIter> si(cx, ScopeIter(this)); si; si++) { 403 fprintf(stderr, "- %s [%p]\n", ScopeKindString(si.kind()), si.scope()); 404 DumpBindings(cx, si.scope()); 405 fprintf(stderr, "\n"); 406 } 407 fprintf(stderr, "\n"); 408 } 409 410 #if defined(DEBUG) || defined(JS_JITSPEW) 411 412 /* static */ 413 bool Scope::dumpForDisassemble(JSContext* cx, JS::Handle<Scope*> scope, 414 GenericPrinter& out, const char* indent) { 415 out.put(ScopeKindString(scope->kind())); 416 out.put(" {"); 417 418 size_t i = 0; 419 for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++, i++) { 420 if (i == 0) { 421 out.put("\n"); 422 } 423 UniqueChars bytes = AtomToPrintableString(cx, bi.name()); 424 if (!bytes) { 425 return false; 426 } 427 out.put(indent); 428 out.printf(" %2zu: %s %s ", i, BindingKindString(bi.kind()), bytes.get()); 429 switch (bi.location().kind()) { 430 case BindingLocation::Kind::Global: 431 if (bi.isTopLevelFunction()) { 432 out.put("(global function)\n"); 433 } else { 434 out.put("(global)\n"); 435 } 436 break; 437 case BindingLocation::Kind::Argument: 438 out.printf("(arg slot %u)\n", bi.location().argumentSlot()); 439 break; 440 case BindingLocation::Kind::Frame: 441 out.printf("(frame slot %u)\n", bi.location().slot()); 442 break; 443 case BindingLocation::Kind::Environment: 444 out.printf("(env slot %u)\n", bi.location().slot()); 445 break; 446 case BindingLocation::Kind::NamedLambdaCallee: 447 out.put("(named lambda callee)\n"); 448 break; 449 case BindingLocation::Kind::Import: 450 out.put("(import)\n"); 451 break; 452 } 453 } 454 if (i > 0) { 455 out.put(indent); 456 } 457 out.put("}"); 458 459 ScopeIter si(scope); 460 si++; 461 for (; si; si++) { 462 out.put(" -> "); 463 out.put(ScopeKindString(si.kind())); 464 } 465 return true; 466 } 467 468 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */ 469 470 static uint32_t NextFrameSlot(Scope* scope) { 471 for (ScopeIter si(scope); si; si++) { 472 switch (si.kind()) { 473 case ScopeKind::With: 474 continue; 475 476 case ScopeKind::Function: 477 return si.scope()->as<FunctionScope>().nextFrameSlot(); 478 479 case ScopeKind::FunctionBodyVar: 480 return si.scope()->as<VarScope>().nextFrameSlot(); 481 482 case ScopeKind::Lexical: 483 case ScopeKind::SimpleCatch: 484 case ScopeKind::Catch: 485 case ScopeKind::FunctionLexical: 486 return si.scope()->as<LexicalScope>().nextFrameSlot(); 487 488 case ScopeKind::ClassBody: 489 return si.scope()->as<ClassBodyScope>().nextFrameSlot(); 490 491 case ScopeKind::NamedLambda: 492 case ScopeKind::StrictNamedLambda: 493 // Named lambda scopes cannot have frame slots. 494 return 0; 495 496 case ScopeKind::Eval: 497 case ScopeKind::StrictEval: 498 return si.scope()->as<EvalScope>().nextFrameSlot(); 499 500 case ScopeKind::Global: 501 case ScopeKind::NonSyntactic: 502 return 0; 503 504 case ScopeKind::Module: 505 return si.scope()->as<ModuleScope>().nextFrameSlot(); 506 507 case ScopeKind::WasmInstance: 508 case ScopeKind::WasmFunction: 509 // Invalid; MOZ_CRASH below. 510 break; 511 } 512 } 513 MOZ_CRASH("Not an enclosing intra-frame Scope"); 514 } 515 516 /* static */ 517 uint32_t LexicalScope::nextFrameSlot(Scope* scope) { 518 return NextFrameSlot(scope); 519 } 520 521 /* static */ 522 uint32_t ClassBodyScope::nextFrameSlot(Scope* scope) { 523 return NextFrameSlot(scope); 524 } 525 526 /* static */ 527 void LexicalScope::prepareForScopeCreation(ScopeKind kind, 528 uint32_t firstFrameSlot, 529 LexicalScope::ParserData* data, 530 mozilla::Maybe<uint32_t>* envShape) { 531 bool isNamedLambda = 532 kind == ScopeKind::NamedLambda || kind == ScopeKind::StrictNamedLambda; 533 534 MOZ_ASSERT_IF(isNamedLambda, firstFrameSlot == LOCALNO_LIMIT); 535 536 ParserBindingIter bi(*data, firstFrameSlot, isNamedLambda); 537 PrepareScopeData<LexicalScope, BlockLexicalEnvironmentObject>( 538 bi, data, firstFrameSlot, envShape); 539 } 540 541 /* static */ 542 SharedShape* LexicalScope::getEmptyExtensibleEnvironmentShape(JSContext* cx) { 543 const JSClass* cls = &LexicalEnvironmentObject::class_; 544 return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), ObjectFlags()); 545 } 546 547 /* static */ 548 void ClassBodyScope::prepareForScopeCreation( 549 ScopeKind kind, uint32_t firstFrameSlot, ClassBodyScope::ParserData* data, 550 mozilla::Maybe<uint32_t>* envShape) { 551 MOZ_ASSERT(kind == ScopeKind::ClassBody); 552 553 ParserBindingIter bi(*data, firstFrameSlot); 554 PrepareScopeData<ClassBodyScope, BlockLexicalEnvironmentObject>( 555 bi, data, firstFrameSlot, envShape); 556 } 557 558 /* static */ 559 void FunctionScope::prepareForScopeCreation( 560 FunctionScope::ParserData* data, bool hasParameterExprs, 561 bool needsEnvironment, mozilla::Maybe<uint32_t>* envShape) { 562 uint32_t firstFrameSlot = 0; 563 ParserBindingIter bi(*data, hasParameterExprs); 564 PrepareScopeData<FunctionScope, CallObject>(bi, data, firstFrameSlot, 565 envShape); 566 567 if (hasParameterExprs) { 568 data->slotInfo.setHasParameterExprs(); 569 } 570 571 // An environment may be needed regardless of existence of any closed over 572 // bindings: 573 // - Extensible scopes (i.e., due to direct eval) 574 // - Needing a home object 575 // - Being a derived class constructor 576 // - Being a generator or async function 577 // Also see |FunctionBox::needsExtraBodyVarEnvironmentRegardlessOfBindings()|. 578 updateEnvShapeIfRequired(envShape, needsEnvironment); 579 } 580 581 JSScript* FunctionScope::script() const { 582 return canonicalFunction()->nonLazyScript(); 583 } 584 585 /* static */ 586 bool FunctionScope::isSpecialName(frontend::TaggedParserAtomIndex name) { 587 return name == frontend::TaggedParserAtomIndex::WellKnown::arguments() || 588 name == frontend::TaggedParserAtomIndex::WellKnown::dot_this_() || 589 name == frontend::TaggedParserAtomIndex::WellKnown::dot_newTarget_() || 590 name == frontend::TaggedParserAtomIndex::WellKnown::dot_generator_(); 591 } 592 593 /* static */ 594 void VarScope::prepareForScopeCreation(ScopeKind kind, 595 VarScope::ParserData* data, 596 uint32_t firstFrameSlot, 597 bool needsEnvironment, 598 mozilla::Maybe<uint32_t>* envShape) { 599 ParserBindingIter bi(*data, firstFrameSlot); 600 PrepareScopeData<VarScope, VarEnvironmentObject>(bi, data, firstFrameSlot, 601 envShape); 602 603 // An environment may be needed regardless of existence of any closed over 604 // bindings: 605 // - Extensible scopes (i.e., due to direct eval) 606 // - Being a generator 607 updateEnvShapeIfRequired(envShape, needsEnvironment); 608 } 609 610 GlobalScope* GlobalScope::createEmpty(JSContext* cx, ScopeKind kind) { 611 RootedBuffer<RuntimeData> data(cx, NewEmptyScopeData<GlobalScope>(cx)); 612 if (!data) { 613 return nullptr; 614 } 615 616 return createWithData(cx, kind, data); 617 } 618 619 /* static */ 620 GlobalScope* GlobalScope::createWithData(JSContext* cx, ScopeKind kind, 621 HandleBuffer<RuntimeData> data) { 622 MOZ_ASSERT(data); 623 624 // The global scope has no environment shape. Its environment is the 625 // global lexical scope and the global object or non-syntactic objects 626 // created by embedding, all of which are not only extensible but may 627 // have names on them deleted. 628 return Scope::create<GlobalScope>(cx, kind, nullptr, nullptr, data); 629 } 630 631 /* static */ 632 WithScope* WithScope::create(JSContext* cx, Handle<Scope*> enclosing) { 633 Scope* scope = Scope::create(cx, ScopeKind::With, enclosing, nullptr); 634 return static_cast<WithScope*>(scope); 635 } 636 637 /* static */ 638 void EvalScope::prepareForScopeCreation(ScopeKind scopeKind, 639 EvalScope::ParserData* data, 640 mozilla::Maybe<uint32_t>* envShape) { 641 if (scopeKind == ScopeKind::StrictEval) { 642 uint32_t firstFrameSlot = 0; 643 ParserBindingIter bi(*data, true); 644 PrepareScopeData<EvalScope, VarEnvironmentObject>(bi, data, firstFrameSlot, 645 envShape); 646 } 647 } 648 649 /* static */ 650 Scope* EvalScope::nearestVarScopeForDirectEval(Scope* scope) { 651 for (ScopeIter si(scope); si; si++) { 652 switch (si.kind()) { 653 case ScopeKind::Function: 654 case ScopeKind::FunctionBodyVar: 655 case ScopeKind::Global: 656 case ScopeKind::NonSyntactic: 657 return scope; 658 default: 659 break; 660 } 661 } 662 return nullptr; 663 } 664 665 ModuleScope::RuntimeData::RuntimeData(size_t length) { 666 PoisonNames(this, length); 667 } 668 669 /* static */ 670 void ModuleScope::prepareForScopeCreation(ModuleScope::ParserData* data, 671 mozilla::Maybe<uint32_t>* envShape) { 672 uint32_t firstFrameSlot = 0; 673 ParserBindingIter bi(*data); 674 PrepareScopeData<ModuleScope, ModuleEnvironmentObject>( 675 bi, data, firstFrameSlot, envShape); 676 677 // Modules always need an environment object for now. 678 bool needsEnvironment = true; 679 updateEnvShapeIfRequired(envShape, needsEnvironment); 680 } 681 682 template <size_t ArrayLength> 683 static JSAtom* GenerateWasmName(JSContext* cx, 684 const char (&prefix)[ArrayLength], 685 uint32_t index) { 686 StringBuilder sb(cx); 687 if (!sb.append(prefix)) { 688 return nullptr; 689 } 690 if (!NumberValueToStringBuilder(NumberValue(index), sb)) { 691 return nullptr; 692 } 693 694 return sb.finishAtom(); 695 } 696 697 static void InitializeTrailingName(AbstractBindingName<JSAtom>* trailingNames, 698 size_t i, JSAtom* name) { 699 void* trailingName = &trailingNames[i]; 700 new (trailingName) BindingName(name, false); 701 } 702 703 template <class DataT> 704 static void InitializeNextTrailingName(RootedBuffer<DataT>& data, 705 JSAtom* name) { 706 InitializeTrailingName(GetScopeDataTrailingNamesPointer(data.get()), 707 data->length, name); 708 data->length++; 709 } 710 711 WasmInstanceScope::RuntimeData::RuntimeData(size_t length) { 712 PoisonNames(this, length); 713 } 714 715 /* static */ 716 WasmInstanceScope* WasmInstanceScope::create( 717 JSContext* cx, Handle<WasmInstanceObject*> instance) { 718 size_t namesCount = 0; 719 720 size_t memoriesStart = namesCount; 721 size_t memoriesCount = instance->instance().codeMeta().memories.length(); 722 namesCount += memoriesCount; 723 724 size_t globalsStart = namesCount; 725 size_t globalsCount = instance->instance().codeMeta().globals.length(); 726 namesCount += globalsCount; 727 728 Rooted<Scope*> enclosing(cx, &cx->global()->emptyGlobalScope()); 729 Rooted<Scope*> scope(cx, Scope::create(cx, ScopeKind::WasmInstance, enclosing, 730 /* envShape = */ nullptr)); 731 if (!scope) { 732 return nullptr; 733 } 734 735 RootedBuffer<RuntimeData> data( 736 cx, NewEmptyScopeData<WasmInstanceScope>(cx, namesCount)); 737 if (!data) { 738 return nullptr; 739 } 740 741 for (size_t i = 0; i < memoriesCount; i++) { 742 JSAtom* wasmName = GenerateWasmName(cx, "memory", i); 743 if (!wasmName) { 744 return nullptr; 745 } 746 747 InitializeNextTrailingName(data, wasmName); 748 } 749 750 for (size_t i = 0; i < globalsCount; i++) { 751 JSAtom* wasmName = GenerateWasmName(cx, "global", i); 752 if (!wasmName) { 753 return nullptr; 754 } 755 756 InitializeNextTrailingName(data, wasmName); 757 } 758 759 MOZ_ASSERT(data->length == namesCount); 760 761 data->instance.init(instance); 762 data->slotInfo.memoriesStart = memoriesStart; 763 data->slotInfo.globalsStart = globalsStart; 764 765 WasmInstanceScope* concreteScope = &scope->as<WasmInstanceScope>(); 766 concreteScope->initData<WasmInstanceScope>(data); 767 return concreteScope; 768 } 769 770 /* static */ 771 WasmFunctionScope* WasmFunctionScope::create(JSContext* cx, 772 Handle<Scope*> enclosing, 773 uint32_t funcIndex) { 774 MOZ_ASSERT(enclosing->is<WasmInstanceScope>()); 775 776 Rooted<WasmFunctionScope*> wasmFunctionScope(cx); 777 778 Rooted<WasmInstanceObject*> instance( 779 cx, enclosing->as<WasmInstanceScope>().instance()); 780 781 // TODO pull the local variable names from the wasm function definition. 782 wasm::ValTypeVector locals; 783 size_t argsLength; 784 wasm::StackResults unusedStackResults; 785 if (!instance->instance().debug().debugGetLocalTypes( 786 funcIndex, &locals, &argsLength, &unusedStackResults)) { 787 return nullptr; 788 } 789 uint32_t namesCount = locals.length(); 790 791 RootedBuffer<RuntimeData> data( 792 cx, NewEmptyScopeData<WasmFunctionScope>(cx, namesCount)); 793 if (!data) { 794 return nullptr; 795 } 796 797 for (size_t i = 0; i < namesCount; i++) { 798 JSAtom* wasmName = GenerateWasmName(cx, "var", i); 799 if (!wasmName) { 800 return nullptr; 801 } 802 803 InitializeNextTrailingName(data, wasmName); 804 } 805 MOZ_ASSERT(data->length == namesCount); 806 807 return Scope::create<WasmFunctionScope>(cx, ScopeKind::WasmFunction, 808 enclosing, 809 /* envShape = */ nullptr, data); 810 } 811 812 ScopeIter::ScopeIter(JSScript* script) : scope_(script->bodyScope()) {} 813 814 bool ScopeIter::hasSyntacticEnvironment() const { 815 return scope()->hasEnvironment() && 816 scope()->kind() != ScopeKind::NonSyntactic; 817 } 818 819 AbstractBindingIter<JSAtom>::AbstractBindingIter(ScopeKind kind, 820 BaseScopeData* data, 821 uint32_t firstFrameSlot) 822 : BaseAbstractBindingIter<JSAtom>() { 823 switch (kind) { 824 case ScopeKind::Lexical: 825 case ScopeKind::SimpleCatch: 826 case ScopeKind::Catch: 827 case ScopeKind::FunctionLexical: 828 init(*static_cast<LexicalScope::RuntimeData*>(data), firstFrameSlot, 0); 829 break; 830 case ScopeKind::NamedLambda: 831 case ScopeKind::StrictNamedLambda: 832 init(*static_cast<LexicalScope::RuntimeData*>(data), LOCALNO_LIMIT, 833 IsNamedLambda); 834 break; 835 case ScopeKind::ClassBody: 836 init(*static_cast<ClassBodyScope::RuntimeData*>(data), firstFrameSlot); 837 break; 838 case ScopeKind::With: 839 // With scopes do not have bindings. 840 index_ = length_ = 0; 841 MOZ_ASSERT(done()); 842 break; 843 case ScopeKind::Function: { 844 uint8_t flags = IgnoreDestructuredFormalParameters; 845 if (static_cast<FunctionScope::RuntimeData*>(data) 846 ->slotInfo.hasParameterExprs()) { 847 flags |= HasFormalParameterExprs; 848 } 849 init(*static_cast<FunctionScope::RuntimeData*>(data), flags); 850 break; 851 } 852 case ScopeKind::FunctionBodyVar: 853 init(*static_cast<VarScope::RuntimeData*>(data), firstFrameSlot); 854 break; 855 case ScopeKind::Eval: 856 case ScopeKind::StrictEval: 857 init(*static_cast<EvalScope::RuntimeData*>(data), 858 kind == ScopeKind::StrictEval); 859 break; 860 case ScopeKind::Global: 861 case ScopeKind::NonSyntactic: 862 init(*static_cast<GlobalScope::RuntimeData*>(data)); 863 break; 864 case ScopeKind::Module: 865 init(*static_cast<ModuleScope::RuntimeData*>(data)); 866 break; 867 case ScopeKind::WasmInstance: 868 init(*static_cast<WasmInstanceScope::RuntimeData*>(data)); 869 break; 870 case ScopeKind::WasmFunction: 871 init(*static_cast<WasmFunctionScope::RuntimeData*>(data)); 872 break; 873 } 874 } 875 876 AbstractBindingIter<JSAtom>::AbstractBindingIter(Scope* scope) 877 : AbstractBindingIter<JSAtom>(scope->kind(), scope->rawData(), 878 scope->firstFrameSlot()) {} 879 880 AbstractBindingIter<JSAtom>::AbstractBindingIter(JSScript* script) 881 : AbstractBindingIter<JSAtom>(script->bodyScope()) {} 882 883 AbstractBindingIter<frontend::TaggedParserAtomIndex>::AbstractBindingIter( 884 const frontend::ScopeStencilRef& ref) 885 : Base() { 886 const ScopeStencil& scope = ref.scope(); 887 BaseParserScopeData* data = ref.context()->scopeNames[ref.scopeIndex_]; 888 switch (scope.kind()) { 889 case ScopeKind::Lexical: 890 case ScopeKind::SimpleCatch: 891 case ScopeKind::Catch: 892 case ScopeKind::FunctionLexical: 893 init(*static_cast<LexicalScope::ParserData*>(data), 894 scope.firstFrameSlot(), 0); 895 break; 896 case ScopeKind::NamedLambda: 897 case ScopeKind::StrictNamedLambda: 898 init(*static_cast<LexicalScope::ParserData*>(data), LOCALNO_LIMIT, 899 IsNamedLambda); 900 break; 901 case ScopeKind::ClassBody: 902 init(*static_cast<ClassBodyScope::ParserData*>(data), 903 scope.firstFrameSlot()); 904 break; 905 case ScopeKind::With: 906 // With scopes do not have bindings. 907 index_ = length_ = 0; 908 MOZ_ASSERT(done()); 909 break; 910 case ScopeKind::Function: { 911 uint8_t flags = IgnoreDestructuredFormalParameters; 912 if (static_cast<FunctionScope::ParserData*>(data) 913 ->slotInfo.hasParameterExprs()) { 914 flags |= HasFormalParameterExprs; 915 } 916 init(*static_cast<FunctionScope::ParserData*>(data), flags); 917 break; 918 } 919 case ScopeKind::FunctionBodyVar: 920 init(*static_cast<VarScope::ParserData*>(data), scope.firstFrameSlot()); 921 break; 922 case ScopeKind::Eval: 923 case ScopeKind::StrictEval: 924 init(*static_cast<EvalScope::ParserData*>(data), 925 scope.kind() == ScopeKind::StrictEval); 926 break; 927 case ScopeKind::Global: 928 case ScopeKind::NonSyntactic: 929 init(*static_cast<GlobalScope::ParserData*>(data)); 930 break; 931 case ScopeKind::Module: 932 init(*static_cast<ModuleScope::ParserData*>(data)); 933 break; 934 case ScopeKind::WasmInstance: 935 init(*static_cast<WasmInstanceScope::ParserData*>(data)); 936 break; 937 case ScopeKind::WasmFunction: 938 init(*static_cast<WasmFunctionScope::ParserData*>(data)); 939 break; 940 } 941 } 942 943 template <typename NameT> 944 void BaseAbstractBindingIter<NameT>::init( 945 LexicalScope::AbstractData<NameT>& data, uint32_t firstFrameSlot, 946 uint8_t flags) { 947 auto& slotInfo = data.slotInfo; 948 949 // Named lambda scopes can only have environment slots. If the callee 950 // isn't closed over, it is accessed via JSOp::Callee. 951 if (flags & IsNamedLambda) { 952 // Named lambda binding is weird. Normal BindingKind ordering rules 953 // don't apply. 954 init(/* positionalFormalStart= */ 0, 955 /* nonPositionalFormalStart= */ 0, 956 /* varStart= */ 0, 957 /* letStart= */ 0, 958 /* constStart= */ 0, 959 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 960 /* usingStart= */ data.length, 961 #endif 962 /* syntheticStart= */ data.length, 963 /* privageMethodStart= */ data.length, 964 /* flags= */ CanHaveEnvironmentSlots | flags, 965 /* firstFrameSlot= */ firstFrameSlot, 966 /* firstEnvironmentSlot= */ 967 JSSLOT_FREE(&LexicalEnvironmentObject::class_), 968 /* names= */ GetScopeDataTrailingNames(&data)); 969 } else { 970 // imports - [0, 0) 971 // positional formals - [0, 0) 972 // other formals - [0, 0) 973 // vars - [0, 0) 974 // lets - [0, slotInfo.constStart) 975 // consts - [slotInfo.constStart, data.length) 976 // synthetic - [data.length, data.length) 977 // private methods - [data.length, data.length) 978 // 979 // If ENABLE_EXPLICIT_RESOURCE_MANAGEMENT is set, the consts range is split 980 // into the following: 981 // consts - [slotInfo.constStart, slotInfo.usingStart) 982 // usings - [slotInfo.usingStart, data.length) 983 init(/* positionalFormalStart= */ 0, 984 /* nonPositionalFormalStart= */ 0, 985 /* varStart= */ 0, 986 /* letStart= */ 0, 987 /* constStart= */ slotInfo.constStart, 988 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 989 /* usingStart= */ slotInfo.usingStart, 990 #endif 991 /* syntheticStart= */ data.length, 992 /* privateMethodStart= */ data.length, 993 /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots | flags, 994 /* firstFrameSlot= */ firstFrameSlot, 995 /* firstEnvironmentSlot= */ 996 JSSLOT_FREE(&LexicalEnvironmentObject::class_), 997 /* names= */ GetScopeDataTrailingNames(&data)); 998 } 999 } 1000 1001 template void BaseAbstractBindingIter<JSAtom>::init( 1002 LexicalScope::AbstractData<JSAtom>&, uint32_t, uint8_t); 1003 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init( 1004 LexicalScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint32_t, 1005 uint8_t); 1006 1007 template <typename NameT> 1008 void BaseAbstractBindingIter<NameT>::init( 1009 ClassBodyScope::AbstractData<NameT>& data, uint32_t firstFrameSlot) { 1010 auto& slotInfo = data.slotInfo; 1011 1012 // imports - [0, 0) 1013 // positional formals - [0, 0) 1014 // other formals - [0, 0) 1015 // vars - [0, 0) 1016 // lets - [0, 0) 1017 // consts - [0, 0) 1018 // synthetic - [0, slotInfo.privateMethodStart) 1019 // private methods - [slotInfo.privateMethodStart, data.length) 1020 init(/* positionalFormalStart= */ 0, 1021 /* nonPositionalFormalStart= */ 0, 1022 /* varStart= */ 0, 1023 /* letStart= */ 0, 1024 /* constStart= */ 0, 1025 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1026 /* usingStart= */ 0, 1027 #endif 1028 /* syntheticStart= */ 0, 1029 /* privateMethodStart= */ slotInfo.privateMethodStart, 1030 /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots, 1031 /* firstFrameSlot= */ firstFrameSlot, 1032 /* firstEnvironmentSlot= */ 1033 JSSLOT_FREE(&ClassBodyLexicalEnvironmentObject::class_), 1034 /* names= */ GetScopeDataTrailingNames(&data)); 1035 } 1036 1037 template void BaseAbstractBindingIter<JSAtom>::init( 1038 ClassBodyScope::AbstractData<JSAtom>&, uint32_t); 1039 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init( 1040 ClassBodyScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint32_t); 1041 1042 template <typename NameT> 1043 void BaseAbstractBindingIter<NameT>::init( 1044 FunctionScope::AbstractData<NameT>& data, uint8_t flags) { 1045 flags = CanHaveFrameSlots | CanHaveEnvironmentSlots | flags; 1046 if (!(flags & HasFormalParameterExprs)) { 1047 flags |= CanHaveArgumentSlots; 1048 } 1049 1050 auto length = data.length; 1051 auto& slotInfo = data.slotInfo; 1052 1053 // imports - [0, 0) 1054 // positional formals - [0, slotInfo.nonPositionalFormalStart) 1055 // other formals - [slotInfo.nonPositionalParamStart, slotInfo.varStart) 1056 // vars - [slotInfo.varStart, length) 1057 // lets - [length, length) 1058 // consts - [length, length) 1059 // synthetic - [length, length) 1060 // private methods - [length, length) 1061 init(/* positionalFormalStart= */ 0, 1062 /* nonPositionalFormalStart= */ slotInfo.nonPositionalFormalStart, 1063 /* varStart= */ slotInfo.varStart, 1064 /* letStart= */ length, 1065 /* constStart= */ length, 1066 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1067 /* usingStart= */ length, 1068 #endif 1069 /* syntheticStart= */ length, 1070 /* privateMethodStart= */ length, 1071 /* flags= */ flags, 1072 /* firstFrameSlot= */ 0, 1073 /* firstEnvironmentSlot= */ JSSLOT_FREE(&CallObject::class_), 1074 /* names= */ GetScopeDataTrailingNames(&data)); 1075 } 1076 template void BaseAbstractBindingIter<JSAtom>::init( 1077 FunctionScope::AbstractData<JSAtom>&, uint8_t); 1078 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init( 1079 FunctionScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint8_t); 1080 1081 template <typename NameT> 1082 void BaseAbstractBindingIter<NameT>::init(VarScope::AbstractData<NameT>& data, 1083 uint32_t firstFrameSlot) { 1084 auto length = data.length; 1085 1086 // imports - [0, 0) 1087 // positional formals - [0, 0) 1088 // other formals - [0, 0) 1089 // vars - [0, length) 1090 // lets - [length, length) 1091 // consts - [length, length) 1092 // synthetic - [length, length) 1093 // private methods - [length, length) 1094 init(/* positionalFormalStart= */ 0, 1095 /* nonPositionalFormalStart= */ 0, 1096 /* varStart= */ 0, 1097 /* letStart= */ length, 1098 /* constStart= */ length, 1099 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1100 /* usingStart= */ length, 1101 #endif 1102 /* syntheticStart= */ length, 1103 /* privateMethodStart= */ length, 1104 /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots, 1105 /* firstFrameSlot= */ firstFrameSlot, 1106 /* firstEnvironmentSlot= */ JSSLOT_FREE(&VarEnvironmentObject::class_), 1107 /* names= */ GetScopeDataTrailingNames(&data)); 1108 } 1109 template void BaseAbstractBindingIter<JSAtom>::init( 1110 VarScope::AbstractData<JSAtom>&, uint32_t); 1111 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init( 1112 VarScope::AbstractData<frontend::TaggedParserAtomIndex>&, uint32_t); 1113 1114 template <typename NameT> 1115 void BaseAbstractBindingIter<NameT>::init( 1116 GlobalScope::AbstractData<NameT>& data) { 1117 auto& slotInfo = data.slotInfo; 1118 1119 // imports - [0, 0) 1120 // positional formals - [0, 0) 1121 // other formals - [0, 0) 1122 // vars - [0, slotInfo.letStart) 1123 // lets - [slotInfo.letStart, slotInfo.constStart) 1124 // consts - [slotInfo.constStart, data.length) 1125 // synthetic - [data.length, data.length) 1126 // private methods - [data.length, data.length) 1127 init(/* positionalFormalStart= */ 0, 1128 /* nonPositionalFormalStart= */ 0, 1129 /* varStart= */ 0, 1130 /* letStart= */ slotInfo.letStart, 1131 /* constStart= */ slotInfo.constStart, 1132 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1133 /* usingStart= */ data.length, 1134 #endif 1135 /* syntheticStart= */ data.length, 1136 /* privateMethoodStart= */ data.length, 1137 /* flags= */ CannotHaveSlots, 1138 /* firstFrameSlot= */ UINT32_MAX, 1139 /* firstEnvironmentSlot= */ UINT32_MAX, 1140 /* names= */ GetScopeDataTrailingNames(&data)); 1141 } 1142 template void BaseAbstractBindingIter<JSAtom>::init( 1143 GlobalScope::AbstractData<JSAtom>&); 1144 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init( 1145 GlobalScope::AbstractData<frontend::TaggedParserAtomIndex>&); 1146 1147 template <typename NameT> 1148 void BaseAbstractBindingIter<NameT>::init(EvalScope::AbstractData<NameT>& data, 1149 bool strict) { 1150 uint32_t flags; 1151 uint32_t firstFrameSlot; 1152 uint32_t firstEnvironmentSlot; 1153 if (strict) { 1154 flags = CanHaveFrameSlots | CanHaveEnvironmentSlots; 1155 firstFrameSlot = 0; 1156 firstEnvironmentSlot = JSSLOT_FREE(&VarEnvironmentObject::class_); 1157 } else { 1158 flags = CannotHaveSlots; 1159 firstFrameSlot = UINT32_MAX; 1160 firstEnvironmentSlot = UINT32_MAX; 1161 } 1162 1163 auto length = data.length; 1164 1165 // imports - [0, 0) 1166 // positional formals - [0, 0) 1167 // other formals - [0, 0) 1168 // vars - [0, length) 1169 // lets - [length, length) 1170 // consts - [length, length) 1171 // synthetic - [length, length) 1172 // private methods - [length, length) 1173 init(/* positionalFormalStart= */ 0, 1174 /* nonPositionalFormalStart= */ 0, 1175 /* varStart= */ 0, 1176 /* letStart= */ length, 1177 /* constStart= */ length, 1178 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1179 /* usingStart= */ length, 1180 #endif 1181 /* syntheticStart= */ length, 1182 /* privateMethodStart= */ length, 1183 /* flags= */ flags, 1184 /* firstFrameSlot= */ firstFrameSlot, 1185 /* firstEnvironmentSlot= */ firstEnvironmentSlot, 1186 /* names= */ GetScopeDataTrailingNames(&data)); 1187 } 1188 template void BaseAbstractBindingIter<JSAtom>::init( 1189 EvalScope::AbstractData<JSAtom>&, bool); 1190 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init( 1191 EvalScope::AbstractData<frontend::TaggedParserAtomIndex>&, bool); 1192 1193 template <typename NameT> 1194 void BaseAbstractBindingIter<NameT>::init( 1195 ModuleScope::AbstractData<NameT>& data) { 1196 auto& slotInfo = data.slotInfo; 1197 1198 // imports - [0, slotInfo.varStart) 1199 // positional formals - [slotInfo.varStart, slotInfo.varStart) 1200 // other formals - [slotInfo.varStart, slotInfo.varStart) 1201 // vars - [slotInfo.varStart, slotInfo.letStart) 1202 // lets - [slotInfo.letStart, slotInfo.constStart) 1203 // consts - [slotInfo.constStart, data.length) 1204 // synthetic - [data.length, data.length) 1205 // private methods - [data.length, data.length) 1206 // 1207 // If ENABLE_EXPLICIT_RESOURCE_MANAGEMENT is set, the consts range is split 1208 // into the following: 1209 // consts - [slotInfo.constStart, slotInfo.usingStart) 1210 // usings - [slotInfo.usingStart, data.length) 1211 init( 1212 /* positionalFormalStart= */ slotInfo.varStart, 1213 /* nonPositionalFormalStart= */ slotInfo.varStart, 1214 /* varStart= */ slotInfo.varStart, 1215 /* letStart= */ slotInfo.letStart, 1216 /* constStart= */ slotInfo.constStart, 1217 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1218 /* usingStart= */ slotInfo.usingStart, 1219 #endif 1220 /* syntheticStart= */ data.length, 1221 /* privateMethodStart= */ data.length, 1222 /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots, 1223 /* firstFrameSlot= */ 0, 1224 /* firstEnvironmentSlot= */ JSSLOT_FREE(&ModuleEnvironmentObject::class_), 1225 /* names= */ GetScopeDataTrailingNames(&data)); 1226 } 1227 template void BaseAbstractBindingIter<JSAtom>::init( 1228 ModuleScope::AbstractData<JSAtom>&); 1229 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init( 1230 ModuleScope::AbstractData<frontend::TaggedParserAtomIndex>&); 1231 1232 template <typename NameT> 1233 void BaseAbstractBindingIter<NameT>::init( 1234 WasmInstanceScope::AbstractData<NameT>& data) { 1235 auto length = data.length; 1236 1237 // imports - [0, 0) 1238 // positional formals - [0, 0) 1239 // other formals - [0, 0) 1240 // vars - [0, length) 1241 // lets - [length, length) 1242 // consts - [length, length) 1243 // synthetic - [length, length) 1244 // private methods - [length, length) 1245 init(/* positionalFormalStart= */ 0, 1246 /* nonPositionalFormalStart= */ 0, 1247 /* varStart= */ 0, 1248 /* letStart= */ length, 1249 /* constStart= */ length, 1250 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1251 /* usingStart= */ length, 1252 #endif 1253 /* syntheticStart= */ length, 1254 /* privateMethodStart= */ length, 1255 /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots, 1256 /* firstFrameSlot= */ UINT32_MAX, 1257 /* firstEnvironmentSlot= */ UINT32_MAX, 1258 /* names= */ GetScopeDataTrailingNames(&data)); 1259 } 1260 template void BaseAbstractBindingIter<JSAtom>::init( 1261 WasmInstanceScope::AbstractData<JSAtom>&); 1262 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init( 1263 WasmInstanceScope::AbstractData<frontend::TaggedParserAtomIndex>&); 1264 1265 template <typename NameT> 1266 void BaseAbstractBindingIter<NameT>::init( 1267 WasmFunctionScope::AbstractData<NameT>& data) { 1268 auto length = data.length; 1269 1270 // imports - [0, 0) 1271 // positional formals - [0, 0) 1272 // other formals - [0, 0) 1273 // vars - [0, length) 1274 // lets - [length, length) 1275 // consts - [length, length) 1276 // synthetic - [length, length) 1277 // private methods - [length, length) 1278 init(/* positionalFormalStart = */ 0, 1279 /* nonPositionalFormalStart = */ 0, 1280 /* varStart= */ 0, 1281 /* letStart= */ length, 1282 /* constStart= */ length, 1283 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1284 /* usingStart= */ length, 1285 #endif 1286 /* syntheticStart= */ length, 1287 /* privateMethodStart= */ length, 1288 /* flags= */ CanHaveFrameSlots | CanHaveEnvironmentSlots, 1289 /* firstFrameSlot= */ UINT32_MAX, 1290 /* firstEnvironmentSlot= */ UINT32_MAX, 1291 /* names= */ GetScopeDataTrailingNames(&data)); 1292 } 1293 template void BaseAbstractBindingIter<JSAtom>::init( 1294 WasmFunctionScope::AbstractData<JSAtom>&); 1295 template void BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>::init( 1296 WasmFunctionScope::AbstractData<frontend::TaggedParserAtomIndex>&); 1297 1298 AbstractPositionalFormalParameterIter< 1299 JSAtom>::AbstractPositionalFormalParameterIter(Scope* scope) 1300 : Base(scope) { 1301 // Reinit with flags = 0, i.e., iterate over all positional parameters. 1302 if (scope->is<FunctionScope>()) { 1303 init(scope->as<FunctionScope>().data(), /* flags = */ 0); 1304 } 1305 settle(); 1306 } 1307 1308 AbstractPositionalFormalParameterIter< 1309 JSAtom>::AbstractPositionalFormalParameterIter(JSScript* script) 1310 : AbstractPositionalFormalParameterIter(script->bodyScope()) {} 1311 1312 void js::DumpBindings(JSContext* cx, Scope* scopeArg) { 1313 Rooted<Scope*> scope(cx, scopeArg); 1314 for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) { 1315 UniqueChars bytes = AtomToPrintableString(cx, bi.name()); 1316 if (!bytes) { 1317 MaybePrintAndClearPendingException(cx); 1318 return; 1319 } 1320 fprintf(stderr, " %s %s ", BindingKindString(bi.kind()), bytes.get()); 1321 switch (bi.location().kind()) { 1322 case BindingLocation::Kind::Global: 1323 if (bi.isTopLevelFunction()) { 1324 fprintf(stderr, "global function\n"); 1325 } else { 1326 fprintf(stderr, "global\n"); 1327 } 1328 break; 1329 case BindingLocation::Kind::Argument: 1330 fprintf(stderr, "arg slot %u\n", bi.location().argumentSlot()); 1331 break; 1332 case BindingLocation::Kind::Frame: 1333 fprintf(stderr, "frame slot %u\n", bi.location().slot()); 1334 break; 1335 case BindingLocation::Kind::Environment: 1336 fprintf(stderr, "env slot %u\n", bi.location().slot()); 1337 break; 1338 case BindingLocation::Kind::NamedLambdaCallee: 1339 fprintf(stderr, "named lambda callee\n"); 1340 break; 1341 case BindingLocation::Kind::Import: 1342 fprintf(stderr, "import\n"); 1343 break; 1344 } 1345 } 1346 } 1347 1348 static JSAtom* GetFrameSlotNameInScope(Scope* scope, uint32_t slot) { 1349 for (BindingIter bi(scope); bi; bi++) { 1350 BindingLocation loc = bi.location(); 1351 if (loc.kind() == BindingLocation::Kind::Frame && loc.slot() == slot) { 1352 return bi.name(); 1353 } 1354 } 1355 return nullptr; 1356 } 1357 1358 JSAtom* js::FrameSlotName(JSScript* script, jsbytecode* pc) { 1359 MOZ_ASSERT(IsLocalOp(JSOp(*pc))); 1360 uint32_t slot = GET_LOCALNO(pc); 1361 MOZ_ASSERT(slot < script->nfixed()); 1362 1363 // Look for it in the body scope first. 1364 if (JSAtom* name = GetFrameSlotNameInScope(script->bodyScope(), slot)) { 1365 return name; 1366 } 1367 1368 // If this is a function script and there is an extra var scope, look for 1369 // it there. 1370 if (script->functionHasExtraBodyVarScope()) { 1371 if (JSAtom* name = GetFrameSlotNameInScope( 1372 script->functionExtraBodyVarScope(), slot)) { 1373 return name; 1374 } 1375 } 1376 // If not found, look for it in a lexical scope. 1377 for (ScopeIter si(script->innermostScope(pc)); si; si++) { 1378 if (!si.scope()->is<LexicalScope>() && !si.scope()->is<ClassBodyScope>()) { 1379 continue; 1380 } 1381 1382 // Is the slot within bounds of the current lexical scope? 1383 if (slot < si.scope()->firstFrameSlot()) { 1384 continue; 1385 } 1386 if (slot >= LexicalScope::nextFrameSlot(si.scope())) { 1387 break; 1388 } 1389 1390 // If so, get the name. 1391 if (JSAtom* name = GetFrameSlotNameInScope(si.scope(), slot)) { 1392 return name; 1393 } 1394 } 1395 1396 MOZ_CRASH("Frame slot not found"); 1397 } 1398 1399 JS::ubi::Node::Size JS::ubi::Concrete<Scope>::size( 1400 mozilla::MallocSizeOf mallocSizeOf) const { 1401 return js::gc::Arena::thingSize(get().asTenured().getAllocKind()) + 1402 get().sizeOfExcludingThis(); 1403 } 1404 1405 template <typename... Args> 1406 /* static */ bool ScopeStencil::appendScopeStencilAndData( 1407 FrontendContext* fc, CompilationState& compilationState, 1408 BaseParserScopeData* data, ScopeIndex* indexOut, Args&&... args) { 1409 *indexOut = ScopeIndex(compilationState.scopeData.length()); 1410 if (uint32_t(*indexOut) >= TaggedScriptThingIndex::IndexLimit) { 1411 ReportAllocationOverflow(fc); 1412 return false; 1413 } 1414 1415 if (!compilationState.scopeData.emplaceBack(std::forward<Args>(args)...)) { 1416 js::ReportOutOfMemory(fc); 1417 return false; 1418 } 1419 if (!compilationState.scopeNames.append(data)) { 1420 compilationState.scopeData.popBack(); 1421 MOZ_ASSERT(compilationState.scopeData.length() == 1422 compilationState.scopeNames.length()); 1423 1424 js::ReportOutOfMemory(fc); 1425 return false; 1426 } 1427 1428 return true; 1429 } 1430 1431 /* static */ 1432 bool ScopeStencil::createForFunctionScope( 1433 FrontendContext* fc, frontend::CompilationState& compilationState, 1434 FunctionScope::ParserData* data, bool hasParameterExprs, 1435 bool needsEnvironment, ScriptIndex functionIndex, bool isArrow, 1436 mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) { 1437 auto kind = ScopeKind::Function; 1438 using ScopeType = FunctionScope; 1439 MOZ_ASSERT(matchScopeKind<ScopeType>(kind)); 1440 1441 if (data) { 1442 MarkParserScopeData<ScopeType>(data, compilationState); 1443 } else { 1444 data = NewEmptyParserScopeData<ScopeType>(fc, compilationState.alloc); 1445 if (!data) { 1446 return false; 1447 } 1448 } 1449 1450 uint32_t firstFrameSlot = 0; 1451 mozilla::Maybe<uint32_t> envShape; 1452 FunctionScope::prepareForScopeCreation(data, hasParameterExprs, 1453 needsEnvironment, &envShape); 1454 1455 return appendScopeStencilAndData(fc, compilationState, data, index, kind, 1456 enclosing, firstFrameSlot, envShape, 1457 mozilla::Some(functionIndex), isArrow); 1458 } 1459 1460 /* static */ 1461 bool ScopeStencil::createForLexicalScope( 1462 FrontendContext* fc, frontend::CompilationState& compilationState, 1463 ScopeKind kind, LexicalScope::ParserData* data, uint32_t firstFrameSlot, 1464 mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) { 1465 using ScopeType = LexicalScope; 1466 MOZ_ASSERT(matchScopeKind<ScopeType>(kind)); 1467 1468 if (data) { 1469 MarkParserScopeData<ScopeType>(data, compilationState); 1470 } else { 1471 data = NewEmptyParserScopeData<ScopeType>(fc, compilationState.alloc); 1472 if (!data) { 1473 return false; 1474 } 1475 } 1476 1477 mozilla::Maybe<uint32_t> envShape; 1478 ScopeType::prepareForScopeCreation(kind, firstFrameSlot, data, &envShape); 1479 1480 return appendScopeStencilAndData(fc, compilationState, data, index, kind, 1481 enclosing, firstFrameSlot, envShape); 1482 } 1483 1484 /* static */ 1485 bool ScopeStencil::createForClassBodyScope( 1486 FrontendContext* fc, frontend::CompilationState& compilationState, 1487 ScopeKind kind, ClassBodyScope::ParserData* data, uint32_t firstFrameSlot, 1488 mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) { 1489 using ScopeType = ClassBodyScope; 1490 MOZ_ASSERT(matchScopeKind<ScopeType>(kind)); 1491 1492 if (data) { 1493 MarkParserScopeData<ScopeType>(data, compilationState); 1494 } else { 1495 data = NewEmptyParserScopeData<ScopeType>(fc, compilationState.alloc); 1496 if (!data) { 1497 return false; 1498 } 1499 } 1500 1501 mozilla::Maybe<uint32_t> envShape; 1502 ScopeType::prepareForScopeCreation(kind, firstFrameSlot, data, &envShape); 1503 1504 return appendScopeStencilAndData(fc, compilationState, data, index, kind, 1505 enclosing, firstFrameSlot, envShape); 1506 } 1507 1508 bool ScopeStencil::createForVarScope( 1509 FrontendContext* fc, frontend::CompilationState& compilationState, 1510 ScopeKind kind, VarScope::ParserData* data, uint32_t firstFrameSlot, 1511 bool needsEnvironment, mozilla::Maybe<ScopeIndex> enclosing, 1512 ScopeIndex* index) { 1513 using ScopeType = VarScope; 1514 MOZ_ASSERT(matchScopeKind<ScopeType>(kind)); 1515 1516 if (data) { 1517 MarkParserScopeData<ScopeType>(data, compilationState); 1518 } else { 1519 data = NewEmptyParserScopeData<ScopeType>(fc, compilationState.alloc); 1520 if (!data) { 1521 return false; 1522 } 1523 } 1524 1525 mozilla::Maybe<uint32_t> envShape; 1526 VarScope::prepareForScopeCreation(kind, data, firstFrameSlot, 1527 needsEnvironment, &envShape); 1528 1529 return appendScopeStencilAndData(fc, compilationState, data, index, kind, 1530 enclosing, firstFrameSlot, envShape); 1531 } 1532 1533 /* static */ 1534 bool ScopeStencil::createForGlobalScope( 1535 FrontendContext* fc, frontend::CompilationState& compilationState, 1536 ScopeKind kind, GlobalScope::ParserData* data, ScopeIndex* index) { 1537 using ScopeType = GlobalScope; 1538 MOZ_ASSERT(matchScopeKind<ScopeType>(kind)); 1539 1540 if (data) { 1541 MarkParserScopeData<ScopeType>(data, compilationState); 1542 } else { 1543 data = NewEmptyParserScopeData<ScopeType>(fc, compilationState.alloc); 1544 if (!data) { 1545 return false; 1546 } 1547 } 1548 1549 // The global scope has no environment shape. Its environment is the 1550 // global lexical scope and the global object or non-syntactic objects 1551 // created by embedding, all of which are not only extensible but may 1552 // have names on them deleted. 1553 uint32_t firstFrameSlot = 0; 1554 mozilla::Maybe<uint32_t> envShape; 1555 1556 mozilla::Maybe<ScopeIndex> enclosing; 1557 1558 return appendScopeStencilAndData(fc, compilationState, data, index, kind, 1559 enclosing, firstFrameSlot, envShape); 1560 } 1561 1562 /* static */ 1563 bool ScopeStencil::createForEvalScope( 1564 FrontendContext* fc, frontend::CompilationState& compilationState, 1565 ScopeKind kind, EvalScope::ParserData* data, 1566 mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index) { 1567 using ScopeType = EvalScope; 1568 MOZ_ASSERT(matchScopeKind<ScopeType>(kind)); 1569 1570 if (data) { 1571 MarkParserScopeData<ScopeType>(data, compilationState); 1572 } else { 1573 data = NewEmptyParserScopeData<ScopeType>(fc, compilationState.alloc); 1574 if (!data) { 1575 return false; 1576 } 1577 } 1578 1579 uint32_t firstFrameSlot = 0; 1580 mozilla::Maybe<uint32_t> envShape; 1581 EvalScope::prepareForScopeCreation(kind, data, &envShape); 1582 1583 return appendScopeStencilAndData(fc, compilationState, data, index, kind, 1584 enclosing, firstFrameSlot, envShape); 1585 } 1586 1587 /* static */ 1588 bool ScopeStencil::createForModuleScope( 1589 FrontendContext* fc, frontend::CompilationState& compilationState, 1590 ModuleScope::ParserData* data, mozilla::Maybe<ScopeIndex> enclosing, 1591 ScopeIndex* index) { 1592 auto kind = ScopeKind::Module; 1593 using ScopeType = ModuleScope; 1594 MOZ_ASSERT(matchScopeKind<ScopeType>(kind)); 1595 1596 if (data) { 1597 MarkParserScopeData<ScopeType>(data, compilationState); 1598 } else { 1599 data = NewEmptyParserScopeData<ScopeType>(fc, compilationState.alloc); 1600 if (!data) { 1601 return false; 1602 } 1603 } 1604 1605 MOZ_ASSERT(enclosing.isNothing()); 1606 1607 // The data that's passed in is from the frontend and is LifoAlloc'd. 1608 // Copy it now that we're creating a permanent VM scope. 1609 uint32_t firstFrameSlot = 0; 1610 mozilla::Maybe<uint32_t> envShape; 1611 ModuleScope::prepareForScopeCreation(data, &envShape); 1612 1613 return appendScopeStencilAndData(fc, compilationState, data, index, kind, 1614 enclosing, firstFrameSlot, envShape); 1615 } 1616 1617 template <typename SpecificEnvironmentT> 1618 bool ScopeStencil::createSpecificShape( 1619 JSContext* cx, ScopeKind kind, BaseScopeData* scopeData, 1620 MutableHandle<SharedShape*> shape) const { 1621 const JSClass* cls = &SpecificEnvironmentT::class_; 1622 constexpr ObjectFlags objectFlags = SpecificEnvironmentT::OBJECT_FLAGS; 1623 1624 if (hasEnvironmentShape()) { 1625 if (numEnvironmentSlots() > 0) { 1626 BindingIter bi(kind, scopeData, firstFrameSlot_); 1627 shape.set(CreateEnvironmentShape(cx, bi, cls, numEnvironmentSlots(), 1628 objectFlags)); 1629 return shape; 1630 } 1631 1632 shape.set(EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), objectFlags)); 1633 return shape; 1634 } 1635 1636 return true; 1637 } 1638 1639 /* static */ 1640 bool ScopeStencil::createForWithScope(FrontendContext* fc, 1641 CompilationState& compilationState, 1642 mozilla::Maybe<ScopeIndex> enclosing, 1643 ScopeIndex* index) { 1644 auto kind = ScopeKind::With; 1645 MOZ_ASSERT(matchScopeKind<WithScope>(kind)); 1646 1647 uint32_t firstFrameSlot = 0; 1648 mozilla::Maybe<uint32_t> envShape; 1649 1650 return appendScopeStencilAndData(fc, compilationState, nullptr, index, kind, 1651 enclosing, firstFrameSlot, envShape); 1652 } 1653 1654 template <typename SpecificScopeT> 1655 typename SpecificScopeT::RuntimeData* ScopeStencil::createSpecificScopeData( 1656 JSContext* cx, CompilationAtomCache& atomCache, 1657 BaseParserScopeData* baseData) const { 1658 return LiftParserScopeData<SpecificScopeT>(cx, atomCache, baseData); 1659 } 1660 1661 template <> 1662 FunctionScope::RuntimeData* 1663 ScopeStencil::createSpecificScopeData<FunctionScope>( 1664 JSContext* cx, CompilationAtomCache& atomCache, 1665 BaseParserScopeData* baseData) const { 1666 // Allocate a new vm function-scope. 1667 return LiftParserScopeData<FunctionScope>(cx, atomCache, baseData); 1668 } 1669 1670 template <> 1671 ModuleScope::RuntimeData* ScopeStencil::createSpecificScopeData<ModuleScope>( 1672 JSContext* cx, CompilationAtomCache& atomCache, 1673 BaseParserScopeData* baseData) const { 1674 // Allocate a new vm module-scope. 1675 return LiftParserScopeData<ModuleScope>(cx, atomCache, baseData); 1676 } 1677 1678 // WithScope does not use binding data. 1679 template <> 1680 Scope* ScopeStencil::createSpecificScope<WithScope, std::nullptr_t>( 1681 JSContext* cx, CompilationAtomCache& atomCache, 1682 Handle<Scope*> enclosingScope, BaseParserScopeData* baseData) const { 1683 return Scope::create(cx, ScopeKind::With, enclosingScope, nullptr); 1684 } 1685 1686 // GlobalScope has bindings but no environment shape. 1687 template <> 1688 Scope* ScopeStencil::createSpecificScope<GlobalScope, std::nullptr_t>( 1689 JSContext* cx, CompilationAtomCache& atomCache, 1690 Handle<Scope*> enclosingScope, BaseParserScopeData* baseData) const { 1691 RootedBuffer<GlobalScope::RuntimeData> data( 1692 cx, createSpecificScopeData<GlobalScope>(cx, atomCache, baseData)); 1693 if (!data) { 1694 return nullptr; 1695 } 1696 1697 MOZ_ASSERT(!hasEnclosing()); 1698 MOZ_ASSERT(!enclosingScope); 1699 1700 // Because we already baked the data here, we needn't do it again. 1701 return Scope::create<GlobalScope>(cx, kind(), nullptr, nullptr, data); 1702 } 1703 1704 template <typename SpecificScopeT, typename SpecificEnvironmentT> 1705 Scope* ScopeStencil::createSpecificScope(JSContext* cx, 1706 CompilationAtomCache& atomCache, 1707 Handle<Scope*> enclosingScope, 1708 BaseParserScopeData* baseData) const { 1709 RootedBuffer<typename SpecificScopeT::RuntimeData> data( 1710 cx, createSpecificScopeData<SpecificScopeT>(cx, atomCache, baseData)); 1711 if (!data) { 1712 return nullptr; 1713 } 1714 1715 Rooted<SharedShape*> shape(cx); 1716 if (!createSpecificShape<SpecificEnvironmentT>(cx, kind(), data, &shape)) { 1717 return nullptr; 1718 } 1719 1720 // Because we already baked the data here, we needn't do it again. 1721 return Scope::create<SpecificScopeT>(cx, kind(), enclosingScope, shape, data); 1722 } 1723 1724 template Scope* ScopeStencil::createSpecificScope<FunctionScope, CallObject>( 1725 JSContext* cx, CompilationAtomCache& atomCache, 1726 Handle<Scope*> enclosingScope, BaseParserScopeData* baseData) const; 1727 template Scope* 1728 ScopeStencil::createSpecificScope<LexicalScope, BlockLexicalEnvironmentObject>( 1729 JSContext* cx, CompilationAtomCache& atomCache, 1730 Handle<Scope*> enclosingScope, BaseParserScopeData* baseData) const; 1731 template Scope* ScopeStencil::createSpecificScope< 1732 ClassBodyScope, BlockLexicalEnvironmentObject>( 1733 JSContext* cx, CompilationAtomCache& atomCache, 1734 Handle<Scope*> enclosingScope, BaseParserScopeData* baseData) const; 1735 template Scope* 1736 ScopeStencil::createSpecificScope<EvalScope, VarEnvironmentObject>( 1737 JSContext* cx, CompilationAtomCache& atomCache, 1738 Handle<Scope*> enclosingScope, BaseParserScopeData* baseData) const; 1739 template Scope* 1740 ScopeStencil::createSpecificScope<VarScope, VarEnvironmentObject>( 1741 JSContext* cx, CompilationAtomCache& atomCache, 1742 Handle<Scope*> enclosingScope, BaseParserScopeData* baseData) const; 1743 template Scope* 1744 ScopeStencil::createSpecificScope<ModuleScope, ModuleEnvironmentObject>( 1745 JSContext* cx, CompilationAtomCache& atomCache, 1746 Handle<Scope*> enclosingScope, BaseParserScopeData* baseData) const;