Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / vm / EnvironmentObject.h
blobef68cc8855bd02bd8168366d4ff6ff9a21a31c5b
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/. */
7 #ifndef vm_EnvironmentObject_h
8 #define vm_EnvironmentObject_h
10 #include <type_traits>
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
23 namespace js {
25 class AbstractGeneratorObject;
26 class IndirectBindingMap;
27 class ModuleObject;
30 * Return a shape representing the static scope containing the variable
31 * accessed by the ALIASEDVAR op at 'pc'.
33 extern SharedShape* EnvironmentCoordinateToEnvironmentShape(JSScript* script,
34 jsbytecode* pc);
36 // Return the name being accessed by the given ALIASEDVAR op. This function is
37 // relatively slow so it should not be used on hot paths.
38 extern PropertyName* EnvironmentCoordinateNameSlow(JSScript* script,
39 jsbytecode* pc);
41 /*** Environment objects ****************************************************/
43 // clang-format off
45 * [SMDOC] Environment Objects
47 * About environments
48 * ------------------
50 * See also: https://tc39.es/ecma262/#sec-environment-records
52 * Scoping in ES is specified in terms of "Environment Records". There's a
53 * global Environment Record per realm, and a new Environment Record is created
54 * whenever control enters a function, block, or other scope.
56 * A "Lexical Environment" is a list of nested Environment Records, innermost
57 * first: everything that's in scope. Throughout SpiderMonkey, "environment"
58 * means a Lexical Environment.
60 * N.B.: "Scope" means something different: a static scope, the compile-time
61 * analogue of an environment. See Scope.h.
63 * How SpiderMonkey represents environments
64 * ----------------------------------------
66 * Some environments are stored as JSObjects. Several kinds of objects
67 * represent environments:
69 * JSObject
70 * |
71 * +--NativeObject
72 * | |
73 * | +--EnvironmentObject Engine-internal environment
74 * | | |
75 * | | +--CallObject Environment of entire function
76 * | | |
77 * | | +--VarEnvironmentObject See VarScope in Scope.h.
78 * | | |
79 * | | +--ModuleEnvironmentObject
80 * | | | Module top-level environment
81 * | | |
82 * | | +--WasmInstanceEnvironmentObject
83 * | | |
84 * | | +--WasmFunctionCallObject
85 * | | |
86 * | | +--LexicalEnvironmentObject
87 * | | | |
88 * | | | +--ScopedLexicalEnvironmentObject
89 * | | | | | Non-extensible lexical environment
90 * | | | | |
91 * | | | | +--BlockLexicalEnvironmentObject
92 * | | | | | | Blocks and such: syntactic,
93 * | | | | | | non-extensible
94 * | | | | | |
95 * | | | | | +--NamedLambdaObject
96 * | | | | | Environment for `(function f(){...})`
97 * | | | | | containing only a binding for `f`
98 * | | | | |
99 * | | | | +--ClassBodyLexicalEnvironmentObject
100 * | | | | Environment for class body, containing
101 * | | | | private names, private brands, and
102 * | | | | static initializers list
103 * | | | |
104 * | | | +--ExtensibleLexicalEnvironmentObject
105 * | | | |
106 * | | | +--GlobalLexicalEnvironmentObject
107 * | | | | Top-level let/const/class in scripts
108 * | | | |
109 * | | | +--NonSyntacticLexicalEnvironmentObject
110 * | | | See "Non-syntactic environments" below
111 * | | |
112 * | | +--NonSyntacticVariablesObject
113 * | | | See "Non-syntactic environments" below
114 * | | |
115 * | | +--WithEnvironmentObject Presents object properties as bindings
116 * | | |
117 * | | +--RuntimeLexicalErrorObject
118 * | | Special value represents uninitialized
119 * | | lexical slots
120 * | |
121 * | +--GlobalObject The global environment (dynamically
122 * | presents its properties as bindings)
123 * +--ProxyObject
125 * +--DebugEnvironmentProxy Environment for debugger eval-in-frame
127 * EnvironmentObjects are technically real JSObjects but only belong on the
128 * environment chain (that is, fp->environmentChain() or fun->environment()).
129 * They are never exposed to scripts.
131 * Note that reserved slots in any base classes shown above are fixed for all
132 * derived classes. So e.g. EnvironmentObject::enclosingEnvironment() can
133 * simply access a fixed slot without further dynamic type information.
135 * When the current environment is represented by an object, the stack frame
136 * has a pointer to that object (see AbstractFramePtr::environmentChain()).
137 * However, that isn't always the case. Where possible, we store binding values
138 * in JS stack slots. For block and function scopes where all bindings can be
139 * stored in stack slots, nothing is allocated in the heap; there is no
140 * environment object.
142 * Full information about the environment chain is always recoverable:
143 * EnvironmentIter can do it, and we construct a fake environment for debugger
144 * eval-in-frame (see "Debug environment objects" below).
146 * Syntactic Environments
147 * ----------------------
149 * Environments may be syntactic, i.e., corresponding to source text, or
150 * non-syntactic, i.e., specially created by embedding. The distinction is
151 * necessary to maintain invariants about the environment chain: non-syntactic
152 * environments may not occur in arbitrary positions in the chain.
154 * CallObject, ModuleEnvironmentObject, BlockLexicalEnvironmentObject, and
155 * GlobalLexicalEnvironmentObject always represent syntactic
156 * environments. (CallObject is considered syntactic even when it's used as the
157 * scope of strict eval code.) WithEnvironmentObject is syntactic when it's
158 * used to represent the scope of a `with` block.
161 * Non-syntactic Environments
162 * --------------------------
164 * A non-syntactic environment is one that was not created due to JS source
165 * code. On the scope chain, a single NonSyntactic GlobalScope maps to 0+
166 * non-syntactic environment objects. This is contrasted with syntactic
167 * environments, where each scope corresponds to 0 or 1 environment object.
169 * There are 3 kinds of dynamic environment objects:
171 * 1. WithEnvironmentObject
173 * When the embedding compiles or executes a script, it has the option to
174 * pass in a vector of objects to be used as the initial env chain, ordered
175 * from outermost env to innermost env. Each of those objects is wrapped by
176 * a WithEnvironmentObject.
178 * The innermost object passed in by the embedding becomes a qualified
179 * variables object that captures 'var' bindings. That is, it wraps the
180 * holder object of 'var' bindings.
182 * Does not hold 'let' or 'const' bindings.
184 * 2. NonSyntacticVariablesObject
186 * When the embedding wants qualified 'var' bindings and unqualified
187 * bareword assignments to go on a different object than the global
188 * object. While any object can be made into a qualified variables object,
189 * only the GlobalObject and NonSyntacticVariablesObject are considered
190 * unqualified variables objects.
192 * Unlike WithEnvironmentObjects that delegate to the object they wrap,
193 * this object is itself the holder of 'var' bindings.
195 * Does not hold 'let' or 'const' bindings.
197 * 3. NonSyntacticLexicalEnvironmentObject
199 * Each non-syntactic object used as a qualified variables object needs to
200 * enclose a non-syntactic lexical environment to hold 'let' and 'const'
201 * bindings. There is a bijection per realm between the non-syntactic
202 * variables objects and their non-syntactic LexicalEnvironmentObjects.
204 * Does not hold 'var' bindings.
206 * The embedding (Gecko) and debugger uses non-syntactic envs for various
207 * things, all of which are detailed below. All env chain listings below are,
208 * from top to bottom, outermost to innermost.
210 * A. JSM loading
212 * Most JSMs are loaded into a shared system global in order to save the memory
213 * consumption and avoid CCWs. To support this, a NonSyntacticVariablesObject
214 * is used for each JSM to provide a basic form of isolation.
215 * NonSyntacticLexicalEnvironmentObject and
216 * NonSyntacticVariablesObject are allocated for each JSM, and
217 * NonSyntacticLexicalEnvironmentObject holds lexical variables and
218 * NonSyntacticVariablesObject holds qualified variables. JSMs cannot have
219 * unqualified names, but if unqualified names are used by subscript, they
220 * goes to NonSyntacticVariablesObject (see B.3 and B.4).
221 * They have the following env chain:
223 * BackstagePass global
225 * GlobalLexicalEnvironmentObject[this=global]
227 * NonSyntacticVariablesObject (qualified 'var's (and unqualified names))
229 * NonSyntacticLexicalEnvironmentObject[this=nsvo] (lexical vars)
231 * B.1 Subscript loading into a target object
233 * Subscripts may be loaded into a target object and it's associated global.
234 * NonSyntacticLexicalEnvironmentObject holds lexical variables and
235 * WithEnvironmentObject holds qualified variables. Unqualified names goes
236 * to the target object's global.
237 * They have the following env chain:
239 * Target object's global (unqualified names)
241 * GlobalLexicalEnvironmentObject[this=global]
243 * WithEnvironmentObject wrapping target (qualified 'var's)
245 * NonSyntacticLexicalEnvironmentObject[this=target] (lexical vars)
247 * B.2 Subscript loading into global this
249 * Subscript may be loaded into global this. In this case no extra environment
250 * object is created.
252 * global (qualified 'var's and unqualified names)
254 * GlobalLexicalEnvironmentObject[this=global] (lexical vars)
256 * B.3 Subscript loading into a target object in JSM
258 * The target object of a subscript load may be in a JSM, in which case we will
259 * also have the NonSyntacticVariablesObject on the chain.
260 * NonSyntacticLexicalEnvironmentObject for target object holds lexical
261 * variables and WithEnvironmentObject holds qualified variables.
262 * Unqualified names goes to NonSyntacticVariablesObject.
264 * BackstagePass global
266 * GlobalLexicalEnvironmentObject[this=global]
268 * NonSyntacticVariablesObject (unqualified names)
270 * NonSyntacticLexicalEnvironmentObject[this=nsvo]
272 * WithEnvironmentObject wrapping target (qualified 'var's)
274 * NonSyntacticLexicalEnvironmentObject[this=target] (lexical vars)
276 * B.4 Subscript loading into per-JSM this
278 * Subscript may be loaded into global this. In this case no extra environment
279 * object is created.
281 * BackstagePass global
283 * GlobalLexicalEnvironmentObject[this=global]
285 * NonSyntacticVariablesObject (qualified 'var's and unqualified names)
287 * NonSyntacticLexicalEnvironmentObject[this=nsvo] (lexical vars)
289 * C.1. Frame scripts with unique scope
291 * XUL frame scripts with unique scope are loaded in the same global as
292 * JSMs, with a NonSyntacticVariablesObject as a "polluting global" for
293 * both qualified 'var' variables and unqualified names, and a with
294 * environment wrapping a message manager object, and
295 * NonSyntacticLexicalEnvironmentObject holding the message manager as `this`,
296 * that holds lexical variables.
297 * These environment objects except for globals are created for each run and
298 * not shared across multiple runs. This is done exclusively in
299 * js::ExecuteInFrameScriptEnvironment.
301 * BackstagePass global
303 * GlobalLexicalEnvironmentObject[this=global]
305 * NonSyntacticVariablesObject (qualified 'var's and unqualified names)
307 * WithEnvironmentObject wrapping messageManager
309 * NonSyntacticLexicalEnvironmentObject[this=messageManager] (lexical vars)
311 * C.2. Frame scripts without unique scope
313 * XUL frame scripts without unique scope are loaded in the same global as
314 * JSMs, with a with environment wrapping a message manager object for
315 * qualified 'var' variables, and NonSyntacticLexicalEnvironmentObject holding
316 * the message manager as `this`, that holds lexical variables.
317 * The environment chain is associated with the message manager object
318 * and cached for subsequent runs.
320 * BackstagePass global (unqualified names)
322 * GlobalLexicalEnvironmentObject[this=global]
324 * WithEnvironmentObject wrapping messageManager (qualified 'var's)
326 * NonSyntacticLexicalEnvironmentObject[this=messageManager] (lexical vars)
328 * D.1. DOM event handlers without direct eval
330 * DOM event handlers are compiled as functions with HTML elements on the
331 * environment chain. For a chain of elements e0, e1, ..., eN, where innerrmost
332 * element is the target element, enclosing elements are such as forms, and the
333 * outermost one is the document.
334 * If the DOM event handlers don't have direct eval, the function's scopes are
335 * optimized and frame slots are used for qualified 'var's and lexical vars.
336 * NonSyntacticLexicalEnvironmentObject's `this` value is not used, given
337 * the function's `this` value is used instead:
339 * global (unqualified names)
341 * GlobalLexicalEnvironmentObject[this=global]
343 * WithEnvironmentObject wrapping eN
345 * ...
347 * WithEnvironmentObject wrapping e1
349 * WithEnvironmentObject wrapping e0
351 * NonSyntacticLexicalEnvironmentObject [this=*unused*]
353 * D.2. DOM event handlers with direct eval
355 * If DOM event handlers have direct eval, the function's scopes are allocated
356 * as environment object:
358 * global (unqualified names)
360 * GlobalLexicalEnvironmentObject[this=global]
362 * ...
364 * WithEnvironmentObject wrapping e1
366 * WithEnvironmentObject wrapping e0
368 * NonSyntacticLexicalEnvironmentObject [this=*unused*]
370 * CallObject (qualified 'var's)
372 * BlockLexicalEnvironmentObject (lexical vars)
374 * E.1. Debugger.Frame.prototype.evalWithBindings
376 * Debugger.Frame.prototype.evalWithBindings uses WithEnvironmentObject for
377 * given bindings, and the frame's enclosing scope.
379 * If qualified 'var's or unqualified names conflict with the bindings object's
380 * properties, they go to the WithEnvironmentObject.
382 * If the frame is function, it has the following env chain.
383 * lexical variables are optimized and uses frame slots, regardless of the name
384 * conflicts with bindings:
386 * global (unqualified names)
388 * [DebugProxy] GlobalLexicalEnvironmentObject[this=global]
390 * [DebugProxy] CallObject (qualified 'var's)
392 * WithEnvironmentObject wrapping bindings (conflicting 'var's and names)
394 * If the script has direct eval, BlockLexicalEnvironmentObject is created for
395 * it:
397 * global (unqualified names)
399 * [DebugProxy] GlobalLexicalEnvironmentObject[this=global]
401 * [DebugProxy] CallObject (qualified 'var's)
403 * WithEnvironmentObject wrapping bindings (conflicting 'var's and names)
405 * BlockLexicalEnvironmentObject (lexical vars, and conflicting lexical vars)
407 * NOTE: Debugger.Frame.prototype.eval uses the frame's enclosing scope only,
408 * and it doesn't use any dynamic environment, but still uses
409 * non-syntactic scope to perform `eval` operation.
411 * E.2. Debugger.Object.prototype.executeInGlobalWithBindings
413 * Debugger.Object.prototype.executeInGlobalWithBindings uses
414 * WithEnvironmentObject for given bindings, and the object's global scope.
416 * If `options.useInnerBindings` is not true, if bindings conflict with
417 * qualified 'var's or global lexicals, those bindings are shadowed and not
418 * stored into the bindings object wrapped by WithEnvironmentObject.
420 * global (qualified 'var's and unqualified names)
422 * GlobalLexicalEnvironmentObject[this=global] (lexical vars)
424 * WithEnvironmentObject wrapping object with not-conflicting bindings
426 * If `options.useInnerBindings` is true, all bindings are stored into the
427 * bindings object wrapped by WithEnvironmentObject, and they shadow globals
429 * global (qualified 'var's and unqualified names)
431 * GlobalLexicalEnvironmentObject[this=global] (lexical vars)
433 * WithEnvironmentObject wrapping object with all bindings
435 * NOTE: If `options.useInnerBindings` is true, and if lexical variable names
436 * conflict with the bindings object's properties, the write on them
437 * within declarations is done for the GlobalLexicalEnvironmentObject,
438 * but the write within assignments and the read on lexicals are done
439 * from the WithEnvironmentObject (bug 1841964 and bug 1847219).
441 * // bindings = { x: 10, y: 20 };
443 * let x = 11; // written to GlobalLexicalEnvironmentObject
444 * x; // read from WithEnvironmentObject
445 * let y;
446 * y = 21; // written to WithEnvironmentObject
447 * y; // read from WithEnvironmentObject
449 * NOTE: Debugger.Object.prototype.executeInGlobal uses the object's global
450 * scope only, and it doesn't use any dynamic environment or
451 * non-syntactic scope.
452 * NOTE: If no extra bindings are used by script,
453 * Debugger.Object.prototype.executeInGlobalWithBindings uses the object's
454 * global scope only, and it doesn't use any dynamic environment or
455 * non-syntactic scope.
458 // clang-format on
460 class EnvironmentObject : public NativeObject {
461 protected:
462 // The enclosing environment. Either another EnvironmentObject, a
463 // GlobalObject, or a non-syntactic environment object.
464 static const uint32_t ENCLOSING_ENV_SLOT = 0;
466 inline void setAliasedBinding(uint32_t slot, const Value& v);
468 public:
469 // Since every env chain terminates with a global object, whether
470 // GlobalObject or a non-syntactic one, and since those objects do not
471 // derive EnvironmentObject (they have completely different layouts), the
472 // enclosing environment of an EnvironmentObject is necessarily non-null.
473 JSObject& enclosingEnvironment() const {
474 return getReservedSlot(ENCLOSING_ENV_SLOT).toObject();
477 void initEnclosingEnvironment(JSObject* enclosing) {
478 initReservedSlot(ENCLOSING_ENV_SLOT, ObjectOrNullValue(enclosing));
481 static bool nonExtensibleIsFixedSlot(EnvironmentCoordinate ec) {
482 // For non-extensible environment objects isFixedSlot(slot) is equivalent to
483 // slot < MAX_FIXED_SLOTS.
484 return ec.slot() < MAX_FIXED_SLOTS;
486 static size_t nonExtensibleDynamicSlotIndex(EnvironmentCoordinate ec) {
487 MOZ_ASSERT(!nonExtensibleIsFixedSlot(ec));
488 return ec.slot() - MAX_FIXED_SLOTS;
491 // Get or set a name contained in this environment.
492 inline const Value& aliasedBinding(EnvironmentCoordinate ec);
494 const Value& aliasedBinding(const BindingIter& bi) {
495 MOZ_ASSERT(bi.location().kind() == BindingLocation::Kind::Environment);
496 return getSlot(bi.location().slot());
499 inline void setAliasedBinding(EnvironmentCoordinate ec, const Value& v);
501 inline void setAliasedBinding(const BindingIter& bi, const Value& v);
503 // For JITs.
504 static size_t offsetOfEnclosingEnvironment() {
505 return getFixedSlotOffset(ENCLOSING_ENV_SLOT);
508 static uint32_t enclosingEnvironmentSlot() { return ENCLOSING_ENV_SLOT; }
510 const char* typeString() const;
512 #if defined(DEBUG) || defined(JS_JITSPEW)
513 void dump();
514 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
517 class CallObject : public EnvironmentObject {
518 protected:
519 static constexpr uint32_t CALLEE_SLOT = 1;
521 static CallObject* create(JSContext* cx, HandleScript script,
522 HandleObject enclosing, gc::Heap heap);
524 public:
525 static const JSClass class_;
527 static constexpr uint32_t RESERVED_SLOTS = 2;
528 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::QualifiedVarObj};
530 /* These functions are internal and are exposed only for JITs. */
533 * Construct a bare-bones call object given a shape.
534 * The call object must be further initialized to be usable.
536 static CallObject* createWithShape(JSContext* cx, Handle<SharedShape*> shape);
538 static CallObject* createTemplateObject(JSContext* cx, HandleScript script,
539 HandleObject enclosing);
541 static CallObject* create(JSContext* cx, AbstractFramePtr frame);
543 static CallObject* createHollowForDebug(JSContext* cx, HandleFunction callee);
545 // If `env` or any enclosing environment is a CallObject, return that
546 // CallObject; else null.
548 // `env` may be a DebugEnvironmentProxy, but not a hollow environment.
549 static CallObject* find(JSObject* env);
552 * When an aliased formal (var accessed by nested closures) is also
553 * aliased by the arguments object, it must of course exist in one
554 * canonical location and that location is always the CallObject. For this
555 * to work, the ArgumentsObject stores special MagicValue in its array for
556 * forwarded-to-CallObject variables. This MagicValue's payload is the
557 * slot of the CallObject to access.
559 const Value& aliasedFormalFromArguments(const Value& argsValue) {
560 return getSlot(ArgumentsObject::SlotFromMagicScopeSlotValue(argsValue));
562 inline void setAliasedFormalFromArguments(const Value& argsValue,
563 const Value& v);
565 JSFunction& callee() const {
566 return getReservedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
569 /* For jit access. */
570 static size_t offsetOfCallee() { return getFixedSlotOffset(CALLEE_SLOT); }
572 static size_t calleeSlot() { return CALLEE_SLOT; }
575 class VarEnvironmentObject : public EnvironmentObject {
576 static constexpr uint32_t SCOPE_SLOT = 1;
578 static VarEnvironmentObject* createInternal(JSContext* cx,
579 Handle<SharedShape*> shape,
580 HandleObject enclosing,
581 gc::Heap heap);
583 static VarEnvironmentObject* create(JSContext* cx, Handle<Scope*> scope,
584 HandleObject enclosing, gc::Heap heap);
586 void initScope(Scope* scope) {
587 initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope));
590 public:
591 static const JSClass class_;
593 static constexpr uint32_t RESERVED_SLOTS = 2;
594 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::QualifiedVarObj};
596 static VarEnvironmentObject* createForFrame(JSContext* cx,
597 Handle<Scope*> scope,
598 AbstractFramePtr frame);
599 static VarEnvironmentObject* createHollowForDebug(JSContext* cx,
600 Handle<Scope*> scope);
601 static VarEnvironmentObject* createTemplateObject(JSContext* cx,
602 Handle<VarScope*> scope);
603 static VarEnvironmentObject* createWithoutEnclosing(JSContext* cx,
604 Handle<VarScope*> scope);
606 Scope& scope() const {
607 Value v = getReservedSlot(SCOPE_SLOT);
608 MOZ_ASSERT(v.isPrivateGCThing());
609 Scope& s = *static_cast<Scope*>(v.toGCThing());
610 MOZ_ASSERT(s.is<VarScope>() || s.is<EvalScope>());
611 return s;
614 bool isForEval() const { return scope().is<EvalScope>(); }
615 bool isForNonStrictEval() const { return scope().kind() == ScopeKind::Eval; }
618 class ModuleEnvironmentObject : public EnvironmentObject {
619 static constexpr uint32_t MODULE_SLOT = 1;
621 static const ObjectOps objectOps_;
622 static const JSClassOps classOps_;
624 public:
625 static const JSClass class_;
627 static constexpr uint32_t RESERVED_SLOTS = 2;
628 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible,
629 ObjectFlag::QualifiedVarObj};
631 static ModuleEnvironmentObject* create(JSContext* cx,
632 Handle<ModuleObject*> module);
633 ModuleObject& module() const;
634 IndirectBindingMap& importBindings() const;
636 bool createImportBinding(JSContext* cx, Handle<JSAtom*> importName,
637 Handle<ModuleObject*> module,
638 Handle<JSAtom*> exportName);
640 bool hasImportBinding(Handle<PropertyName*> name);
642 bool lookupImport(jsid name, ModuleEnvironmentObject** envOut,
643 mozilla::Maybe<PropertyInfo>* propOut);
645 // If `env` or any enclosing environment is a ModuleEnvironmentObject,
646 // return that ModuleEnvironmentObject; else null.
648 // `env` may be a DebugEnvironmentProxy, but not a hollow environment.
649 static ModuleEnvironmentObject* find(JSObject* env);
651 private:
652 static bool lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
653 MutableHandleObject objp, PropertyResult* propp);
654 static bool hasProperty(JSContext* cx, HandleObject obj, HandleId id,
655 bool* foundp);
656 static bool getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
657 HandleId id, MutableHandleValue vp);
658 static bool setProperty(JSContext* cx, HandleObject obj, HandleId id,
659 HandleValue v, HandleValue receiver,
660 JS::ObjectOpResult& result);
661 static bool getOwnPropertyDescriptor(
662 JSContext* cx, HandleObject obj, HandleId id,
663 MutableHandle<mozilla::Maybe<PropertyDescriptor>> desc);
664 static bool deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
665 ObjectOpResult& result);
666 static bool newEnumerate(JSContext* cx, HandleObject obj,
667 MutableHandleIdVector properties,
668 bool enumerableOnly);
671 class WasmInstanceEnvironmentObject : public EnvironmentObject {
672 // Currently WasmInstanceScopes do not use their scopes in a
673 // meaningful way. However, it is an invariant of DebugEnvironments that
674 // environments kept in those maps have live scopes, thus this strong
675 // reference.
676 static constexpr uint32_t SCOPE_SLOT = 1;
678 public:
679 static const JSClass class_;
681 static constexpr uint32_t RESERVED_SLOTS = 2;
682 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible};
684 static WasmInstanceEnvironmentObject* createHollowForDebug(
685 JSContext* cx, Handle<WasmInstanceScope*> scope);
686 WasmInstanceScope& scope() const {
687 Value v = getReservedSlot(SCOPE_SLOT);
688 MOZ_ASSERT(v.isPrivateGCThing());
689 return *static_cast<WasmInstanceScope*>(v.toGCThing());
693 class WasmFunctionCallObject : public EnvironmentObject {
694 // Currently WasmFunctionCallObjects do not use their scopes in a
695 // meaningful way. However, it is an invariant of DebugEnvironments that
696 // environments kept in those maps have live scopes, thus this strong
697 // reference.
698 static constexpr uint32_t SCOPE_SLOT = 1;
700 public:
701 static const JSClass class_;
703 // TODO Check what Debugger behavior should be when it evaluates a
704 // var declaration.
705 static constexpr uint32_t RESERVED_SLOTS = 2;
706 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible};
708 static WasmFunctionCallObject* createHollowForDebug(
709 JSContext* cx, HandleObject enclosing, Handle<WasmFunctionScope*> scope);
710 WasmFunctionScope& scope() const {
711 Value v = getReservedSlot(SCOPE_SLOT);
712 MOZ_ASSERT(v.isPrivateGCThing());
713 return *static_cast<WasmFunctionScope*>(v.toGCThing());
717 // Abstract base class for environments that can contain let/const bindings,
718 // plus a few other kinds of environments, such as `catch` blocks, that have
719 // similar behavior.
720 class LexicalEnvironmentObject : public EnvironmentObject {
721 protected:
722 // Global and non-syntactic lexical environments need to store a 'this'
723 // object and all other lexical environments have a fixed shape and store a
724 // backpointer to the LexicalScope.
726 // Since the two sets are disjoint, we only use one slot to save space.
727 static constexpr uint32_t THIS_VALUE_OR_SCOPE_SLOT = 1;
729 public:
730 static const JSClass class_;
732 static constexpr uint32_t RESERVED_SLOTS = 2;
734 protected:
735 static LexicalEnvironmentObject* create(JSContext* cx,
736 Handle<SharedShape*> shape,
737 HandleObject enclosing,
738 gc::Heap heap);
740 public:
741 // Is this the global lexical scope?
742 bool isGlobal() const { return enclosingEnvironment().is<GlobalObject>(); }
744 // Global and non-syntactic lexical scopes are extensible. All other
745 // lexical scopes are not.
746 bool isExtensible() const;
748 // Is this a syntactic (i.e. corresponds to a source text) lexical
749 // environment?
750 bool isSyntactic() const { return !isExtensible() || isGlobal(); }
753 // A non-extensible lexical environment.
755 // Used for blocks (ScopeKind::Lexical) and several other scope kinds,
756 // including Catch, NamedLambda, FunctionLexical, and ClassBody.
757 class ScopedLexicalEnvironmentObject : public LexicalEnvironmentObject {
758 public:
759 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible};
761 Scope& scope() const {
762 Value v = getReservedSlot(THIS_VALUE_OR_SCOPE_SLOT);
763 MOZ_ASSERT(!isExtensible() && v.isPrivateGCThing());
764 return *static_cast<Scope*>(v.toGCThing());
767 bool isClassBody() const { return scope().kind() == ScopeKind::ClassBody; }
769 void initScope(Scope* scope) {
770 initReservedSlot(THIS_VALUE_OR_SCOPE_SLOT, PrivateGCThingValue(scope));
774 class BlockLexicalEnvironmentObject : public ScopedLexicalEnvironmentObject {
775 protected:
776 static BlockLexicalEnvironmentObject* create(JSContext* cx,
777 Handle<LexicalScope*> scope,
778 HandleObject enclosing,
779 gc::Heap heap);
781 public:
782 static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible};
784 static BlockLexicalEnvironmentObject* createForFrame(
785 JSContext* cx, Handle<LexicalScope*> scope, AbstractFramePtr frame);
787 static BlockLexicalEnvironmentObject* createHollowForDebug(
788 JSContext* cx, Handle<LexicalScope*> scope);
790 static BlockLexicalEnvironmentObject* createTemplateObject(
791 JSContext* cx, Handle<LexicalScope*> scope);
793 static BlockLexicalEnvironmentObject* createWithoutEnclosing(
794 JSContext* cx, Handle<LexicalScope*> scope);
796 // Create a new BlockLexicalEnvironmentObject with the same enclosing env and
797 // variable values as this.
798 static BlockLexicalEnvironmentObject* clone(
799 JSContext* cx, Handle<BlockLexicalEnvironmentObject*> env);
801 // Create a new BlockLexicalEnvironmentObject with the same enclosing env as
802 // this, with all variables uninitialized.
803 static BlockLexicalEnvironmentObject* recreate(
804 JSContext* cx, Handle<BlockLexicalEnvironmentObject*> env);
806 // The LexicalScope that created this environment.
807 LexicalScope& scope() const {
808 return ScopedLexicalEnvironmentObject::scope().as<LexicalScope>();
812 class NamedLambdaObject : public BlockLexicalEnvironmentObject {
813 static NamedLambdaObject* create(JSContext* cx, HandleFunction callee,
814 HandleObject enclosing, gc::Heap heap);
816 public:
817 static NamedLambdaObject* createTemplateObject(JSContext* cx,
818 HandleFunction callee);
820 static NamedLambdaObject* createWithoutEnclosing(JSContext* cx,
821 HandleFunction callee);
823 static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame);
825 // For JITs.
826 static size_t lambdaSlot();
828 static size_t offsetOfLambdaSlot() {
829 return getFixedSlotOffset(lambdaSlot());
833 class ClassBodyLexicalEnvironmentObject
834 : public ScopedLexicalEnvironmentObject {
835 static ClassBodyLexicalEnvironmentObject* create(
836 JSContext* cx, Handle<ClassBodyScope*> scope, HandleObject enclosing,
837 gc::Heap heap);
839 public:
840 static ClassBodyLexicalEnvironmentObject* createForFrame(
841 JSContext* cx, Handle<ClassBodyScope*> scope, AbstractFramePtr frame);
843 static ClassBodyLexicalEnvironmentObject* createTemplateObject(
844 JSContext* cx, Handle<ClassBodyScope*> scope);
846 static ClassBodyLexicalEnvironmentObject* createWithoutEnclosing(
847 JSContext* cx, Handle<ClassBodyScope*> scope);
849 // The ClassBodyScope that created this environment.
850 ClassBodyScope& scope() const {
851 return ScopedLexicalEnvironmentObject::scope().as<ClassBodyScope>();
854 static uint32_t privateBrandSlot() { return JSSLOT_FREE(&class_); }
857 // Global and non-syntactic lexical environments are extensible.
858 class ExtensibleLexicalEnvironmentObject : public LexicalEnvironmentObject {
859 public:
860 JSObject* thisObject() const;
862 // For a given global object or JSMEnvironment `obj`, return the associated
863 // global lexical or non-syntactic lexical environment, where top-level `let`
864 // bindings are added.
865 static ExtensibleLexicalEnvironmentObject* forVarEnvironment(JSObject* obj);
867 protected:
868 void initThisObject(JSObject* obj) {
869 MOZ_ASSERT(isGlobal() || !isSyntactic());
870 JSObject* thisObj = GetThisObject(obj);
871 initReservedSlot(THIS_VALUE_OR_SCOPE_SLOT, ObjectValue(*thisObj));
875 // The global lexical environment, where global let/const/class bindings are
876 // added.
877 class GlobalLexicalEnvironmentObject
878 : public ExtensibleLexicalEnvironmentObject {
879 public:
880 static GlobalLexicalEnvironmentObject* create(JSContext* cx,
881 Handle<GlobalObject*> global);
883 GlobalObject& global() const {
884 return enclosingEnvironment().as<GlobalObject>();
887 void setWindowProxyThisObject(JSObject* obj);
889 static constexpr size_t offsetOfThisValueSlot() {
890 return getFixedSlotOffset(THIS_VALUE_OR_SCOPE_SLOT);
894 // Non-standard. See "Non-syntactic Environments" above.
895 class NonSyntacticLexicalEnvironmentObject
896 : public ExtensibleLexicalEnvironmentObject {
897 public:
898 static NonSyntacticLexicalEnvironmentObject* create(JSContext* cx,
899 HandleObject enclosing,
900 HandleObject thisv);
903 // A non-syntactic dynamic scope object that captures non-lexical
904 // bindings. That is, a scope object that captures both qualified var
905 // assignments and unqualified bareword assignments. Its parent is always the
906 // global lexical environment.
908 // This is used in ExecuteInGlobalAndReturnScope and sits in front of the
909 // global scope to store 'var' bindings, and to store fresh properties created
910 // by assignments to undeclared variables that otherwise would have gone on
911 // the global object.
912 class NonSyntacticVariablesObject : public EnvironmentObject {
913 public:
914 static const JSClass class_;
916 static constexpr uint32_t RESERVED_SLOTS = 1;
917 static constexpr ObjectFlags OBJECT_FLAGS = {};
919 static NonSyntacticVariablesObject* create(JSContext* cx);
922 extern bool CreateNonSyntacticEnvironmentChain(JSContext* cx,
923 JS::HandleObjectVector envChain,
924 MutableHandleObject env);
926 // With environment objects on the run-time environment chain.
927 class WithEnvironmentObject : public EnvironmentObject {
928 static constexpr uint32_t OBJECT_SLOT = 1;
929 static constexpr uint32_t THIS_SLOT = 2;
930 static constexpr uint32_t SCOPE_SLOT = 3;
932 public:
933 static const JSClass class_;
935 static constexpr uint32_t RESERVED_SLOTS = 4;
936 static constexpr ObjectFlags OBJECT_FLAGS = {};
938 static WithEnvironmentObject* create(JSContext* cx, HandleObject object,
939 HandleObject enclosing,
940 Handle<WithScope*> scope);
941 static WithEnvironmentObject* createNonSyntactic(JSContext* cx,
942 HandleObject object,
943 HandleObject enclosing);
945 /* Return the 'o' in 'with (o)'. */
946 JSObject& object() const;
948 /* Return object for GetThisValue. */
949 JSObject* withThis() const;
952 * Return whether this object is a syntactic with object. If not, this is
953 * a With object we inserted between the outermost syntactic scope and the
954 * global object to wrap the environment chain someone explicitly passed
955 * via JSAPI to CompileFunction or script evaluation.
957 bool isSyntactic() const;
959 // For syntactic with environment objects, the with scope.
960 WithScope& scope() const;
962 static inline size_t objectSlot() { return OBJECT_SLOT; }
964 static inline size_t thisSlot() { return THIS_SLOT; }
967 // Internal scope object used by JSOp::BindName upon encountering an
968 // uninitialized lexical slot or an assignment to a 'const' binding.
970 // ES6 lexical bindings cannot be accessed in any way (throwing
971 // ReferenceErrors) until initialized. Normally, NAME operations
972 // unconditionally check for uninitialized lexical slots. When getting or
973 // looking up names, this can be done without slowing down normal operations
974 // on the return value. When setting names, however, we do not want to pollute
975 // all set-property paths with uninitialized lexical checks. For setting names
976 // (i.e. JSOp::SetName), we emit an accompanying, preceding JSOp::BindName which
977 // finds the right scope on which to set the name. Moreover, when the name on
978 // the scope is an uninitialized lexical, we cannot throw eagerly, as the spec
979 // demands that the error be thrown after evaluating the RHS of
980 // assignments. Instead, this sentinel scope object is pushed on the stack.
981 // Attempting to access anything on this scope throws the appropriate
982 // ReferenceError.
984 // ES6 'const' bindings induce a runtime error when assigned to outside
985 // of initialization, regardless of strictness.
986 class RuntimeLexicalErrorObject : public EnvironmentObject {
987 static const unsigned ERROR_SLOT = 1;
989 public:
990 static const unsigned RESERVED_SLOTS = 2;
991 static const JSClass class_;
993 static RuntimeLexicalErrorObject* create(JSContext* cx,
994 HandleObject enclosing,
995 unsigned errorNumber);
997 unsigned errorNumber() { return getReservedSlot(ERROR_SLOT).toInt32(); }
1000 /****************************************************************************/
1002 // A environment iterator describes the active environments starting from an
1003 // environment, scope pair. This pair may be derived from the current point of
1004 // execution in a frame. If derived in such a fashion, the EnvironmentIter
1005 // tracks whether the current scope is within the extent of this initial
1006 // frame. Here, "frame" means a single activation of: a function, eval, or
1007 // global code.
1008 class MOZ_RAII EnvironmentIter {
1009 Rooted<ScopeIter> si_;
1010 RootedObject env_;
1011 AbstractFramePtr frame_;
1013 void incrementScopeIter();
1014 void settle();
1016 // No value semantics.
1017 EnvironmentIter(const EnvironmentIter& ei) = delete;
1019 public:
1020 // Constructing from a copy of an existing EnvironmentIter.
1021 EnvironmentIter(JSContext* cx, const EnvironmentIter& ei);
1023 // Constructing from an environment, scope pair. All environments
1024 // considered not to be withinInitialFrame, since no frame is given.
1025 EnvironmentIter(JSContext* cx, JSObject* env, Scope* scope);
1027 // Constructing from a frame. Places the EnvironmentIter on the innermost
1028 // environment at pc.
1029 EnvironmentIter(JSContext* cx, AbstractFramePtr frame, const jsbytecode* pc);
1031 // Constructing from an environment, scope and frame. The frame is given
1032 // to initialize to proper enclosing environment/scope.
1033 EnvironmentIter(JSContext* cx, JSObject* env, Scope* scope,
1034 AbstractFramePtr frame);
1036 bool done() const { return si_.done(); }
1038 explicit operator bool() const { return !done(); }
1040 void operator++(int) {
1041 if (hasAnyEnvironmentObject()) {
1042 env_ = &env_->as<EnvironmentObject>().enclosingEnvironment();
1044 incrementScopeIter();
1045 settle();
1048 EnvironmentIter& operator++() {
1049 operator++(1);
1050 return *this;
1053 // If done():
1054 JSObject& enclosingEnvironment() const;
1056 // If !done():
1057 bool hasNonSyntacticEnvironmentObject() const;
1059 bool hasSyntacticEnvironment() const { return si_.hasSyntacticEnvironment(); }
1061 bool hasAnyEnvironmentObject() const {
1062 return hasNonSyntacticEnvironmentObject() || hasSyntacticEnvironment();
1065 EnvironmentObject& environment() const {
1066 MOZ_ASSERT(hasAnyEnvironmentObject());
1067 return env_->as<EnvironmentObject>();
1070 Scope& scope() const { return *si_.scope(); }
1072 Scope* maybeScope() const {
1073 if (si_) {
1074 return si_.scope();
1076 return nullptr;
1079 JSFunction& callee() const { return env_->as<CallObject>().callee(); }
1081 bool withinInitialFrame() const { return !!frame_; }
1083 AbstractFramePtr initialFrame() const {
1084 MOZ_ASSERT(withinInitialFrame());
1085 return frame_;
1088 AbstractFramePtr maybeInitialFrame() const { return frame_; }
1091 // The key in MissingEnvironmentMap. For live frames, maps live frames to
1092 // their synthesized environments. For completely optimized-out environments,
1093 // maps the Scope to their synthesized environments. The env we synthesize for
1094 // Scopes are read-only, and we never use their parent links, so they don't
1095 // need to be distinct.
1097 // That is, completely optimized out environments can't be distinguished by
1098 // frame. Note that even if the frame corresponding to the Scope is live on
1099 // the stack, it is unsound to synthesize an environment from that live
1100 // frame. In other words, the provenance of the environment chain is from
1101 // allocated closures (i.e., allocation sites) and is irrecoverable from
1102 // simple stack inspection (i.e., call sites).
1103 class MissingEnvironmentKey {
1104 friend class LiveEnvironmentVal;
1106 AbstractFramePtr frame_;
1107 Scope* scope_;
1109 public:
1110 explicit MissingEnvironmentKey(const EnvironmentIter& ei)
1111 : frame_(ei.maybeInitialFrame()), scope_(ei.maybeScope()) {}
1113 MissingEnvironmentKey(AbstractFramePtr frame, Scope* scope)
1114 : frame_(frame), scope_(scope) {}
1116 AbstractFramePtr frame() const { return frame_; }
1117 Scope* scope() const { return scope_; }
1119 void updateScope(Scope* scope) { scope_ = scope; }
1120 void updateFrame(AbstractFramePtr frame) { frame_ = frame; }
1122 // For use as hash policy.
1123 using Lookup = MissingEnvironmentKey;
1124 static HashNumber hash(MissingEnvironmentKey sk);
1125 static bool match(MissingEnvironmentKey sk1, MissingEnvironmentKey sk2);
1126 bool operator!=(const MissingEnvironmentKey& other) const {
1127 return frame_ != other.frame_ || scope_ != other.scope_;
1129 static void rekey(MissingEnvironmentKey& k,
1130 const MissingEnvironmentKey& newKey) {
1131 k = newKey;
1135 // The value in LiveEnvironmentMap, mapped from by live environment objects.
1136 class LiveEnvironmentVal {
1137 friend class DebugEnvironments;
1138 friend class MissingEnvironmentKey;
1140 AbstractFramePtr frame_;
1141 HeapPtr<Scope*> scope_;
1143 static void staticAsserts();
1145 public:
1146 explicit LiveEnvironmentVal(const EnvironmentIter& ei)
1147 : frame_(ei.initialFrame()), scope_(ei.maybeScope()) {}
1149 AbstractFramePtr frame() const { return frame_; }
1151 void updateFrame(AbstractFramePtr frame) { frame_ = frame; }
1153 bool traceWeak(JSTracer* trc);
1156 /****************************************************************************/
1159 * [SMDOC] Debug environment objects
1161 * The frontend optimizes unaliased variables into stack slots and can optimize
1162 * away whole EnvironmentObjects. So when the debugger wants to perform an
1163 * unexpected eval-in-frame (or otherwise access the environment),
1164 * `fp->environmentChain` is often incomplete. This is a problem: a major use
1165 * case for eval-in-frame is to access the local variables in debuggee code.
1167 * Even when all EnvironmentObjects exist, giving complete information for all
1168 * bindings, stack and heap, there's another issue: eval-in-frame code can
1169 * create closures that capture stack locals. The variable slots go away when
1170 * the frame is popped, but the closure, which uses them, may survive.
1172 * To solve both problems, eval-in-frame code is compiled and run against a
1173 * "debug environment chain" of DebugEnvironmentProxy objects rather than real
1174 * EnvironmentObjects. The `GetDebugEnvironmentFor` functions below create
1175 * these proxies, one to sit in front of each existing EnvironmentObject. They
1176 * also create bogus "hollow" EnvironmentObjects to stand in for environments
1177 * that were optimized away; and proxies for those. The frontend sees these
1178 * environments as something like `with` scopes, and emits deoptimized bytecode
1179 * instructions for all variable accesses.
1181 * When eval-in-frame code runs, `fp->environmentChain` points to this chain of
1182 * proxies. On each variable access, the proxy laboriously figures out what to
1183 * do. See e.g. `DebuggerEnvironmentProxyHandler::handleUnaliasedAccess`.
1185 * There's a limit to what the proxies can manage, since they're proxying
1186 * environments that are already optimized. Some debugger operations, like
1187 * redefining a lexical binding, can fail when a true direct eval would
1188 * succeed. Even plain variable accesses can throw, if the variable has been
1189 * optimized away.
1191 * To support accessing stack variables after they've gone out of scope, we
1192 * copy the variables to the heap as they leave scope. See
1193 * `DebugEnvironments::onPopCall` and `onPopLexical`.
1195 * `GetDebugEnvironmentFor*` guarantees that the same DebugEnvironmentProxy is
1196 * always produced for the same underlying environment (optimized or not!).
1197 * This is maintained by some bookkeeping information stored in
1198 * `DebugEnvironments`.
1201 extern JSObject* GetDebugEnvironmentForFunction(JSContext* cx,
1202 HandleFunction fun);
1204 extern JSObject* GetDebugEnvironmentForSuspendedGenerator(
1205 JSContext* cx, JSScript* script, AbstractGeneratorObject& genObj);
1207 extern JSObject* GetDebugEnvironmentForFrame(JSContext* cx,
1208 AbstractFramePtr frame,
1209 jsbytecode* pc);
1211 extern JSObject* GetDebugEnvironmentForGlobalLexicalEnvironment(JSContext* cx);
1212 extern Scope* GetEnvironmentScope(const JSObject& env);
1214 /* Provides debugger access to a environment. */
1215 class DebugEnvironmentProxy : public ProxyObject {
1217 * The enclosing environment on the dynamic environment chain. This slot is
1218 * analogous to the ENCLOSING_ENV_SLOT of a EnvironmentObject.
1220 static const unsigned ENCLOSING_SLOT = 0;
1223 * NullValue or a dense array holding the unaliased variables of a function
1224 * frame that has been popped.
1226 static const unsigned SNAPSHOT_SLOT = 1;
1228 public:
1229 static DebugEnvironmentProxy* create(JSContext* cx, EnvironmentObject& env,
1230 HandleObject enclosing);
1232 // NOTE: The environment may be a debug hollow with invalid
1233 // enclosingEnvironment. Always use the enclosingEnvironment accessor on
1234 // the DebugEnvironmentProxy in order to walk the environment chain.
1235 EnvironmentObject& environment() const;
1236 JSObject& enclosingEnvironment() const;
1238 // May only be called for proxies to function call objects or modules
1239 // with top-level-await.
1240 ArrayObject* maybeSnapshot() const;
1241 void initSnapshot(ArrayObject& snapshot);
1243 // Currently, the 'declarative' environments are function, module, and
1244 // lexical environments.
1245 bool isForDeclarative() const;
1247 // Get a property by 'id', but returns sentinel values instead of throwing
1248 // on exceptional cases.
1249 static bool getMaybeSentinelValue(JSContext* cx,
1250 Handle<DebugEnvironmentProxy*> env,
1251 HandleId id, MutableHandleValue vp);
1253 // Returns true iff this is a function environment with its own this-binding
1254 // (all functions except arrow functions).
1255 bool isFunctionEnvironmentWithThis();
1257 // Does this debug environment not have a real counterpart or was never
1258 // live (and thus does not have a synthesized EnvironmentObject or a
1259 // snapshot)?
1260 bool isOptimizedOut() const;
1262 #if defined(DEBUG) || defined(JS_JITSPEW)
1263 void dump();
1264 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
1267 /* Maintains per-realm debug environment bookkeeping information. */
1268 class DebugEnvironments {
1269 Zone* zone_;
1271 /* The map from (non-debug) environments to debug environments. */
1272 ObjectWeakMap proxiedEnvs;
1275 * The map from live frames which have optimized-away environments to the
1276 * corresponding debug environments.
1278 typedef HashMap<MissingEnvironmentKey, WeakHeapPtr<DebugEnvironmentProxy*>,
1279 MissingEnvironmentKey, ZoneAllocPolicy>
1280 MissingEnvironmentMap;
1281 MissingEnvironmentMap missingEnvs;
1284 * The map from environment objects of live frames to the live frame. This
1285 * map updated lazily whenever the debugger needs the information. In
1286 * between two lazy updates, liveEnvs becomes incomplete (but not invalid,
1287 * onPop* removes environments as they are popped). Thus, two consecutive
1288 * debugger lazy updates of liveEnvs need only fill in the new
1289 * environments.
1291 typedef GCHashMap<WeakHeapPtr<JSObject*>, LiveEnvironmentVal,
1292 StableCellHasher<WeakHeapPtr<JSObject*>>, ZoneAllocPolicy>
1293 LiveEnvironmentMap;
1294 LiveEnvironmentMap liveEnvs;
1296 public:
1297 DebugEnvironments(JSContext* cx, Zone* zone);
1298 ~DebugEnvironments();
1300 Zone* zone() const { return zone_; }
1302 private:
1303 static DebugEnvironments* ensureRealmData(JSContext* cx);
1305 template <typename Environment, typename Scope>
1306 static void onPopGeneric(JSContext* cx, const EnvironmentIter& ei);
1308 public:
1309 void trace(JSTracer* trc);
1310 void traceWeak(JSTracer* trc);
1311 void finish();
1312 #ifdef JS_GC_ZEAL
1313 void checkHashTablesAfterMovingGC();
1314 #endif
1316 // If a live frame has a synthesized entry in missingEnvs, make sure it's not
1317 // collected.
1318 void traceLiveFrame(JSTracer* trc, AbstractFramePtr frame);
1320 static DebugEnvironmentProxy* hasDebugEnvironment(JSContext* cx,
1321 EnvironmentObject& env);
1322 static bool addDebugEnvironment(JSContext* cx, Handle<EnvironmentObject*> env,
1323 Handle<DebugEnvironmentProxy*> debugEnv);
1325 static DebugEnvironmentProxy* hasDebugEnvironment(JSContext* cx,
1326 const EnvironmentIter& ei);
1327 static bool addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
1328 Handle<DebugEnvironmentProxy*> debugEnv);
1330 static bool updateLiveEnvironments(JSContext* cx);
1331 static LiveEnvironmentVal* hasLiveEnvironment(EnvironmentObject& env);
1332 static void unsetPrevUpToDateUntil(JSContext* cx, AbstractFramePtr frame);
1334 // When a frame bails out from Ion to Baseline, there might be missing
1335 // envs keyed on, and live envs containing, the old
1336 // RematerializedFrame. Forward those values to the new BaselineFrame.
1337 static void forwardLiveFrame(JSContext* cx, AbstractFramePtr from,
1338 AbstractFramePtr to);
1340 // When an environment is popped, we store a snapshot of its bindings that
1341 // live on the frame.
1343 // This is done during frame unwinding, which cannot handle errors
1344 // gracefully. Errors result in no snapshot being set on the
1345 // DebugEnvironmentProxy.
1346 static void takeFrameSnapshot(JSContext* cx,
1347 Handle<DebugEnvironmentProxy*> debugEnv,
1348 AbstractFramePtr frame);
1350 // In debug-mode, these must be called whenever exiting a scope that might
1351 // have stack-allocated locals.
1352 static void onPopCall(JSContext* cx, AbstractFramePtr frame);
1353 static void onPopVar(JSContext* cx, const EnvironmentIter& ei);
1354 static void onPopLexical(JSContext* cx, const EnvironmentIter& ei);
1355 static void onPopLexical(JSContext* cx, AbstractFramePtr frame,
1356 const jsbytecode* pc);
1357 static void onPopWith(AbstractFramePtr frame);
1358 static void onPopModule(JSContext* cx, const EnvironmentIter& ei);
1359 static void onRealmUnsetIsDebuggee(Realm* realm);
1362 } /* namespace js */
1364 template <>
1365 inline bool JSObject::is<js::EnvironmentObject>() const {
1366 return is<js::CallObject>() || is<js::VarEnvironmentObject>() ||
1367 is<js::ModuleEnvironmentObject>() ||
1368 is<js::WasmInstanceEnvironmentObject>() ||
1369 is<js::WasmFunctionCallObject>() ||
1370 is<js::LexicalEnvironmentObject>() ||
1371 is<js::WithEnvironmentObject>() ||
1372 is<js::NonSyntacticVariablesObject>() ||
1373 is<js::RuntimeLexicalErrorObject>();
1376 template <>
1377 inline bool JSObject::is<js::ScopedLexicalEnvironmentObject>() const {
1378 return is<js::LexicalEnvironmentObject>() &&
1379 !as<js::LexicalEnvironmentObject>().isExtensible();
1382 template <>
1383 inline bool JSObject::is<js::BlockLexicalEnvironmentObject>() const {
1384 return is<js::ScopedLexicalEnvironmentObject>() &&
1385 !as<js::ScopedLexicalEnvironmentObject>().isClassBody();
1388 template <>
1389 inline bool JSObject::is<js::ClassBodyLexicalEnvironmentObject>() const {
1390 return is<js::ScopedLexicalEnvironmentObject>() &&
1391 as<js::ScopedLexicalEnvironmentObject>().isClassBody();
1394 template <>
1395 inline bool JSObject::is<js::ExtensibleLexicalEnvironmentObject>() const {
1396 return is<js::LexicalEnvironmentObject>() &&
1397 as<js::LexicalEnvironmentObject>().isExtensible();
1400 template <>
1401 inline bool JSObject::is<js::GlobalLexicalEnvironmentObject>() const {
1402 return is<js::LexicalEnvironmentObject>() &&
1403 as<js::LexicalEnvironmentObject>().isGlobal();
1406 template <>
1407 inline bool JSObject::is<js::NonSyntacticLexicalEnvironmentObject>() const {
1408 return is<js::LexicalEnvironmentObject>() &&
1409 !as<js::LexicalEnvironmentObject>().isSyntactic();
1412 template <>
1413 inline bool JSObject::is<js::NamedLambdaObject>() const {
1414 return is<js::BlockLexicalEnvironmentObject>() &&
1415 as<js::BlockLexicalEnvironmentObject>().scope().isNamedLambda();
1418 template <>
1419 bool JSObject::is<js::DebugEnvironmentProxy>() const;
1421 namespace js {
1423 inline bool IsSyntacticEnvironment(JSObject* env) {
1424 if (!env->is<EnvironmentObject>()) {
1425 return false;
1428 if (env->is<WithEnvironmentObject>()) {
1429 return env->as<WithEnvironmentObject>().isSyntactic();
1432 if (env->is<LexicalEnvironmentObject>()) {
1433 return env->as<LexicalEnvironmentObject>().isSyntactic();
1436 if (env->is<NonSyntacticVariablesObject>()) {
1437 return false;
1440 return true;
1443 inline bool IsExtensibleLexicalEnvironment(JSObject* env) {
1444 return env->is<ExtensibleLexicalEnvironmentObject>();
1447 inline bool IsGlobalLexicalEnvironment(JSObject* env) {
1448 return env->is<GlobalLexicalEnvironmentObject>();
1451 inline bool IsNSVOLexicalEnvironment(JSObject* env) {
1452 return env->is<LexicalEnvironmentObject>() &&
1453 env->as<LexicalEnvironmentObject>()
1454 .enclosingEnvironment()
1455 .is<NonSyntacticVariablesObject>();
1458 inline JSObject* MaybeUnwrapWithEnvironment(JSObject* env) {
1459 if (env->is<WithEnvironmentObject>()) {
1460 return &env->as<WithEnvironmentObject>().object();
1462 return env;
1465 template <typename SpecificEnvironment>
1466 inline bool IsFrameInitialEnvironment(AbstractFramePtr frame,
1467 SpecificEnvironment& env) {
1468 // A frame's initial environment is the innermost environment
1469 // corresponding to the scope chain from frame.script()->bodyScope() to
1470 // frame.script()->outermostScope(). This environment must be on the chain
1471 // for the frame to be considered initialized. That is, it must be on the
1472 // chain for the environment chain to fully match the scope chain at the
1473 // start of execution in the frame.
1475 // This logic must be in sync with the HAS_INITIAL_ENV logic in
1476 // BaselineStackBuilder::buildBaselineFrame.
1478 // A function frame's CallObject, if present, is always the initial
1479 // environment.
1480 if constexpr (std::is_same_v<SpecificEnvironment, CallObject>) {
1481 return true;
1484 // For an eval frame, the VarEnvironmentObject, if present, is always the
1485 // initial environment.
1486 if constexpr (std::is_same_v<SpecificEnvironment, VarEnvironmentObject>) {
1487 if (frame.isEvalFrame()) {
1488 return true;
1492 // For named lambda frames without CallObjects (i.e., no binding in the
1493 // body of the function was closed over), the NamedLambdaObject
1494 // corresponding to the named lambda scope is the initial environment.
1495 if constexpr (std::is_same_v<SpecificEnvironment, NamedLambdaObject>) {
1496 if (frame.isFunctionFrame() &&
1497 frame.callee()->needsNamedLambdaEnvironment() &&
1498 !frame.callee()->needsCallObject()) {
1499 LexicalScope* namedLambdaScope = frame.script()->maybeNamedLambdaScope();
1500 return &env.scope() == namedLambdaScope;
1504 return false;
1507 extern bool CreateObjectsForEnvironmentChain(JSContext* cx,
1508 HandleObjectVector chain,
1509 HandleObject terminatingEnv,
1510 MutableHandleObject envObj);
1512 ModuleObject* GetModuleObjectForScript(JSScript* script);
1514 ModuleEnvironmentObject* GetModuleEnvironmentForScript(JSScript* script);
1516 [[nodiscard]] bool GetThisValueForDebuggerFrameMaybeOptimizedOut(
1517 JSContext* cx, AbstractFramePtr frame, const jsbytecode* pc,
1518 MutableHandleValue res);
1519 [[nodiscard]] bool GetThisValueForDebuggerSuspendedGeneratorMaybeOptimizedOut(
1520 JSContext* cx, AbstractGeneratorObject& genObj, JSScript* script,
1521 MutableHandleValue res);
1523 [[nodiscard]] bool CheckCanDeclareGlobalBinding(JSContext* cx,
1524 Handle<GlobalObject*> global,
1525 Handle<PropertyName*> name,
1526 bool isFunction);
1528 [[nodiscard]] bool CheckLexicalNameConflict(
1529 JSContext* cx, Handle<ExtensibleLexicalEnvironmentObject*> lexicalEnv,
1530 HandleObject varObj, Handle<PropertyName*> name);
1532 [[nodiscard]] bool CheckGlobalDeclarationConflicts(
1533 JSContext* cx, HandleScript script,
1534 Handle<ExtensibleLexicalEnvironmentObject*> lexicalEnv,
1535 HandleObject varObj);
1537 [[nodiscard]] bool GlobalOrEvalDeclInstantiation(JSContext* cx,
1538 HandleObject envChain,
1539 HandleScript script,
1540 GCThingIndex lastFun);
1542 [[nodiscard]] bool InitFunctionEnvironmentObjects(JSContext* cx,
1543 AbstractFramePtr frame);
1545 [[nodiscard]] bool PushVarEnvironmentObject(JSContext* cx, Handle<Scope*> scope,
1546 AbstractFramePtr frame);
1548 [[nodiscard]] bool GetFrameEnvironmentAndScope(JSContext* cx,
1549 AbstractFramePtr frame,
1550 const jsbytecode* pc,
1551 MutableHandleObject env,
1552 MutableHandle<Scope*> scope);
1554 void GetSuspendedGeneratorEnvironmentAndScope(AbstractGeneratorObject& genObj,
1555 JSScript* script,
1556 MutableHandleObject env,
1557 MutableHandle<Scope*> scope);
1559 #ifdef DEBUG
1560 bool AnalyzeEntrainedVariables(JSContext* cx, HandleScript script);
1561 #endif
1563 extern JSObject* MaybeOptimizeBindGlobalName(JSContext* cx,
1564 Handle<GlobalObject*> global,
1565 Handle<PropertyName*> name);
1566 } // namespace js
1568 #endif /* vm_EnvironmentObject_h */