EnvironmentObject.h (66869B)
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 #ifndef vm_EnvironmentObject_h 8 #define vm_EnvironmentObject_h 9 10 #include <type_traits> 11 12 #include "frontend/NameAnalysisTypes.h" 13 #include "gc/Barrier.h" 14 #include "gc/WeakMap.h" 15 #include "js/GCHashTable.h" 16 #include "vm/ArgumentsObject.h" 17 #include "vm/GlobalObject.h" 18 #include "vm/JSObject.h" 19 #include "vm/ProxyObject.h" 20 #include "vm/Scope.h" 21 #include "vm/ScopeKind.h" // ScopeKind 22 23 namespace JS { 24 class JS_PUBLIC_API EnvironmentChain; 25 enum class SupportUnscopables : bool; 26 }; // namespace JS 27 28 namespace js { 29 30 class AbstractGeneratorObject; 31 class IndirectBindingMap; 32 class ModuleObject; 33 34 // Return the name being accessed by the given ALIASEDVAR op. This function is 35 // relatively slow so it should not be used on hot paths. 36 extern PropertyName* EnvironmentCoordinateNameSlow(JSScript* script, 37 jsbytecode* pc); 38 39 /*** Environment objects ****************************************************/ 40 41 // clang-format off 42 /* 43 * [SMDOC] Environment Objects 44 * 45 * About environments 46 * ------------------ 47 * 48 * See also: https://tc39.es/ecma262/#sec-environment-records 49 * 50 * Scoping in ES is specified in terms of "Environment Records". There's a 51 * global Environment Record per realm, and a new Environment Record is created 52 * whenever control enters a function, block, or other scope. 53 * 54 * A "Lexical Environment" is a list of nested Environment Records, innermost 55 * first: everything that's in scope. Throughout SpiderMonkey, "environment" 56 * means a Lexical Environment. 57 * 58 * N.B.: "Scope" means something different: a static scope, the compile-time 59 * analogue of an environment. See Scope.h. 60 * 61 * How SpiderMonkey represents environments 62 * ---------------------------------------- 63 * 64 * Some environments are stored as JSObjects. Several kinds of objects 65 * represent environments: 66 * 67 * JSObject 68 * | 69 * +--NativeObject 70 * | | 71 * | +--EnvironmentObject Engine-internal environment 72 * | | | 73 * | | +--CallObject Environment of entire function 74 * | | | 75 * | | +--VarEnvironmentObject See VarScope in Scope.h. 76 * | | | 77 * | | +--(DisposableEnvironmentObject) 78 * | | | | Environment for `using x = ...` 79 * | | | | (exists only when 80 * | | | | ENABLE_EXPLICIT_RESOURCE_MANAGEMENT is 81 * | | | | defined) 82 * | | | | 83 * | | | +--ModuleEnvironmentObject 84 * | | | | 85 * | | | +--LexicalEnvironmentObject 86 * | | | | 87 * | | | +--ScopedLexicalEnvironmentObject 88 * | | | | | Non-extensible lexical environment 89 * | | | | | 90 * | | | | +--BlockLexicalEnvironmentObject 91 * | | | | | | Blocks and such: syntactic, 92 * | | | | | | non-extensible 93 * | | | | | | 94 * | | | | | +--NamedLambdaObject 95 * | | | | | Environment for `(function f(){...})` 96 * | | | | | containing only a binding for `f` 97 * | | | | | 98 * | | | | +--ClassBodyLexicalEnvironmentObject 99 * | | | | Environment for class body, containing 100 * | | | | private names, private brands, and 101 * | | | | static initializers list 102 * | | | | 103 * | | | +--ExtensibleLexicalEnvironmentObject 104 * | | | | 105 * | | | +--GlobalLexicalEnvironmentObject 106 * | | | | Top-level let/const/class in scripts 107 * | | | | 108 * | | | +--NonSyntacticLexicalEnvironmentObject 109 * | | | See "Non-syntactic environments" below 110 * | | | 111 * | | +--NonSyntacticVariablesObject 112 * | | | See "Non-syntactic environments" below 113 * | | | 114 * | | +--WithEnvironmentObject Presents object properties as bindings 115 * | | | 116 * | | +--RuntimeLexicalErrorObject 117 * | | Special value represents uninitialized 118 * | | lexical slots 119 * | | 120 * | +--GlobalObject The global environment (dynamically 121 * | presents its properties as bindings) 122 * +--ProxyObject 123 * | 124 * +--DebugEnvironmentProxy Environment for debugger eval-in-frame 125 * 126 * EnvironmentObjects are technically real JSObjects but only belong on the 127 * environment chain (that is, fp->environmentChain() or fun->environment()). 128 * They are never exposed to scripts. 129 * 130 * Note that reserved slots in any base classes shown above are fixed for all 131 * derived classes. So e.g. EnvironmentObject::enclosingEnvironment() can 132 * simply access a fixed slot without further dynamic type information. 133 * 134 * When the current environment is represented by an object, the stack frame 135 * has a pointer to that object (see AbstractFramePtr::environmentChain()). 136 * However, that isn't always the case. Where possible, we store binding values 137 * in JS stack slots. For block and function scopes where all bindings can be 138 * stored in stack slots, nothing is allocated in the heap; there is no 139 * environment object. 140 * 141 * Full information about the environment chain is always recoverable: 142 * EnvironmentIter can do it, and we construct a fake environment for debugger 143 * eval-in-frame (see "Debug environment objects" below). 144 * 145 * Syntactic Environments 146 * ---------------------- 147 * 148 * Environments may be syntactic, i.e., corresponding to source text, or 149 * non-syntactic, i.e., specially created by embedding. The distinction is 150 * necessary to maintain invariants about the environment chain: non-syntactic 151 * environments may not occur in arbitrary positions in the chain. 152 * 153 * CallObject, ModuleEnvironmentObject, BlockLexicalEnvironmentObject, and 154 * GlobalLexicalEnvironmentObject always represent syntactic 155 * environments. (CallObject is considered syntactic even when it's used as the 156 * scope of strict eval code.) WithEnvironmentObject is syntactic when it's 157 * used to represent the scope of a `with` block. 158 * 159 * 160 * Non-syntactic Environments 161 * -------------------------- 162 * 163 * A non-syntactic environment is one that was not created due to JS source 164 * code. On the scope chain, a single NonSyntactic GlobalScope maps to 0+ 165 * non-syntactic environment objects. This is contrasted with syntactic 166 * environments, where each scope corresponds to 0 or 1 environment object. 167 * 168 * There are 3 kinds of dynamic environment objects: 169 * 170 * 1. WithEnvironmentObject 171 * 172 * When the embedding compiles or executes a script, it has the option to 173 * pass in a vector of objects to be used as the initial env chain, ordered 174 * from outermost env to innermost env. Each of those objects is wrapped by 175 * a WithEnvironmentObject. 176 * 177 * The innermost object passed in by the embedding becomes a qualified 178 * variables object that captures 'var' bindings. That is, it wraps the 179 * holder object of 'var' bindings. 180 * 181 * Does not hold 'let' or 'const' bindings. 182 * 183 * The embedding can specify whether these non-syntactic WithEnvironment 184 * objects support Symbol.unscopables similar to syntactic 'with' statements 185 * in JS. In Firefox, we support Symbol.unscopables only for DOM event 186 * handlers because this is required by the spec. 187 * 188 * 2. NonSyntacticVariablesObject 189 * 190 * When the embedding wants qualified 'var' bindings and unqualified 191 * bareword assignments to go on a different object than the global 192 * object. While any object can be made into a qualified variables object, 193 * only the GlobalObject and NonSyntacticVariablesObject are considered 194 * unqualified variables objects. 195 * 196 * Unlike WithEnvironmentObjects that delegate to the object they wrap, 197 * this object is itself the holder of 'var' bindings. 198 * 199 * Does not hold 'let' or 'const' bindings. 200 * 201 * 3. NonSyntacticLexicalEnvironmentObject 202 * 203 * Each non-syntactic object used as a qualified variables object needs to 204 * enclose a non-syntactic lexical environment to hold 'let' and 'const' 205 * bindings. There is a bijection per realm between the non-syntactic 206 * variables objects and their non-syntactic LexicalEnvironmentObjects. 207 * 208 * Does not hold 'var' bindings. 209 * 210 * The embedding (Gecko) and debugger uses non-syntactic envs for various 211 * things, all of which are detailed below. All env chain listings below are, 212 * from top to bottom, outermost to innermost. 213 * 214 * A. JSM loading 215 * 216 * Most JSMs are loaded into a shared system global in order to save the memory 217 * consumption and avoid CCWs. To support this, a NonSyntacticVariablesObject 218 * is used for each JSM to provide a basic form of isolation. 219 * NonSyntacticLexicalEnvironmentObject and 220 * NonSyntacticVariablesObject are allocated for each JSM, and 221 * NonSyntacticLexicalEnvironmentObject holds lexical variables and 222 * NonSyntacticVariablesObject holds qualified variables. JSMs cannot have 223 * unqualified names, but if unqualified names are used by subscript, they 224 * goes to NonSyntacticVariablesObject (see C.3 and C.4). 225 * They have the following env chain: 226 * 227 * SystemGlobal 228 * | 229 * GlobalLexicalEnvironmentObject[this=global] 230 * | 231 * NonSyntacticVariablesObject (qualified 'var's (and unqualified names)) 232 * | 233 * NonSyntacticLexicalEnvironmentObject[this=nsvo] (lexical vars) 234 * 235 * B.1. Frame scripts with unique scope 236 * 237 * XUL frame scripts with unique scope are loaded in the same global as 238 * JSMs, with a NonSyntacticVariablesObject as a "polluting global" for 239 * both qualified 'var' variables and unqualified names, and a with 240 * environment wrapping a message manager object, and 241 * NonSyntacticLexicalEnvironmentObject holding the message manager as `this`, 242 * that holds lexical variables. 243 * These environment objects, except for globals, are created for each 244 * execution of js::ExecuteInFrameScriptEnvironment. 245 * 246 * SystemGlobal 247 * | 248 * GlobalLexicalEnvironmentObject[this=global] 249 * | 250 * NonSyntacticVariablesObject (qualified 'var's and unqualified names) 251 * | 252 * WithEnvironmentObject [SupportUnscopables=No] wrapping messageManager 253 * | 254 * NonSyntacticLexicalEnvironmentObject[this=messageManager] (lexical vars) 255 * 256 * B.2. Frame scripts without unique scope 257 * 258 * XUL frame scripts without unique scope are loaded in the same global as 259 * JSMs with JS_ExecuteScript, with a with environment wrapping a message 260 * manager object for qualified 'var' variables, and 261 * NonSyntacticLexicalEnvironmentObject holding the message manager as `this`, 262 * that holds lexical variables. 263 * The environment chain is associated with the message manager object 264 * and cached for subsequent executions. 265 * 266 * SystemGlobal (unqualified names) 267 * | 268 * GlobalLexicalEnvironmentObject[this=global] 269 * | 270 * WithEnvironmentObject [SupportUnscopables=No] wrapping messageManager 271 * (qualified 'var's) 272 * | 273 * NonSyntacticLexicalEnvironmentObject[this=messageManager] (lexical vars) 274 * 275 * C.1 Subscript loading into a target object 276 * 277 * Subscripts may be loaded into a target object and it's associated global. 278 * NonSyntacticLexicalEnvironmentObject holds lexical variables and 279 * WithEnvironmentObject holds qualified variables. Unqualified names goes 280 * to the target object's global. 281 * They have the following env chain: 282 * 283 * Target object's global (unqualified names) 284 * | 285 * GlobalLexicalEnvironmentObject[this=global] 286 * | 287 * WithEnvironmentObject [SupportUnscopables=No] wrapping target 288 * (qualified 'var's) 289 * | 290 * NonSyntacticLexicalEnvironmentObject[this=target] (lexical vars) 291 * 292 * C.2 Subscript loading into global this 293 * 294 * Subscript may be loaded into global this. In this case no extra environment 295 * object is created. 296 * 297 * global (qualified 'var's and unqualified names) 298 * | 299 * GlobalLexicalEnvironmentObject[this=global] (lexical vars) 300 * 301 * C.3 Subscript loading into a target object in JSM 302 * 303 * The target object of a subscript load may be in a JSM, in which case we will 304 * also have the NonSyntacticVariablesObject on the chain. 305 * NonSyntacticLexicalEnvironmentObject for target object holds lexical 306 * variables and WithEnvironmentObject holds qualified variables. 307 * Unqualified names goes to NonSyntacticVariablesObject. 308 * 309 * SystemGlobal 310 * | 311 * GlobalLexicalEnvironmentObject[this=global] 312 * | 313 * NonSyntacticVariablesObject (unqualified names) 314 * | 315 * NonSyntacticLexicalEnvironmentObject[this=nsvo] 316 * | 317 * WithEnvironmentObject [SupportUnscopables=No] wrapping target 318 * (qualified 'var's) 319 * | 320 * NonSyntacticLexicalEnvironmentObject[this=target] (lexical vars) 321 * 322 * C.4 Subscript loading into per-JSM this 323 * 324 * Subscript may be loaded into global this. In this case no extra environment 325 * object is created. 326 * 327 * SystemGlobal 328 * | 329 * GlobalLexicalEnvironmentObject[this=global] 330 * | 331 * NonSyntacticVariablesObject (qualified 'var's and unqualified names) 332 * | 333 * NonSyntacticLexicalEnvironmentObject[this=nsvo] (lexical vars) 334 * 335 * C.5. Subscript loading into a target object in a frame script with unique 336 * scope 337 * 338 * Subscript may be loaded into a target object inside a frame script 339 * environment. If the frame script has an unique scope, the subscript inherits 340 * the unique scope, with additional WithEnvironmentObject and NSLEO are 341 * created for qualified variables. 342 * 343 * SystemGlobal 344 * | 345 * GlobalLexicalEnvironmentObject[this=global] 346 * | 347 * NonSyntacticVariablesObject (unqualified names) 348 * | 349 * WithEnvironmentObject [SupportUnscopables=No] wrapping messageManager 350 * | 351 * NonSyntacticLexicalEnvironmentObject[this=messageManager] 352 * | 353 * WithEnvironmentObject [SupportUnscopables=No] wrapping target 354 * (qualified 'var's) 355 * | 356 * NonSyntacticLexicalEnvironmentObject[this=target] (lexical vars) 357 * 358 * C.6. Subscript loading into a target object in a frame script without unique 359 * scope 360 * 361 * If the frame script doesn't have an unique scope, the subscript uses the 362 * global scope, with additional WithEnvironmentObject and NSLEO are 363 * created for qualified variables. 364 * 365 * SystemGlobal (unqualified names) 366 * | 367 * GlobalLexicalEnvironmentObject[this=global] 368 * | 369 * WithEnvironmentObject [SupportUnscopables=No] wrapping target 370 * (qualified 'var's) 371 * | 372 * NonSyntacticLexicalEnvironmentObject[this=target] (lexical vars) 373 * 374 * C.7. Subscript loading into a frame script with unique scope 375 * 376 * If a subscript doesn't use a target object and the frame script has an 377 * unique scope, the subscript uses the same environment as the frame script. 378 * 379 * SystemGlobal 380 * | 381 * GlobalLexicalEnvironmentObject[this=global] 382 * | 383 * NonSyntacticVariablesObject (qualified 'var's and unqualified names) 384 * | 385 * WithEnvironmentObject [SupportUnscopables=No] wrapping messageManager 386 * | 387 * NonSyntacticLexicalEnvironmentObject[this=messageManager] (lexical vars) 388 * 389 * C.8. Subscript loading into a frame script without unique scope 390 * 391 * If a subscript doesn't use a target object and the frame script doesn't have 392 * an unique scope, the subscript uses the global scope. 393 * 394 * SystemGlobal (qualified 'var's and unqualified names) 395 * | 396 * GlobalLexicalEnvironmentObject[this=global] (lexical vars) 397 * 398 * D.1. DOM event handlers without direct eval 399 * 400 * DOM event handlers are compiled as functions with HTML elements on the 401 * environment chain. For a chain of elements e0, e1, ..., eN, where innerrmost 402 * element is the target element, enclosing elements are such as forms, and the 403 * outermost one is the document. 404 * If the DOM event handlers don't have direct eval, the function's scopes are 405 * optimized and frame slots are used for qualified 'var's and lexical vars. 406 * NonSyntacticLexicalEnvironmentObject's `this` value is not used, given 407 * the function's `this` value is used instead: 408 * 409 * global (unqualified names) 410 * | 411 * GlobalLexicalEnvironmentObject[this=global] 412 * | 413 * WithEnvironmentObject [SupportUnscopables=Yes] wrapping eN 414 * | 415 * ... 416 * | 417 * WithEnvironmentObject [SupportUnscopables=Yes] wrapping e1 418 * | 419 * WithEnvironmentObject [SupportUnscopables=Yes] wrapping e0 420 * | 421 * NonSyntacticLexicalEnvironmentObject [this=*unused*] 422 * 423 * D.2. DOM event handlers with direct eval 424 * 425 * If DOM event handlers have direct eval, the function's scopes are allocated 426 * as environment object: 427 * 428 * global (unqualified names) 429 * | 430 * GlobalLexicalEnvironmentObject[this=global] 431 * | 432 * ... 433 * | 434 * WithEnvironmentObject [SupportUnscopables=Yes] wrapping e1 435 * | 436 * WithEnvironmentObject [SupportUnscopables=Yes] wrapping e0 437 * | 438 * NonSyntacticLexicalEnvironmentObject [this=*unused*] 439 * | 440 * CallObject (qualified 'var's) 441 * | 442 * BlockLexicalEnvironmentObject (lexical vars) 443 * 444 * E.1. Debugger.Frame.prototype.evalWithBindings 445 * 446 * Debugger.Frame.prototype.evalWithBindings uses WithEnvironmentObject for 447 * given bindings, and the frame's enclosing scope. 448 * 449 * If qualified 'var's or unqualified names conflict with the bindings object's 450 * properties, they go to the WithEnvironmentObject. 451 * 452 * If the frame is function, it has the following env chain. 453 * lexical variables are optimized and uses frame slots, regardless of the name 454 * conflicts with bindings: 455 * 456 * global (unqualified names) 457 * | 458 * [DebugProxy] GlobalLexicalEnvironmentObject[this=global] 459 * | 460 * [DebugProxy] CallObject (qualified 'var's) 461 * | 462 * WithEnvironmentObject [SupportUnscopables=No] wrapping bindings 463 * (conflicting 'var's and names) 464 * 465 * If the script has direct eval, BlockLexicalEnvironmentObject is created for 466 * it: 467 * 468 * global (unqualified names) 469 * | 470 * [DebugProxy] GlobalLexicalEnvironmentObject[this=global] 471 * | 472 * [DebugProxy] CallObject (qualified 'var's) 473 * | 474 * WithEnvironmentObject [SupportUnscopables=No] wrapping bindings 475 * (conflicting 'var's and names) 476 * | 477 * BlockLexicalEnvironmentObject (lexical vars, and conflicting lexical vars) 478 * 479 * NOTE: Debugger.Frame.prototype.eval uses the frame's enclosing scope only, 480 * and it doesn't use any dynamic environment, but still uses 481 * non-syntactic scope to perform `eval` operation. 482 * 483 * E.2. Debugger.Object.prototype.executeInGlobalWithBindings 484 * 485 * Debugger.Object.prototype.executeInGlobalWithBindings uses 486 * WithEnvironmentObject for given bindings, and the object's global scope. 487 * 488 * If `options.useInnerBindings` is not true, if bindings conflict with 489 * qualified 'var's or global lexicals, those bindings are shadowed and not 490 * stored into the bindings object wrapped by WithEnvironmentObject. 491 * 492 * global (qualified 'var's and unqualified names) 493 * | 494 * GlobalLexicalEnvironmentObject[this=global] (lexical vars) 495 * | 496 * WithEnvironmentObject [SupportUnscopables=No] wrapping object with 497 * not-conflicting bindings 498 * 499 * If `options.useInnerBindings` is true, all bindings are stored into the 500 * bindings object wrapped by WithEnvironmentObject, and they shadow globals 501 * 502 * global (qualified 'var's and unqualified names) 503 * | 504 * GlobalLexicalEnvironmentObject[this=global] (lexical vars) 505 * | 506 * WithEnvironmentObject [SupportUnscopables=No] wrapping object with all 507 * bindings 508 * 509 * NOTE: If `options.useInnerBindings` is true, and if lexical variable names 510 * conflict with the bindings object's properties, the write on them 511 * within declarations is done for the GlobalLexicalEnvironmentObject, 512 * but the write within assignments and the read on lexicals are done 513 * from the WithEnvironmentObject (bug 1841964 and bug 1847219). 514 * 515 * // bindings = { x: 10, y: 20 }; 516 * 517 * let x = 11; // written to GlobalLexicalEnvironmentObject 518 * x; // read from WithEnvironmentObject 519 * let y; 520 * y = 21; // written to WithEnvironmentObject 521 * y; // read from WithEnvironmentObject 522 * 523 * NOTE: Debugger.Object.prototype.executeInGlobal uses the object's global 524 * scope only, and it doesn't use any dynamic environment or 525 * non-syntactic scope. 526 * NOTE: If no extra bindings are used by script, 527 * Debugger.Object.prototype.executeInGlobalWithBindings uses the object's 528 * global scope only, and it doesn't use any dynamic environment or 529 * non-syntactic scope. 530 * 531 */ 532 // clang-format on 533 534 class EnvironmentObject : public NativeObject { 535 protected: 536 // The enclosing environment. Either another EnvironmentObject, a 537 // GlobalObject, or a non-syntactic environment object. 538 static const uint32_t ENCLOSING_ENV_SLOT = 0; 539 540 inline void setAliasedBinding(uint32_t slot, const Value& v); 541 542 public: 543 // Since every env chain terminates with a global object, whether 544 // GlobalObject or a non-syntactic one, and since those objects do not 545 // derive EnvironmentObject (they have completely different layouts), the 546 // enclosing environment of an EnvironmentObject is necessarily non-null. 547 JSObject& enclosingEnvironment() const { 548 return getReservedSlot(ENCLOSING_ENV_SLOT).toObject(); 549 } 550 551 void initEnclosingEnvironment(JSObject* enclosing) { 552 initReservedSlot(ENCLOSING_ENV_SLOT, ObjectOrNullValue(enclosing)); 553 } 554 555 static bool nonExtensibleIsFixedSlot(EnvironmentCoordinate ec) { 556 // For non-extensible environment objects isFixedSlot(slot) is equivalent to 557 // slot < MAX_FIXED_SLOTS. 558 return ec.slot() < MAX_FIXED_SLOTS; 559 } 560 static size_t nonExtensibleDynamicSlotIndex(EnvironmentCoordinate ec) { 561 MOZ_ASSERT(!nonExtensibleIsFixedSlot(ec)); 562 return ec.slot() - MAX_FIXED_SLOTS; 563 } 564 565 // Get or set a name contained in this environment. 566 inline const Value& aliasedBinding(EnvironmentCoordinate ec); 567 568 const Value& aliasedBinding(const BindingIter& bi) { 569 MOZ_ASSERT(bi.location().kind() == BindingLocation::Kind::Environment); 570 return getSlot(bi.location().slot()); 571 } 572 573 inline void setAliasedBinding(EnvironmentCoordinate ec, const Value& v); 574 575 inline void setAliasedBinding(const BindingIter& bi, const Value& v); 576 577 // For JITs. 578 static size_t offsetOfEnclosingEnvironment() { 579 return getFixedSlotOffset(ENCLOSING_ENV_SLOT); 580 } 581 582 static uint32_t enclosingEnvironmentSlot() { return ENCLOSING_ENV_SLOT; } 583 584 const char* typeString() const; 585 586 #if defined(DEBUG) || defined(JS_JITSPEW) 587 void dump(); 588 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */ 589 }; 590 591 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 592 class DisposableEnvironmentObject : public EnvironmentObject { 593 protected: 594 static constexpr uint32_t DISPOSABLE_RESOURCE_STACK_SLOT = 1; 595 596 public: 597 static constexpr uint32_t RESERVED_SLOTS = 2; 598 599 ArrayObject* getOrCreateDisposeCapability(JSContext* cx); 600 601 // Used to get the Disposable objects within the 602 // lexical scope, it returns a ArrayObject if there 603 // is a non empty list of Disposables, else 604 // UndefinedValue. 605 JS::Value getDisposables(); 606 607 void clearDisposables(); 608 609 // For JITs 610 static size_t offsetOfDisposeCapability() { 611 return getFixedSlotOffset(DISPOSABLE_RESOURCE_STACK_SLOT); 612 } 613 }; 614 #endif 615 616 class CallObject : public EnvironmentObject { 617 protected: 618 static constexpr uint32_t CALLEE_SLOT = 1; 619 620 static CallObject* create(JSContext* cx, HandleScript script, 621 HandleObject enclosing, gc::Heap heap, 622 gc::AllocSite* site = nullptr); 623 624 public: 625 static const JSClass class_; 626 627 static constexpr uint32_t RESERVED_SLOTS = 2; 628 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::QualifiedVarObj}; 629 630 /* These functions are internal and are exposed only for JITs. */ 631 632 /* 633 * Construct a bare-bones call object given a shape. 634 * The call object must be further initialized to be usable. 635 */ 636 static CallObject* createWithShape(JSContext* cx, Handle<SharedShape*> shape, 637 gc::Heap heap = gc::Heap::Default); 638 639 static CallObject* createTemplateObject(JSContext* cx, HandleScript script, 640 HandleObject enclosing); 641 642 static CallObject* createForFrame(JSContext* cx, AbstractFramePtr frame, 643 gc::AllocSite* site); 644 645 static CallObject* createHollowForDebug(JSContext* cx, HandleFunction callee); 646 647 // If `env` or any enclosing environment is a CallObject, return that 648 // CallObject; else null. 649 // 650 // `env` may be a DebugEnvironmentProxy, but not a hollow environment. 651 static CallObject* find(JSObject* env); 652 653 /* 654 * When an aliased formal (var accessed by nested closures) is also 655 * aliased by the arguments object, it must of course exist in one 656 * canonical location and that location is always the CallObject. For this 657 * to work, the ArgumentsObject stores special MagicValue in its array for 658 * forwarded-to-CallObject variables. This MagicValue's payload is the 659 * slot of the CallObject to access. 660 */ 661 const Value& aliasedFormalFromArguments(const Value& argsValue) { 662 return getSlot(ArgumentsObject::SlotFromMagicScopeSlotValue(argsValue)); 663 } 664 inline void setAliasedFormalFromArguments(const Value& argsValue, 665 const Value& v); 666 667 JSFunction& callee() const { 668 return getReservedSlot(CALLEE_SLOT).toObject().as<JSFunction>(); 669 } 670 671 /* For jit access. */ 672 static size_t offsetOfCallee() { return getFixedSlotOffset(CALLEE_SLOT); } 673 674 static size_t calleeSlot() { return CALLEE_SLOT; } 675 }; 676 677 class VarEnvironmentObject : public EnvironmentObject { 678 static constexpr uint32_t SCOPE_SLOT = 1; 679 680 static VarEnvironmentObject* createInternal(JSContext* cx, 681 Handle<SharedShape*> shape, 682 HandleObject enclosing, 683 gc::Heap heap); 684 685 static VarEnvironmentObject* create(JSContext* cx, Handle<Scope*> scope, 686 HandleObject enclosing, gc::Heap heap); 687 688 void initScope(Scope* scope) { 689 initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope)); 690 } 691 692 public: 693 static const JSClass class_; 694 695 static constexpr uint32_t RESERVED_SLOTS = 2; 696 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::QualifiedVarObj}; 697 698 static VarEnvironmentObject* createForFrame(JSContext* cx, 699 Handle<Scope*> scope, 700 AbstractFramePtr frame); 701 static VarEnvironmentObject* createHollowForDebug(JSContext* cx, 702 Handle<Scope*> scope); 703 static VarEnvironmentObject* createTemplateObject(JSContext* cx, 704 Handle<VarScope*> scope); 705 static VarEnvironmentObject* createWithoutEnclosing(JSContext* cx, 706 Handle<VarScope*> scope); 707 708 Scope& scope() const { 709 Value v = getReservedSlot(SCOPE_SLOT); 710 MOZ_ASSERT(v.isPrivateGCThing()); 711 Scope& s = *static_cast<Scope*>(v.toGCThing()); 712 MOZ_ASSERT(s.is<VarScope>() || s.is<EvalScope>()); 713 return s; 714 } 715 716 bool isForEval() const { return scope().is<EvalScope>(); } 717 bool isForNonStrictEval() const { return scope().kind() == ScopeKind::Eval; } 718 }; 719 720 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 721 class ModuleEnvironmentObject : public DisposableEnvironmentObject { 722 #else 723 class ModuleEnvironmentObject : public EnvironmentObject { 724 #endif 725 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 726 static constexpr uint32_t MODULE_SLOT = 727 DisposableEnvironmentObject::RESERVED_SLOTS; 728 #else 729 static constexpr uint32_t MODULE_SLOT = 1; 730 #endif 731 732 static const ObjectOps objectOps_; 733 static const JSClassOps classOps_; 734 735 public: 736 using EnvironmentObject::setAliasedBinding; 737 738 static const JSClass class_; 739 740 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 741 // While there are only 3 reserved slots, this needs to be set to 4, given 742 // there are some code expect the number of fixed slot to be same as the 743 // number of reserved slots for the lexical environments (bug 1913864). 744 static constexpr uint32_t RESERVED_SLOTS = 745 DisposableEnvironmentObject::RESERVED_SLOTS + 2; 746 #else 747 static constexpr uint32_t RESERVED_SLOTS = 2; 748 #endif 749 750 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible, 751 ObjectFlag::QualifiedVarObj}; 752 753 static ModuleEnvironmentObject* create(JSContext* cx, 754 Handle<ModuleObject*> module); 755 static ModuleEnvironmentObject* createSynthetic(JSContext* cx, 756 Handle<ModuleObject*> module); 757 758 ModuleObject& module() const; 759 IndirectBindingMap& importBindings() const; 760 761 bool createImportBinding(JSContext* cx, Handle<JSAtom*> importName, 762 Handle<ModuleObject*> module, 763 Handle<JSAtom*> exportName); 764 765 bool hasImportBinding(Handle<PropertyName*> name); 766 767 bool lookupImport(jsid name, ModuleEnvironmentObject** envOut, 768 mozilla::Maybe<PropertyInfo>* propOut); 769 770 // If `env` or any enclosing environment is a ModuleEnvironmentObject, 771 // return that ModuleEnvironmentObject; else null. 772 // 773 // `env` may be a DebugEnvironmentProxy, but not a hollow environment. 774 static ModuleEnvironmentObject* find(JSObject* env); 775 776 uint32_t firstSyntheticValueSlot() { return RESERVED_SLOTS; } 777 778 private: 779 static bool lookupProperty(JSContext* cx, HandleObject obj, HandleId id, 780 MutableHandleObject objp, PropertyResult* propp); 781 static bool hasProperty(JSContext* cx, HandleObject obj, HandleId id, 782 bool* foundp); 783 static bool getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, 784 HandleId id, MutableHandleValue vp); 785 static bool setProperty(JSContext* cx, HandleObject obj, HandleId id, 786 HandleValue v, HandleValue receiver, 787 JS::ObjectOpResult& result); 788 static bool getOwnPropertyDescriptor( 789 JSContext* cx, HandleObject obj, HandleId id, 790 MutableHandle<mozilla::Maybe<PropertyDescriptor>> desc); 791 static bool deleteProperty(JSContext* cx, HandleObject obj, HandleId id, 792 ObjectOpResult& result); 793 static bool newEnumerate(JSContext* cx, HandleObject obj, 794 MutableHandleIdVector properties, 795 bool enumerableOnly); 796 }; 797 798 class WasmInstanceEnvironmentObject : public EnvironmentObject { 799 // Currently WasmInstanceScopes do not use their scopes in a 800 // meaningful way. However, it is an invariant of DebugEnvironments that 801 // environments kept in those maps have live scopes, thus this strong 802 // reference. 803 static constexpr uint32_t SCOPE_SLOT = 1; 804 805 public: 806 static const JSClass class_; 807 808 static constexpr uint32_t RESERVED_SLOTS = 2; 809 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible}; 810 811 static WasmInstanceEnvironmentObject* createHollowForDebug( 812 JSContext* cx, Handle<WasmInstanceScope*> scope); 813 WasmInstanceScope& scope() const { 814 Value v = getReservedSlot(SCOPE_SLOT); 815 MOZ_ASSERT(v.isPrivateGCThing()); 816 return *static_cast<WasmInstanceScope*>(v.toGCThing()); 817 } 818 }; 819 820 class WasmFunctionCallObject : public EnvironmentObject { 821 // Currently WasmFunctionCallObjects do not use their scopes in a 822 // meaningful way. However, it is an invariant of DebugEnvironments that 823 // environments kept in those maps have live scopes, thus this strong 824 // reference. 825 static constexpr uint32_t SCOPE_SLOT = 1; 826 827 public: 828 static const JSClass class_; 829 830 // TODO Check what Debugger behavior should be when it evaluates a 831 // var declaration. 832 static constexpr uint32_t RESERVED_SLOTS = 2; 833 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible}; 834 835 static WasmFunctionCallObject* createHollowForDebug( 836 JSContext* cx, HandleObject enclosing, Handle<WasmFunctionScope*> scope); 837 WasmFunctionScope& scope() const { 838 Value v = getReservedSlot(SCOPE_SLOT); 839 MOZ_ASSERT(v.isPrivateGCThing()); 840 return *static_cast<WasmFunctionScope*>(v.toGCThing()); 841 } 842 }; 843 844 // Abstract base class for environments that can contain let/const bindings, 845 // plus a few other kinds of environments, such as `catch` blocks, that have 846 // similar behavior. 847 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 848 class LexicalEnvironmentObject : public DisposableEnvironmentObject { 849 #else 850 class LexicalEnvironmentObject : public EnvironmentObject { 851 #endif 852 protected: 853 // Global and non-syntactic lexical environments need to store a 'this' 854 // object and all other lexical environments have a fixed shape and store a 855 // backpointer to the LexicalScope. 856 // 857 // Since the two sets are disjoint, we only use one slot to save space. 858 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 859 static constexpr uint32_t THIS_VALUE_OR_SCOPE_SLOT = 860 DisposableEnvironmentObject::RESERVED_SLOTS; 861 #else 862 static constexpr uint32_t THIS_VALUE_OR_SCOPE_SLOT = 1; 863 #endif 864 865 public: 866 static const JSClass class_; 867 868 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 869 // See comment on RESERVED_SLOTS in ModuleEnvironmentObject. 870 static constexpr uint32_t RESERVED_SLOTS = 871 DisposableEnvironmentObject::RESERVED_SLOTS + 2; 872 #else 873 static constexpr uint32_t RESERVED_SLOTS = 2; 874 #endif 875 876 protected: 877 static LexicalEnvironmentObject* create(JSContext* cx, 878 Handle<SharedShape*> shape, 879 HandleObject enclosing, gc::Heap heap, 880 gc::AllocSite* site = nullptr); 881 882 public: 883 // Is this the global lexical scope? 884 bool isGlobal() const { return enclosingEnvironment().is<GlobalObject>(); } 885 886 // Global and non-syntactic lexical scopes are extensible. All other 887 // lexical scopes are not. 888 bool isExtensible() const; 889 890 // Is this a syntactic (i.e. corresponds to a source text) lexical 891 // environment? 892 bool isSyntactic() const { return !isExtensible() || isGlobal(); } 893 }; 894 895 // A non-extensible lexical environment. 896 // 897 // Used for blocks (ScopeKind::Lexical) and several other scope kinds, 898 // including Catch, NamedLambda, FunctionLexical, and ClassBody. 899 class ScopedLexicalEnvironmentObject : public LexicalEnvironmentObject { 900 public: 901 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible}; 902 903 Scope& scope() const { 904 Value v = getReservedSlot(THIS_VALUE_OR_SCOPE_SLOT); 905 MOZ_ASSERT(!isExtensible() && v.isPrivateGCThing()); 906 return *static_cast<Scope*>(v.toGCThing()); 907 } 908 909 bool isClassBody() const { return scope().kind() == ScopeKind::ClassBody; } 910 911 void initScope(Scope* scope) { 912 initReservedSlot(THIS_VALUE_OR_SCOPE_SLOT, PrivateGCThingValue(scope)); 913 } 914 }; 915 916 class BlockLexicalEnvironmentObject : public ScopedLexicalEnvironmentObject { 917 protected: 918 static BlockLexicalEnvironmentObject* create(JSContext* cx, 919 Handle<LexicalScope*> scope, 920 HandleObject enclosing, 921 gc::Heap heap, 922 gc::AllocSite* site = nullptr); 923 924 public: 925 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible}; 926 927 static BlockLexicalEnvironmentObject* createForFrame( 928 JSContext* cx, Handle<LexicalScope*> scope, AbstractFramePtr frame); 929 930 static BlockLexicalEnvironmentObject* createHollowForDebug( 931 JSContext* cx, Handle<LexicalScope*> scope); 932 933 static BlockLexicalEnvironmentObject* createTemplateObject( 934 JSContext* cx, Handle<LexicalScope*> scope); 935 936 static BlockLexicalEnvironmentObject* createWithoutEnclosing( 937 JSContext* cx, Handle<LexicalScope*> scope); 938 939 // Create a new BlockLexicalEnvironmentObject with the same enclosing env and 940 // variable values as this. 941 static BlockLexicalEnvironmentObject* clone( 942 JSContext* cx, Handle<BlockLexicalEnvironmentObject*> env); 943 944 // Create a new BlockLexicalEnvironmentObject with the same enclosing env as 945 // this, with all variables uninitialized. 946 static BlockLexicalEnvironmentObject* recreate( 947 JSContext* cx, Handle<BlockLexicalEnvironmentObject*> env); 948 949 // The LexicalScope that created this environment. 950 LexicalScope& scope() const { 951 return ScopedLexicalEnvironmentObject::scope().as<LexicalScope>(); 952 } 953 }; 954 955 class NamedLambdaObject : public BlockLexicalEnvironmentObject { 956 static NamedLambdaObject* create(JSContext* cx, HandleFunction callee, 957 HandleObject enclosing, gc::Heap heap, 958 gc::AllocSite* site = nullptr); 959 960 public: 961 static NamedLambdaObject* createTemplateObject(JSContext* cx, 962 HandleFunction callee); 963 964 static NamedLambdaObject* createWithoutEnclosing(JSContext* cx, 965 HandleFunction callee, 966 gc::Heap heap); 967 968 static NamedLambdaObject* createForFrame(JSContext* cx, 969 AbstractFramePtr frame, 970 gc::AllocSite* site); 971 972 // For JITs. 973 static size_t lambdaSlot(); 974 975 static size_t offsetOfLambdaSlot() { 976 return getFixedSlotOffset(lambdaSlot()); 977 } 978 }; 979 980 class ClassBodyLexicalEnvironmentObject 981 : public ScopedLexicalEnvironmentObject { 982 static ClassBodyLexicalEnvironmentObject* create( 983 JSContext* cx, Handle<ClassBodyScope*> scope, HandleObject enclosing, 984 gc::Heap heap); 985 986 public: 987 static ClassBodyLexicalEnvironmentObject* createForFrame( 988 JSContext* cx, Handle<ClassBodyScope*> scope, AbstractFramePtr frame); 989 990 static ClassBodyLexicalEnvironmentObject* createTemplateObject( 991 JSContext* cx, Handle<ClassBodyScope*> scope); 992 993 static ClassBodyLexicalEnvironmentObject* createWithoutEnclosing( 994 JSContext* cx, Handle<ClassBodyScope*> scope); 995 996 // The ClassBodyScope that created this environment. 997 ClassBodyScope& scope() const { 998 return ScopedLexicalEnvironmentObject::scope().as<ClassBodyScope>(); 999 } 1000 1001 static uint32_t privateBrandSlot() { return JSSLOT_FREE(&class_); } 1002 }; 1003 1004 /* 1005 * Prepare a |this| object to be returned to script. This includes replacing 1006 * Windows with their corresponding WindowProxy. 1007 */ 1008 JSObject* GetThisObject(JSObject* obj); 1009 1010 // Global and non-syntactic lexical environments are extensible. 1011 class ExtensibleLexicalEnvironmentObject : public LexicalEnvironmentObject { 1012 public: 1013 JSObject* thisObject() const; 1014 1015 // For a given global object or JSMEnvironment `obj`, return the associated 1016 // global lexical or non-syntactic lexical environment, where top-level `let` 1017 // bindings are added. 1018 static ExtensibleLexicalEnvironmentObject* forVarEnvironment(JSObject* obj); 1019 1020 protected: 1021 void initThisObject(JSObject* obj) { 1022 MOZ_ASSERT(isGlobal() || !isSyntactic()); 1023 JSObject* thisObj = GetThisObject(obj); 1024 initReservedSlot(THIS_VALUE_OR_SCOPE_SLOT, ObjectValue(*thisObj)); 1025 } 1026 }; 1027 1028 // The global lexical environment, where global let/const/class bindings are 1029 // added. 1030 class GlobalLexicalEnvironmentObject 1031 : public ExtensibleLexicalEnvironmentObject { 1032 public: 1033 static GlobalLexicalEnvironmentObject* create(JSContext* cx, 1034 Handle<GlobalObject*> global); 1035 1036 GlobalObject& global() const { 1037 return enclosingEnvironment().as<GlobalObject>(); 1038 } 1039 1040 void setWindowProxyThisObject(JSObject* obj); 1041 1042 static constexpr size_t offsetOfThisValueSlot() { 1043 return getFixedSlotOffset(THIS_VALUE_OR_SCOPE_SLOT); 1044 } 1045 }; 1046 1047 // Non-standard. See "Non-syntactic Environments" above. 1048 class NonSyntacticLexicalEnvironmentObject 1049 : public ExtensibleLexicalEnvironmentObject { 1050 public: 1051 static NonSyntacticLexicalEnvironmentObject* create(JSContext* cx, 1052 HandleObject enclosing, 1053 HandleObject thisv); 1054 }; 1055 1056 // A non-syntactic dynamic scope object that captures non-lexical 1057 // bindings. That is, a scope object that captures both qualified var 1058 // assignments and unqualified bareword assignments. Its parent is always the 1059 // global lexical environment. 1060 // 1061 // See the long "Non-syntactic Environments" comment above. 1062 class NonSyntacticVariablesObject : public EnvironmentObject { 1063 public: 1064 static const JSClass class_; 1065 1066 static constexpr uint32_t RESERVED_SLOTS = 1; 1067 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::QualifiedVarObj}; 1068 1069 static NonSyntacticVariablesObject* create(JSContext* cx); 1070 }; 1071 1072 NonSyntacticLexicalEnvironmentObject* CreateNonSyntacticEnvironmentChain( 1073 JSContext* cx, const JS::EnvironmentChain& envChain); 1074 1075 // With environment objects on the run-time environment chain. 1076 class WithEnvironmentObject : public EnvironmentObject { 1077 static constexpr uint32_t OBJECT_SLOT = 1; 1078 static constexpr uint32_t THIS_SLOT = 2; 1079 // For syntactic with-environments this slot stores the js::Scope*. 1080 // For non-syntactic with-environments it stores a boolean indicating whether 1081 // we need to look up and use Symbol.unscopables. 1082 static constexpr uint32_t SCOPE_OR_SUPPORT_UNSCOPABLES_SLOT = 3; 1083 1084 public: 1085 static const JSClass class_; 1086 1087 static constexpr uint32_t RESERVED_SLOTS = 4; 1088 static constexpr ObjectFlags OBJECT_FLAGS = {}; 1089 1090 static WithEnvironmentObject* create( 1091 JSContext* cx, HandleObject object, HandleObject enclosing, 1092 Handle<WithScope*> scope, JS::SupportUnscopables supportUnscopables); 1093 static WithEnvironmentObject* createNonSyntactic( 1094 JSContext* cx, HandleObject object, HandleObject enclosing, 1095 JS::SupportUnscopables supportUnscopables); 1096 1097 /* Return the 'o' in 'with (o)'. */ 1098 JSObject& object() const; 1099 1100 /* Return object for GetThisValue. */ 1101 JSObject* withThis() const; 1102 1103 /* 1104 * Return whether this object is a syntactic with object. If not, this is 1105 * a With object we inserted between the outermost syntactic scope and the 1106 * global object to wrap the environment chain someone explicitly passed 1107 * via JSAPI to CompileFunction or script evaluation. 1108 */ 1109 bool isSyntactic() const; 1110 1111 // Whether Symbol.unscopables must be supported for this with-environment. 1112 // This always returns true for syntactic with-environments. 1113 bool supportUnscopables() const; 1114 1115 // For syntactic with environment objects, the with scope. 1116 WithScope& scope() const; 1117 1118 static constexpr size_t objectSlot() { return OBJECT_SLOT; } 1119 1120 static constexpr size_t thisSlot() { return THIS_SLOT; } 1121 1122 // For JITs. 1123 static constexpr size_t offsetOfThisSlot() { 1124 return getFixedSlotOffset(THIS_SLOT); 1125 } 1126 }; 1127 1128 // Internal environment object used by JSOp::BindUnqualifiedName upon 1129 // encountering an uninitialized lexical slot or an assignment to a 'const' 1130 // binding. 1131 // 1132 // ES6 lexical bindings cannot be accessed in any way (throwing 1133 // ReferenceErrors) until initialized. Normally, NAME operations 1134 // unconditionally check for uninitialized lexical slots. When getting or 1135 // looking up names, this can be done without slowing down normal operations 1136 // on the return value. When setting names, however, we do not want to pollute 1137 // all set-property paths with uninitialized lexical checks. For setting names 1138 // (i.e. JSOp::SetName), we emit an accompanying, preceding 1139 // JSOp::BindUnqualifiedName which finds the right scope on which to set the 1140 // name. Moreover, when the name on the scope is an uninitialized lexical, we 1141 // cannot throw eagerly, as the spec demands that the error be thrown after 1142 // evaluating the RHS of assignments. Instead, this sentinel scope object is 1143 // pushed on the stack. Attempting to access anything on this scope throws the 1144 // appropriate ReferenceError. 1145 // 1146 // ES6 'const' bindings induce a runtime error when assigned to outside 1147 // of initialization, regardless of strictness. 1148 class RuntimeLexicalErrorObject : public EnvironmentObject { 1149 static const unsigned ERROR_SLOT = 1; 1150 1151 public: 1152 static const unsigned RESERVED_SLOTS = 2; 1153 static const JSClass class_; 1154 1155 static RuntimeLexicalErrorObject* create(JSContext* cx, 1156 HandleObject enclosing, 1157 unsigned errorNumber); 1158 1159 unsigned errorNumber() { return getReservedSlot(ERROR_SLOT).toInt32(); } 1160 }; 1161 1162 /****************************************************************************/ 1163 1164 // A environment iterator describes the active environments starting from an 1165 // environment, scope pair. This pair may be derived from the current point of 1166 // execution in a frame. If derived in such a fashion, the EnvironmentIter 1167 // tracks whether the current scope is within the extent of this initial 1168 // frame. Here, "frame" means a single activation of: a function, eval, or 1169 // global code. 1170 class MOZ_RAII EnvironmentIter { 1171 Rooted<ScopeIter> si_; 1172 RootedObject env_; 1173 AbstractFramePtr frame_; 1174 1175 void incrementScopeIter(); 1176 void settle(); 1177 1178 // No value semantics. 1179 EnvironmentIter(const EnvironmentIter& ei) = delete; 1180 1181 public: 1182 // Constructing from a copy of an existing EnvironmentIter. 1183 EnvironmentIter(JSContext* cx, const EnvironmentIter& ei); 1184 1185 // Constructing from an environment, scope pair. All environments 1186 // considered not to be withinInitialFrame, since no frame is given. 1187 EnvironmentIter(JSContext* cx, JSObject* env, Scope* scope); 1188 1189 // Constructing from a frame. Places the EnvironmentIter on the innermost 1190 // environment at pc. 1191 EnvironmentIter(JSContext* cx, AbstractFramePtr frame, const jsbytecode* pc); 1192 1193 // Constructing from an environment, scope and frame. The frame is given 1194 // to initialize to proper enclosing environment/scope. 1195 EnvironmentIter(JSContext* cx, JSObject* env, Scope* scope, 1196 AbstractFramePtr frame); 1197 1198 bool done() const { return si_.done(); } 1199 1200 explicit operator bool() const { return !done(); } 1201 1202 void operator++(int) { 1203 if (hasAnyEnvironmentObject()) { 1204 env_ = &env_->as<EnvironmentObject>().enclosingEnvironment(); 1205 } 1206 incrementScopeIter(); 1207 settle(); 1208 } 1209 1210 EnvironmentIter& operator++() { 1211 operator++(1); 1212 return *this; 1213 } 1214 1215 // If done(): 1216 JSObject& enclosingEnvironment() const; 1217 1218 // If !done(): 1219 bool hasNonSyntacticEnvironmentObject() const; 1220 1221 bool hasSyntacticEnvironment() const { return si_.hasSyntacticEnvironment(); } 1222 1223 bool hasAnyEnvironmentObject() const { 1224 return hasNonSyntacticEnvironmentObject() || hasSyntacticEnvironment(); 1225 } 1226 1227 EnvironmentObject& environment() const { 1228 MOZ_ASSERT(hasAnyEnvironmentObject()); 1229 return env_->as<EnvironmentObject>(); 1230 } 1231 1232 Scope& scope() const { return *si_.scope(); } 1233 1234 Scope* maybeScope() const { 1235 if (si_) { 1236 return si_.scope(); 1237 } 1238 return nullptr; 1239 } 1240 1241 JSFunction& callee() const { return env_->as<CallObject>().callee(); } 1242 1243 bool withinInitialFrame() const { return !!frame_; } 1244 1245 AbstractFramePtr initialFrame() const { 1246 MOZ_ASSERT(withinInitialFrame()); 1247 return frame_; 1248 } 1249 1250 AbstractFramePtr maybeInitialFrame() const { return frame_; } 1251 }; 1252 1253 // The key in MissingEnvironmentMap. 1254 // 1255 // * For live frames, maps live frames to their synthesized environments. 1256 // * For completely optimized-out environments, maps the Scope to their 1257 // synthesized environments. 1258 // 1259 // The env we synthesize for Scopes are read-only, but the parent links can be 1260 // used when accessing closed-over bindings held by the enclosing environments. 1261 // Thus these environments need to be distinct for multiple execution for the 1262 // same scope. Otherwise looking up the MissingEnvironmentMap can yield 1263 // the environment for previous execution, which holds different values in the 1264 // variables. 1265 // 1266 // Completely optimized out environments lack the frame, and they can't be 1267 // distinguished by the frame pointers. Note that even if the frame 1268 // corresponding to the Scope is live on the stack, it is unsound to synthesize 1269 // environment from that live frame. 1270 // 1271 // If the frame is missing, the nearestEnvId_ field is used for distinguishing 1272 // the missing environments across multiple executions. 1273 // The nearestEnvId_ field holds the ID of environment object that encloses this 1274 // environment. 1275 // 1276 // The goal of distinguishing the environments is to avoid mixing up the 1277 // variables in these enclosing environments, thus using these environment 1278 // object pointers should be sufficient. 1279 // For example, if there's no enclosing local environment which has an 1280 // environment object, nearestEnvId_ will point to the global environment 1281 // object, and all executions for the same scope will alias, but there's no need 1282 // to distinguish between them. 1283 class DebugEnvironments; 1284 1285 class MissingEnvironmentKey { 1286 friend class LiveEnvironmentVal; 1287 1288 // The corresponding frame for the environment. 1289 // This can be null for function etc. 1290 AbstractFramePtr frame_; 1291 1292 // The corresponding scope for the environment. 1293 // This is shared betwen all executions. 1294 Scope* scope_; 1295 1296 // The ID of the nearest enclosing environment object's DebugEnvironmentProxy 1297 // if any. Used only if frame_ is null, to distinguish between multiple 1298 // execution on the same scope. 1299 uint64_t nearestEnvId_; 1300 1301 public: 1302 MissingEnvironmentKey() 1303 : frame_(NullFramePtr()), scope_(nullptr), nearestEnvId_(0) {} 1304 1305 MissingEnvironmentKey(AbstractFramePtr frame, Scope* scope) 1306 : frame_(frame), scope_(scope), nearestEnvId_(0) { 1307 MOZ_ASSERT(frame); 1308 } 1309 1310 bool initFromEnvironmentIter(JSContext* cx, const EnvironmentIter& ei); 1311 1312 AbstractFramePtr frame() const { return frame_; } 1313 Scope* scope() const { return scope_; } 1314 1315 void updateScope(Scope* scope) { scope_ = scope; } 1316 void updateFrame(AbstractFramePtr frame) { frame_ = frame; } 1317 1318 // For use as hash policy. 1319 using Lookup = MissingEnvironmentKey; 1320 static HashNumber hash(MissingEnvironmentKey sk); 1321 static bool match(MissingEnvironmentKey sk1, MissingEnvironmentKey sk2); 1322 bool operator!=(const MissingEnvironmentKey& other) const { 1323 return frame_ != other.frame_ || nearestEnvId_ != other.nearestEnvId_ || 1324 scope_ != other.scope_; 1325 } 1326 static void rekey(MissingEnvironmentKey& k, 1327 const MissingEnvironmentKey& newKey) { 1328 k = newKey; 1329 } 1330 }; 1331 1332 // The value in LiveEnvironmentMap, mapped from by live environment objects. 1333 class LiveEnvironmentVal { 1334 friend class DebugEnvironments; 1335 friend class MissingEnvironmentKey; 1336 1337 AbstractFramePtr frame_; 1338 HeapPtr<Scope*> scope_; 1339 // See LiveEnvironmentVal::staticAsserts. 1340 uint64_t padding_ = 0; 1341 1342 static void staticAsserts(); 1343 1344 public: 1345 explicit LiveEnvironmentVal(const EnvironmentIter& ei) 1346 : frame_(ei.initialFrame()), scope_(ei.maybeScope()) { 1347 (void)padding_; 1348 } 1349 1350 AbstractFramePtr frame() const { return frame_; } 1351 1352 void updateFrame(AbstractFramePtr frame) { frame_ = frame; } 1353 1354 bool traceWeak(JSTracer* trc); 1355 }; 1356 1357 /****************************************************************************/ 1358 1359 /* 1360 * [SMDOC] Debug environment objects 1361 * 1362 * The frontend optimizes unaliased variables into stack slots and can optimize 1363 * away whole EnvironmentObjects. So when the debugger wants to perform an 1364 * unexpected eval-in-frame (or otherwise access the environment), 1365 * `fp->environmentChain` is often incomplete. This is a problem: a major use 1366 * case for eval-in-frame is to access the local variables in debuggee code. 1367 * 1368 * Even when all EnvironmentObjects exist, giving complete information for all 1369 * bindings, stack and heap, there's another issue: eval-in-frame code can 1370 * create closures that capture stack locals. The variable slots go away when 1371 * the frame is popped, but the closure, which uses them, may survive. 1372 * 1373 * To solve both problems, eval-in-frame code is compiled and run against a 1374 * "debug environment chain" of DebugEnvironmentProxy objects rather than real 1375 * EnvironmentObjects. The `GetDebugEnvironmentFor` functions below create 1376 * these proxies, one to sit in front of each existing EnvironmentObject. They 1377 * also create bogus "hollow" EnvironmentObjects to stand in for environments 1378 * that were optimized away; and proxies for those. The frontend sees these 1379 * environments as something like `with` scopes, and emits deoptimized bytecode 1380 * instructions for all variable accesses. 1381 * 1382 * When eval-in-frame code runs, `fp->environmentChain` points to this chain of 1383 * proxies. On each variable access, the proxy laboriously figures out what to 1384 * do. See e.g. `DebuggerEnvironmentProxyHandler::handleUnaliasedAccess`. 1385 * 1386 * There's a limit to what the proxies can manage, since they're proxying 1387 * environments that are already optimized. Some debugger operations, like 1388 * redefining a lexical binding, can fail when a true direct eval would 1389 * succeed. Even plain variable accesses can throw, if the variable has been 1390 * optimized away. 1391 * 1392 * To support accessing stack variables after they've gone out of scope, we 1393 * copy the variables to the heap as they leave scope. See 1394 * `DebugEnvironments::onPopCall` and `onPopLexical`. 1395 * 1396 * `GetDebugEnvironmentFor*` guarantees that the same DebugEnvironmentProxy is 1397 * always produced for the same underlying environment (optimized or not!). 1398 * This is maintained by some bookkeeping information stored in 1399 * `DebugEnvironments`. 1400 */ 1401 1402 extern JSObject* GetDebugEnvironmentForFunction(JSContext* cx, 1403 HandleFunction fun); 1404 1405 extern JSObject* GetDebugEnvironmentForSuspendedGenerator( 1406 JSContext* cx, JSScript* script, AbstractGeneratorObject& genObj); 1407 1408 extern JSObject* GetDebugEnvironmentForFrame(JSContext* cx, 1409 AbstractFramePtr frame, 1410 jsbytecode* pc); 1411 1412 extern JSObject* GetDebugEnvironmentForGlobalLexicalEnvironment(JSContext* cx); 1413 extern Scope* GetEnvironmentScope(const JSObject& env); 1414 1415 /* Provides debugger access to a environment. */ 1416 class DebugEnvironmentProxy : public ProxyObject { 1417 /* 1418 * The enclosing environment on the dynamic environment chain. This slot is 1419 * analogous to the ENCLOSING_ENV_SLOT of a EnvironmentObject. 1420 */ 1421 static const unsigned ENCLOSING_SLOT = 0; 1422 1423 /* 1424 * NullValue or a dense array holding the unaliased variables of a function 1425 * frame that has been popped. 1426 */ 1427 static const unsigned SNAPSHOT_SLOT = 1; 1428 1429 public: 1430 static DebugEnvironmentProxy* create(JSContext* cx, EnvironmentObject& env, 1431 HandleObject enclosing); 1432 1433 // NOTE: The environment may be a debug hollow with invalid 1434 // enclosingEnvironment. Always use the enclosingEnvironment accessor on 1435 // the DebugEnvironmentProxy in order to walk the environment chain. 1436 EnvironmentObject& environment() const; 1437 JSObject& enclosingEnvironment() const; 1438 1439 // May only be called for proxies to function call objects or modules 1440 // with top-level-await. 1441 ArrayObject* maybeSnapshot() const; 1442 void initSnapshot(ArrayObject& snapshot); 1443 1444 // Currently, the 'declarative' environments are function, module, and 1445 // lexical environments. 1446 bool isForDeclarative() const; 1447 1448 // Get a property by 'id', but returns sentinel values instead of throwing 1449 // on exceptional cases. 1450 static bool getMaybeSentinelValue(JSContext* cx, 1451 Handle<DebugEnvironmentProxy*> env, 1452 HandleId id, MutableHandleValue vp); 1453 1454 // Returns true iff this is a function environment with its own this-binding 1455 // (all functions except arrow functions). 1456 bool isFunctionEnvironmentWithThis(); 1457 1458 // Does this debug environment not have a real counterpart or was never 1459 // live (and thus does not have a synthesized EnvironmentObject or a 1460 // snapshot)? 1461 bool isOptimizedOut() const; 1462 1463 #if defined(DEBUG) || defined(JS_JITSPEW) 1464 void dump(); 1465 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */ 1466 }; 1467 1468 /* Maintains per-realm debug environment bookkeeping information. */ 1469 class DebugEnvironments { 1470 Zone* zone_; 1471 1472 /* The map from (non-debug) environments to debug environments. */ 1473 using ProxiedEnvironmentsMap = WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>; 1474 ProxiedEnvironmentsMap proxiedEnvs; 1475 1476 /* 1477 * The map from live frames which have optimized-away environments to the 1478 * corresponding debug environments. 1479 */ 1480 using MissingEnvironmentMap = 1481 HashMap<MissingEnvironmentKey, WeakHeapPtr<DebugEnvironmentProxy*>, 1482 MissingEnvironmentKey, ZoneAllocPolicy>; 1483 MissingEnvironmentMap missingEnvs; 1484 1485 /* 1486 * The map from environment objects of live frames to the live frame. This 1487 * map updated lazily whenever the debugger needs the information. In 1488 * between two lazy updates, liveEnvs becomes incomplete (but not invalid, 1489 * onPop* removes environments as they are popped). Thus, two consecutive 1490 * debugger lazy updates of liveEnvs need only fill in the new 1491 * environments. 1492 */ 1493 using LiveEnvironmentMap = 1494 GCHashMap<WeakHeapPtr<JSObject*>, LiveEnvironmentVal, 1495 StableCellHasher<WeakHeapPtr<JSObject*>>, ZoneAllocPolicy>; 1496 LiveEnvironmentMap liveEnvs; 1497 1498 public: 1499 DebugEnvironments(JSContext* cx, Zone* zone); 1500 ~DebugEnvironments(); 1501 1502 Zone* zone() const { return zone_; } 1503 1504 private: 1505 static DebugEnvironments* ensureRealmData(JSContext* cx); 1506 1507 template <typename Environment, typename Scope> 1508 static void onPopGeneric(JSContext* cx, const EnvironmentIter& ei); 1509 1510 public: 1511 void trace(JSTracer* trc); 1512 void traceWeak(JSTracer* trc); 1513 void finish(); 1514 #ifdef JS_GC_ZEAL 1515 void checkHashTablesAfterMovingGC(); 1516 #endif 1517 1518 // If a live frame has a synthesized entry in missingEnvs, make sure it's not 1519 // collected. 1520 void traceLiveFrame(JSTracer* trc, AbstractFramePtr frame); 1521 1522 static DebugEnvironmentProxy* hasDebugEnvironment(JSContext* cx, 1523 EnvironmentObject& env); 1524 static bool addDebugEnvironment(JSContext* cx, Handle<EnvironmentObject*> env, 1525 Handle<DebugEnvironmentProxy*> debugEnv); 1526 1527 static bool getExistingDebugEnvironment(JSContext* cx, 1528 const EnvironmentIter& ei, 1529 DebugEnvironmentProxy** out); 1530 static bool addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei, 1531 Handle<DebugEnvironmentProxy*> debugEnv); 1532 1533 static bool updateLiveEnvironments(JSContext* cx); 1534 static LiveEnvironmentVal* hasLiveEnvironment(EnvironmentObject& env); 1535 static void unsetPrevUpToDateUntil(JSContext* cx, AbstractFramePtr frame); 1536 1537 // When a frame bails out from Ion to Baseline, there might be missing 1538 // envs keyed on, and live envs containing, the old 1539 // RematerializedFrame. Forward those values to the new BaselineFrame. 1540 static void forwardLiveFrame(JSContext* cx, AbstractFramePtr from, 1541 AbstractFramePtr to); 1542 1543 // When an environment is popped, we store a snapshot of its bindings that 1544 // live on the frame. 1545 // 1546 // This is done during frame unwinding, which cannot handle errors 1547 // gracefully. Errors result in no snapshot being set on the 1548 // DebugEnvironmentProxy. 1549 static void takeFrameSnapshot(JSContext* cx, 1550 Handle<DebugEnvironmentProxy*> debugEnv, 1551 AbstractFramePtr frame); 1552 1553 // In debug-mode, these must be called whenever exiting a scope that might 1554 // have stack-allocated locals. 1555 static void onPopCall(JSContext* cx, AbstractFramePtr frame); 1556 static void onPopVar(JSContext* cx, const EnvironmentIter& ei); 1557 static void onPopLexical(JSContext* cx, const EnvironmentIter& ei); 1558 static void onPopLexical(JSContext* cx, AbstractFramePtr frame, 1559 const jsbytecode* pc); 1560 static void onPopWith(AbstractFramePtr frame); 1561 static void onPopModule(JSContext* cx, const EnvironmentIter& ei); 1562 static void onRealmUnsetIsDebuggee(Realm* realm); 1563 }; 1564 1565 } /* namespace js */ 1566 1567 template <> 1568 inline bool JSObject::is<js::EnvironmentObject>() const { 1569 return is<js::CallObject>() || is<js::VarEnvironmentObject>() || 1570 is<js::ModuleEnvironmentObject>() || 1571 is<js::WasmInstanceEnvironmentObject>() || 1572 is<js::WasmFunctionCallObject>() || 1573 is<js::LexicalEnvironmentObject>() || 1574 is<js::WithEnvironmentObject>() || 1575 is<js::NonSyntacticVariablesObject>() || 1576 is<js::RuntimeLexicalErrorObject>(); 1577 } 1578 1579 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1580 template <> 1581 inline bool JSObject::is<js::DisposableEnvironmentObject>() const { 1582 return is<js::LexicalEnvironmentObject>() || 1583 is<js::ModuleEnvironmentObject>(); 1584 } 1585 #endif 1586 1587 template <> 1588 inline bool JSObject::is<js::ScopedLexicalEnvironmentObject>() const { 1589 return is<js::LexicalEnvironmentObject>() && 1590 !as<js::LexicalEnvironmentObject>().isExtensible(); 1591 } 1592 1593 template <> 1594 inline bool JSObject::is<js::BlockLexicalEnvironmentObject>() const { 1595 return is<js::ScopedLexicalEnvironmentObject>() && 1596 !as<js::ScopedLexicalEnvironmentObject>().isClassBody(); 1597 } 1598 1599 template <> 1600 inline bool JSObject::is<js::ClassBodyLexicalEnvironmentObject>() const { 1601 return is<js::ScopedLexicalEnvironmentObject>() && 1602 as<js::ScopedLexicalEnvironmentObject>().isClassBody(); 1603 } 1604 1605 template <> 1606 inline bool JSObject::is<js::ExtensibleLexicalEnvironmentObject>() const { 1607 return is<js::LexicalEnvironmentObject>() && 1608 as<js::LexicalEnvironmentObject>().isExtensible(); 1609 } 1610 1611 template <> 1612 inline bool JSObject::is<js::GlobalLexicalEnvironmentObject>() const { 1613 return is<js::LexicalEnvironmentObject>() && 1614 as<js::LexicalEnvironmentObject>().isGlobal(); 1615 } 1616 1617 template <> 1618 inline bool JSObject::is<js::NonSyntacticLexicalEnvironmentObject>() const { 1619 return is<js::LexicalEnvironmentObject>() && 1620 !as<js::LexicalEnvironmentObject>().isSyntactic(); 1621 } 1622 1623 template <> 1624 inline bool JSObject::is<js::NamedLambdaObject>() const { 1625 return is<js::BlockLexicalEnvironmentObject>() && 1626 as<js::BlockLexicalEnvironmentObject>().scope().isNamedLambda(); 1627 } 1628 1629 template <> 1630 bool JSObject::is<js::DebugEnvironmentProxy>() const; 1631 1632 namespace js { 1633 1634 inline bool IsSyntacticEnvironment(JSObject* env) { 1635 if (!env->is<EnvironmentObject>()) { 1636 return false; 1637 } 1638 1639 if (env->is<WithEnvironmentObject>()) { 1640 return env->as<WithEnvironmentObject>().isSyntactic(); 1641 } 1642 1643 if (env->is<LexicalEnvironmentObject>()) { 1644 return env->as<LexicalEnvironmentObject>().isSyntactic(); 1645 } 1646 1647 if (env->is<NonSyntacticVariablesObject>()) { 1648 return false; 1649 } 1650 1651 return true; 1652 } 1653 1654 inline JSObject* MaybeUnwrapWithEnvironment(JSObject* env) { 1655 if (env->is<WithEnvironmentObject>()) { 1656 return &env->as<WithEnvironmentObject>().object(); 1657 } 1658 return env; 1659 } 1660 1661 template <typename SpecificEnvironment> 1662 inline bool IsFrameInitialEnvironment(AbstractFramePtr frame, 1663 SpecificEnvironment& env) { 1664 // A frame's initial environment is the innermost environment 1665 // corresponding to the scope chain from frame.script()->bodyScope() to 1666 // frame.script()->outermostScope(). This environment must be on the chain 1667 // for the frame to be considered initialized. That is, it must be on the 1668 // chain for the environment chain to fully match the scope chain at the 1669 // start of execution in the frame. 1670 // 1671 // This logic must be in sync with the HAS_INITIAL_ENV logic in 1672 // BaselineStackBuilder::buildBaselineFrame. 1673 1674 // A function frame's CallObject, if present, is always the initial 1675 // environment. 1676 if constexpr (std::is_same_v<SpecificEnvironment, CallObject>) { 1677 return true; 1678 } 1679 1680 // For an eval frame, the VarEnvironmentObject, if present, is always the 1681 // initial environment. 1682 if constexpr (std::is_same_v<SpecificEnvironment, VarEnvironmentObject>) { 1683 if (frame.isEvalFrame()) { 1684 return true; 1685 } 1686 } 1687 1688 // For named lambda frames without CallObjects (i.e., no binding in the 1689 // body of the function was closed over), the NamedLambdaObject 1690 // corresponding to the named lambda scope is the initial environment. 1691 if constexpr (std::is_same_v<SpecificEnvironment, NamedLambdaObject>) { 1692 if (frame.isFunctionFrame() && 1693 frame.callee()->needsNamedLambdaEnvironment() && 1694 !frame.callee()->needsCallObject()) { 1695 LexicalScope* namedLambdaScope = frame.script()->maybeNamedLambdaScope(); 1696 return &env.scope() == namedLambdaScope; 1697 } 1698 } 1699 1700 return false; 1701 } 1702 1703 WithEnvironmentObject* CreateObjectsForEnvironmentChain( 1704 JSContext* cx, const JS::EnvironmentChain& envChain, 1705 HandleObject terminatingEnv); 1706 1707 ModuleObject* GetModuleObjectForScript(JSScript* script); 1708 1709 ModuleEnvironmentObject* GetModuleEnvironmentForScript(JSScript* script); 1710 1711 [[nodiscard]] bool GetThisValueForDebuggerFrameMaybeOptimizedOut( 1712 JSContext* cx, AbstractFramePtr frame, const jsbytecode* pc, 1713 MutableHandleValue res); 1714 [[nodiscard]] bool GetThisValueForDebuggerSuspendedGeneratorMaybeOptimizedOut( 1715 JSContext* cx, AbstractGeneratorObject& genObj, JSScript* script, 1716 MutableHandleValue res); 1717 1718 [[nodiscard]] bool GlobalOrEvalDeclInstantiation(JSContext* cx, 1719 HandleObject envChain, 1720 HandleScript script, 1721 GCThingIndex lastFun); 1722 1723 [[nodiscard]] bool InitFunctionEnvironmentObjects(JSContext* cx, 1724 AbstractFramePtr frame); 1725 1726 [[nodiscard]] bool PushVarEnvironmentObject(JSContext* cx, Handle<Scope*> scope, 1727 AbstractFramePtr frame); 1728 1729 #ifdef DEBUG 1730 bool AnalyzeEntrainedVariables(JSContext* cx, HandleScript script); 1731 #endif 1732 1733 extern JSObject* MaybeOptimizeBindUnqualifiedGlobalName(GlobalObject* global, 1734 PropertyName* name); 1735 } // namespace js 1736 1737 #endif /* vm_EnvironmentObject_h */