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"
21 #include "vm/ScopeKind.h" // ScopeKind
25 class AbstractGeneratorObject
;
26 class IndirectBindingMap
;
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
,
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
,
41 /*** Environment objects ****************************************************/
45 * [SMDOC] Environment Objects
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:
73 * | +--EnvironmentObject Engine-internal environment
75 * | | +--CallObject Environment of entire function
77 * | | +--VarEnvironmentObject See VarScope in Scope.h.
79 * | | +--ModuleEnvironmentObject
80 * | | | Module top-level environment
82 * | | +--WasmInstanceEnvironmentObject
84 * | | +--WasmFunctionCallObject
86 * | | +--LexicalEnvironmentObject
88 * | | | +--ScopedLexicalEnvironmentObject
89 * | | | | | Non-extensible lexical environment
91 * | | | | +--BlockLexicalEnvironmentObject
92 * | | | | | | Blocks and such: syntactic,
93 * | | | | | | non-extensible
95 * | | | | | +--NamedLambdaObject
96 * | | | | | Environment for `(function f(){...})`
97 * | | | | | containing only a binding for `f`
99 * | | | | +--ClassBodyLexicalEnvironmentObject
100 * | | | | Environment for class body, containing
101 * | | | | private names, private brands, and
102 * | | | | static initializers list
104 * | | | +--ExtensibleLexicalEnvironmentObject
106 * | | | +--GlobalLexicalEnvironmentObject
107 * | | | | Top-level let/const/class in scripts
109 * | | | +--NonSyntacticLexicalEnvironmentObject
110 * | | | See "Non-syntactic environments" below
112 * | | +--NonSyntacticVariablesObject
113 * | | | See "Non-syntactic environments" below
115 * | | +--WithEnvironmentObject Presents object properties as bindings
117 * | | +--RuntimeLexicalErrorObject
118 * | | Special value represents uninitialized
121 * | +--GlobalObject The global environment (dynamically
122 * | presents its properties as bindings)
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.
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
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
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
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]
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
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
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.
460 class EnvironmentObject
: public NativeObject
{
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
);
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
);
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)
514 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
517 class CallObject
: public EnvironmentObject
{
519 static constexpr uint32_t CALLEE_SLOT
= 1;
521 static CallObject
* create(JSContext
* cx
, HandleScript script
,
522 HandleObject enclosing
, gc::Heap heap
);
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
,
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
,
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
));
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
>());
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_
;
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
);
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
,
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
676 static constexpr uint32_t SCOPE_SLOT
= 1;
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
698 static constexpr uint32_t SCOPE_SLOT
= 1;
701 static const JSClass class_
;
703 // TODO Check what Debugger behavior should be when it evaluates a
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
720 class LexicalEnvironmentObject
: public EnvironmentObject
{
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;
730 static const JSClass class_
;
732 static constexpr uint32_t RESERVED_SLOTS
= 2;
735 static LexicalEnvironmentObject
* create(JSContext
* cx
,
736 Handle
<SharedShape
*> shape
,
737 HandleObject enclosing
,
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
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
{
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
{
776 static BlockLexicalEnvironmentObject
* create(JSContext
* cx
,
777 Handle
<LexicalScope
*> scope
,
778 HandleObject enclosing
,
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
);
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
);
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
,
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
{
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
);
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
877 class GlobalLexicalEnvironmentObject
878 : public ExtensibleLexicalEnvironmentObject
{
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
{
898 static NonSyntacticLexicalEnvironmentObject
* create(JSContext
* cx
,
899 HandleObject enclosing
,
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 // See the long "Non-syntactic Environments" comment above.
909 class NonSyntacticVariablesObject
: public EnvironmentObject
{
911 static const JSClass class_
;
913 static constexpr uint32_t RESERVED_SLOTS
= 1;
914 static constexpr ObjectFlags OBJECT_FLAGS
= {};
916 static NonSyntacticVariablesObject
* create(JSContext
* cx
);
919 extern bool CreateNonSyntacticEnvironmentChain(JSContext
* cx
,
920 JS::HandleObjectVector envChain
,
921 MutableHandleObject env
);
923 // With environment objects on the run-time environment chain.
924 class WithEnvironmentObject
: public EnvironmentObject
{
925 static constexpr uint32_t OBJECT_SLOT
= 1;
926 static constexpr uint32_t THIS_SLOT
= 2;
927 static constexpr uint32_t SCOPE_SLOT
= 3;
930 static const JSClass class_
;
932 static constexpr uint32_t RESERVED_SLOTS
= 4;
933 static constexpr ObjectFlags OBJECT_FLAGS
= {};
935 static WithEnvironmentObject
* create(JSContext
* cx
, HandleObject object
,
936 HandleObject enclosing
,
937 Handle
<WithScope
*> scope
);
938 static WithEnvironmentObject
* createNonSyntactic(JSContext
* cx
,
940 HandleObject enclosing
);
942 /* Return the 'o' in 'with (o)'. */
943 JSObject
& object() const;
945 /* Return object for GetThisValue. */
946 JSObject
* withThis() const;
949 * Return whether this object is a syntactic with object. If not, this is
950 * a With object we inserted between the outermost syntactic scope and the
951 * global object to wrap the environment chain someone explicitly passed
952 * via JSAPI to CompileFunction or script evaluation.
954 bool isSyntactic() const;
956 // For syntactic with environment objects, the with scope.
957 WithScope
& scope() const;
959 static inline size_t objectSlot() { return OBJECT_SLOT
; }
961 static inline size_t thisSlot() { return THIS_SLOT
; }
964 // Internal scope object used by JSOp::BindName upon encountering an
965 // uninitialized lexical slot or an assignment to a 'const' binding.
967 // ES6 lexical bindings cannot be accessed in any way (throwing
968 // ReferenceErrors) until initialized. Normally, NAME operations
969 // unconditionally check for uninitialized lexical slots. When getting or
970 // looking up names, this can be done without slowing down normal operations
971 // on the return value. When setting names, however, we do not want to pollute
972 // all set-property paths with uninitialized lexical checks. For setting names
973 // (i.e. JSOp::SetName), we emit an accompanying, preceding JSOp::BindName which
974 // finds the right scope on which to set the name. Moreover, when the name on
975 // the scope is an uninitialized lexical, we cannot throw eagerly, as the spec
976 // demands that the error be thrown after evaluating the RHS of
977 // assignments. Instead, this sentinel scope object is pushed on the stack.
978 // Attempting to access anything on this scope throws the appropriate
981 // ES6 'const' bindings induce a runtime error when assigned to outside
982 // of initialization, regardless of strictness.
983 class RuntimeLexicalErrorObject
: public EnvironmentObject
{
984 static const unsigned ERROR_SLOT
= 1;
987 static const unsigned RESERVED_SLOTS
= 2;
988 static const JSClass class_
;
990 static RuntimeLexicalErrorObject
* create(JSContext
* cx
,
991 HandleObject enclosing
,
992 unsigned errorNumber
);
994 unsigned errorNumber() { return getReservedSlot(ERROR_SLOT
).toInt32(); }
997 /****************************************************************************/
999 // A environment iterator describes the active environments starting from an
1000 // environment, scope pair. This pair may be derived from the current point of
1001 // execution in a frame. If derived in such a fashion, the EnvironmentIter
1002 // tracks whether the current scope is within the extent of this initial
1003 // frame. Here, "frame" means a single activation of: a function, eval, or
1005 class MOZ_RAII EnvironmentIter
{
1006 Rooted
<ScopeIter
> si_
;
1008 AbstractFramePtr frame_
;
1010 void incrementScopeIter();
1013 // No value semantics.
1014 EnvironmentIter(const EnvironmentIter
& ei
) = delete;
1017 // Constructing from a copy of an existing EnvironmentIter.
1018 EnvironmentIter(JSContext
* cx
, const EnvironmentIter
& ei
);
1020 // Constructing from an environment, scope pair. All environments
1021 // considered not to be withinInitialFrame, since no frame is given.
1022 EnvironmentIter(JSContext
* cx
, JSObject
* env
, Scope
* scope
);
1024 // Constructing from a frame. Places the EnvironmentIter on the innermost
1025 // environment at pc.
1026 EnvironmentIter(JSContext
* cx
, AbstractFramePtr frame
, const jsbytecode
* pc
);
1028 // Constructing from an environment, scope and frame. The frame is given
1029 // to initialize to proper enclosing environment/scope.
1030 EnvironmentIter(JSContext
* cx
, JSObject
* env
, Scope
* scope
,
1031 AbstractFramePtr frame
);
1033 bool done() const { return si_
.done(); }
1035 explicit operator bool() const { return !done(); }
1037 void operator++(int) {
1038 if (hasAnyEnvironmentObject()) {
1039 env_
= &env_
->as
<EnvironmentObject
>().enclosingEnvironment();
1041 incrementScopeIter();
1045 EnvironmentIter
& operator++() {
1051 JSObject
& enclosingEnvironment() const;
1054 bool hasNonSyntacticEnvironmentObject() const;
1056 bool hasSyntacticEnvironment() const { return si_
.hasSyntacticEnvironment(); }
1058 bool hasAnyEnvironmentObject() const {
1059 return hasNonSyntacticEnvironmentObject() || hasSyntacticEnvironment();
1062 EnvironmentObject
& environment() const {
1063 MOZ_ASSERT(hasAnyEnvironmentObject());
1064 return env_
->as
<EnvironmentObject
>();
1067 Scope
& scope() const { return *si_
.scope(); }
1069 Scope
* maybeScope() const {
1076 JSFunction
& callee() const { return env_
->as
<CallObject
>().callee(); }
1078 bool withinInitialFrame() const { return !!frame_
; }
1080 AbstractFramePtr
initialFrame() const {
1081 MOZ_ASSERT(withinInitialFrame());
1085 AbstractFramePtr
maybeInitialFrame() const { return frame_
; }
1088 // The key in MissingEnvironmentMap. For live frames, maps live frames to
1089 // their synthesized environments. For completely optimized-out environments,
1090 // maps the Scope to their synthesized environments. The env we synthesize for
1091 // Scopes are read-only, and we never use their parent links, so they don't
1092 // need to be distinct.
1094 // That is, completely optimized out environments can't be distinguished by
1095 // frame. Note that even if the frame corresponding to the Scope is live on
1096 // the stack, it is unsound to synthesize an environment from that live
1097 // frame. In other words, the provenance of the environment chain is from
1098 // allocated closures (i.e., allocation sites) and is irrecoverable from
1099 // simple stack inspection (i.e., call sites).
1100 class MissingEnvironmentKey
{
1101 friend class LiveEnvironmentVal
;
1103 AbstractFramePtr frame_
;
1107 explicit MissingEnvironmentKey(const EnvironmentIter
& ei
)
1108 : frame_(ei
.maybeInitialFrame()), scope_(ei
.maybeScope()) {}
1110 MissingEnvironmentKey(AbstractFramePtr frame
, Scope
* scope
)
1111 : frame_(frame
), scope_(scope
) {}
1113 AbstractFramePtr
frame() const { return frame_
; }
1114 Scope
* scope() const { return scope_
; }
1116 void updateScope(Scope
* scope
) { scope_
= scope
; }
1117 void updateFrame(AbstractFramePtr frame
) { frame_
= frame
; }
1119 // For use as hash policy.
1120 using Lookup
= MissingEnvironmentKey
;
1121 static HashNumber
hash(MissingEnvironmentKey sk
);
1122 static bool match(MissingEnvironmentKey sk1
, MissingEnvironmentKey sk2
);
1123 bool operator!=(const MissingEnvironmentKey
& other
) const {
1124 return frame_
!= other
.frame_
|| scope_
!= other
.scope_
;
1126 static void rekey(MissingEnvironmentKey
& k
,
1127 const MissingEnvironmentKey
& newKey
) {
1132 // The value in LiveEnvironmentMap, mapped from by live environment objects.
1133 class LiveEnvironmentVal
{
1134 friend class DebugEnvironments
;
1135 friend class MissingEnvironmentKey
;
1137 AbstractFramePtr frame_
;
1138 HeapPtr
<Scope
*> scope_
;
1140 static void staticAsserts();
1143 explicit LiveEnvironmentVal(const EnvironmentIter
& ei
)
1144 : frame_(ei
.initialFrame()), scope_(ei
.maybeScope()) {}
1146 AbstractFramePtr
frame() const { return frame_
; }
1148 void updateFrame(AbstractFramePtr frame
) { frame_
= frame
; }
1150 bool traceWeak(JSTracer
* trc
);
1153 /****************************************************************************/
1156 * [SMDOC] Debug environment objects
1158 * The frontend optimizes unaliased variables into stack slots and can optimize
1159 * away whole EnvironmentObjects. So when the debugger wants to perform an
1160 * unexpected eval-in-frame (or otherwise access the environment),
1161 * `fp->environmentChain` is often incomplete. This is a problem: a major use
1162 * case for eval-in-frame is to access the local variables in debuggee code.
1164 * Even when all EnvironmentObjects exist, giving complete information for all
1165 * bindings, stack and heap, there's another issue: eval-in-frame code can
1166 * create closures that capture stack locals. The variable slots go away when
1167 * the frame is popped, but the closure, which uses them, may survive.
1169 * To solve both problems, eval-in-frame code is compiled and run against a
1170 * "debug environment chain" of DebugEnvironmentProxy objects rather than real
1171 * EnvironmentObjects. The `GetDebugEnvironmentFor` functions below create
1172 * these proxies, one to sit in front of each existing EnvironmentObject. They
1173 * also create bogus "hollow" EnvironmentObjects to stand in for environments
1174 * that were optimized away; and proxies for those. The frontend sees these
1175 * environments as something like `with` scopes, and emits deoptimized bytecode
1176 * instructions for all variable accesses.
1178 * When eval-in-frame code runs, `fp->environmentChain` points to this chain of
1179 * proxies. On each variable access, the proxy laboriously figures out what to
1180 * do. See e.g. `DebuggerEnvironmentProxyHandler::handleUnaliasedAccess`.
1182 * There's a limit to what the proxies can manage, since they're proxying
1183 * environments that are already optimized. Some debugger operations, like
1184 * redefining a lexical binding, can fail when a true direct eval would
1185 * succeed. Even plain variable accesses can throw, if the variable has been
1188 * To support accessing stack variables after they've gone out of scope, we
1189 * copy the variables to the heap as they leave scope. See
1190 * `DebugEnvironments::onPopCall` and `onPopLexical`.
1192 * `GetDebugEnvironmentFor*` guarantees that the same DebugEnvironmentProxy is
1193 * always produced for the same underlying environment (optimized or not!).
1194 * This is maintained by some bookkeeping information stored in
1195 * `DebugEnvironments`.
1198 extern JSObject
* GetDebugEnvironmentForFunction(JSContext
* cx
,
1199 HandleFunction fun
);
1201 extern JSObject
* GetDebugEnvironmentForSuspendedGenerator(
1202 JSContext
* cx
, JSScript
* script
, AbstractGeneratorObject
& genObj
);
1204 extern JSObject
* GetDebugEnvironmentForFrame(JSContext
* cx
,
1205 AbstractFramePtr frame
,
1208 extern JSObject
* GetDebugEnvironmentForGlobalLexicalEnvironment(JSContext
* cx
);
1209 extern Scope
* GetEnvironmentScope(const JSObject
& env
);
1211 /* Provides debugger access to a environment. */
1212 class DebugEnvironmentProxy
: public ProxyObject
{
1214 * The enclosing environment on the dynamic environment chain. This slot is
1215 * analogous to the ENCLOSING_ENV_SLOT of a EnvironmentObject.
1217 static const unsigned ENCLOSING_SLOT
= 0;
1220 * NullValue or a dense array holding the unaliased variables of a function
1221 * frame that has been popped.
1223 static const unsigned SNAPSHOT_SLOT
= 1;
1226 static DebugEnvironmentProxy
* create(JSContext
* cx
, EnvironmentObject
& env
,
1227 HandleObject enclosing
);
1229 // NOTE: The environment may be a debug hollow with invalid
1230 // enclosingEnvironment. Always use the enclosingEnvironment accessor on
1231 // the DebugEnvironmentProxy in order to walk the environment chain.
1232 EnvironmentObject
& environment() const;
1233 JSObject
& enclosingEnvironment() const;
1235 // May only be called for proxies to function call objects or modules
1236 // with top-level-await.
1237 ArrayObject
* maybeSnapshot() const;
1238 void initSnapshot(ArrayObject
& snapshot
);
1240 // Currently, the 'declarative' environments are function, module, and
1241 // lexical environments.
1242 bool isForDeclarative() const;
1244 // Get a property by 'id', but returns sentinel values instead of throwing
1245 // on exceptional cases.
1246 static bool getMaybeSentinelValue(JSContext
* cx
,
1247 Handle
<DebugEnvironmentProxy
*> env
,
1248 HandleId id
, MutableHandleValue vp
);
1250 // Returns true iff this is a function environment with its own this-binding
1251 // (all functions except arrow functions).
1252 bool isFunctionEnvironmentWithThis();
1254 // Does this debug environment not have a real counterpart or was never
1255 // live (and thus does not have a synthesized EnvironmentObject or a
1257 bool isOptimizedOut() const;
1259 #if defined(DEBUG) || defined(JS_JITSPEW)
1261 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
1264 /* Maintains per-realm debug environment bookkeeping information. */
1265 class DebugEnvironments
{
1268 /* The map from (non-debug) environments to debug environments. */
1269 ObjectWeakMap proxiedEnvs
;
1272 * The map from live frames which have optimized-away environments to the
1273 * corresponding debug environments.
1275 typedef HashMap
<MissingEnvironmentKey
, WeakHeapPtr
<DebugEnvironmentProxy
*>,
1276 MissingEnvironmentKey
, ZoneAllocPolicy
>
1277 MissingEnvironmentMap
;
1278 MissingEnvironmentMap missingEnvs
;
1281 * The map from environment objects of live frames to the live frame. This
1282 * map updated lazily whenever the debugger needs the information. In
1283 * between two lazy updates, liveEnvs becomes incomplete (but not invalid,
1284 * onPop* removes environments as they are popped). Thus, two consecutive
1285 * debugger lazy updates of liveEnvs need only fill in the new
1288 typedef GCHashMap
<WeakHeapPtr
<JSObject
*>, LiveEnvironmentVal
,
1289 StableCellHasher
<WeakHeapPtr
<JSObject
*>>, ZoneAllocPolicy
>
1291 LiveEnvironmentMap liveEnvs
;
1294 DebugEnvironments(JSContext
* cx
, Zone
* zone
);
1295 ~DebugEnvironments();
1297 Zone
* zone() const { return zone_
; }
1300 static DebugEnvironments
* ensureRealmData(JSContext
* cx
);
1302 template <typename Environment
, typename Scope
>
1303 static void onPopGeneric(JSContext
* cx
, const EnvironmentIter
& ei
);
1306 void trace(JSTracer
* trc
);
1307 void traceWeak(JSTracer
* trc
);
1310 void checkHashTablesAfterMovingGC();
1313 // If a live frame has a synthesized entry in missingEnvs, make sure it's not
1315 void traceLiveFrame(JSTracer
* trc
, AbstractFramePtr frame
);
1317 static DebugEnvironmentProxy
* hasDebugEnvironment(JSContext
* cx
,
1318 EnvironmentObject
& env
);
1319 static bool addDebugEnvironment(JSContext
* cx
, Handle
<EnvironmentObject
*> env
,
1320 Handle
<DebugEnvironmentProxy
*> debugEnv
);
1322 static DebugEnvironmentProxy
* hasDebugEnvironment(JSContext
* cx
,
1323 const EnvironmentIter
& ei
);
1324 static bool addDebugEnvironment(JSContext
* cx
, const EnvironmentIter
& ei
,
1325 Handle
<DebugEnvironmentProxy
*> debugEnv
);
1327 static bool updateLiveEnvironments(JSContext
* cx
);
1328 static LiveEnvironmentVal
* hasLiveEnvironment(EnvironmentObject
& env
);
1329 static void unsetPrevUpToDateUntil(JSContext
* cx
, AbstractFramePtr frame
);
1331 // When a frame bails out from Ion to Baseline, there might be missing
1332 // envs keyed on, and live envs containing, the old
1333 // RematerializedFrame. Forward those values to the new BaselineFrame.
1334 static void forwardLiveFrame(JSContext
* cx
, AbstractFramePtr from
,
1335 AbstractFramePtr to
);
1337 // When an environment is popped, we store a snapshot of its bindings that
1338 // live on the frame.
1340 // This is done during frame unwinding, which cannot handle errors
1341 // gracefully. Errors result in no snapshot being set on the
1342 // DebugEnvironmentProxy.
1343 static void takeFrameSnapshot(JSContext
* cx
,
1344 Handle
<DebugEnvironmentProxy
*> debugEnv
,
1345 AbstractFramePtr frame
);
1347 // In debug-mode, these must be called whenever exiting a scope that might
1348 // have stack-allocated locals.
1349 static void onPopCall(JSContext
* cx
, AbstractFramePtr frame
);
1350 static void onPopVar(JSContext
* cx
, const EnvironmentIter
& ei
);
1351 static void onPopLexical(JSContext
* cx
, const EnvironmentIter
& ei
);
1352 static void onPopLexical(JSContext
* cx
, AbstractFramePtr frame
,
1353 const jsbytecode
* pc
);
1354 static void onPopWith(AbstractFramePtr frame
);
1355 static void onPopModule(JSContext
* cx
, const EnvironmentIter
& ei
);
1356 static void onRealmUnsetIsDebuggee(Realm
* realm
);
1359 } /* namespace js */
1362 inline bool JSObject::is
<js::EnvironmentObject
>() const {
1363 return is
<js::CallObject
>() || is
<js::VarEnvironmentObject
>() ||
1364 is
<js::ModuleEnvironmentObject
>() ||
1365 is
<js::WasmInstanceEnvironmentObject
>() ||
1366 is
<js::WasmFunctionCallObject
>() ||
1367 is
<js::LexicalEnvironmentObject
>() ||
1368 is
<js::WithEnvironmentObject
>() ||
1369 is
<js::NonSyntacticVariablesObject
>() ||
1370 is
<js::RuntimeLexicalErrorObject
>();
1374 inline bool JSObject::is
<js::ScopedLexicalEnvironmentObject
>() const {
1375 return is
<js::LexicalEnvironmentObject
>() &&
1376 !as
<js::LexicalEnvironmentObject
>().isExtensible();
1380 inline bool JSObject::is
<js::BlockLexicalEnvironmentObject
>() const {
1381 return is
<js::ScopedLexicalEnvironmentObject
>() &&
1382 !as
<js::ScopedLexicalEnvironmentObject
>().isClassBody();
1386 inline bool JSObject::is
<js::ClassBodyLexicalEnvironmentObject
>() const {
1387 return is
<js::ScopedLexicalEnvironmentObject
>() &&
1388 as
<js::ScopedLexicalEnvironmentObject
>().isClassBody();
1392 inline bool JSObject::is
<js::ExtensibleLexicalEnvironmentObject
>() const {
1393 return is
<js::LexicalEnvironmentObject
>() &&
1394 as
<js::LexicalEnvironmentObject
>().isExtensible();
1398 inline bool JSObject::is
<js::GlobalLexicalEnvironmentObject
>() const {
1399 return is
<js::LexicalEnvironmentObject
>() &&
1400 as
<js::LexicalEnvironmentObject
>().isGlobal();
1404 inline bool JSObject::is
<js::NonSyntacticLexicalEnvironmentObject
>() const {
1405 return is
<js::LexicalEnvironmentObject
>() &&
1406 !as
<js::LexicalEnvironmentObject
>().isSyntactic();
1410 inline bool JSObject::is
<js::NamedLambdaObject
>() const {
1411 return is
<js::BlockLexicalEnvironmentObject
>() &&
1412 as
<js::BlockLexicalEnvironmentObject
>().scope().isNamedLambda();
1416 bool JSObject::is
<js::DebugEnvironmentProxy
>() const;
1420 inline bool IsSyntacticEnvironment(JSObject
* env
) {
1421 if (!env
->is
<EnvironmentObject
>()) {
1425 if (env
->is
<WithEnvironmentObject
>()) {
1426 return env
->as
<WithEnvironmentObject
>().isSyntactic();
1429 if (env
->is
<LexicalEnvironmentObject
>()) {
1430 return env
->as
<LexicalEnvironmentObject
>().isSyntactic();
1433 if (env
->is
<NonSyntacticVariablesObject
>()) {
1440 inline bool IsExtensibleLexicalEnvironment(JSObject
* env
) {
1441 return env
->is
<ExtensibleLexicalEnvironmentObject
>();
1444 inline bool IsGlobalLexicalEnvironment(JSObject
* env
) {
1445 return env
->is
<GlobalLexicalEnvironmentObject
>();
1448 inline bool IsNSVOLexicalEnvironment(JSObject
* env
) {
1449 return env
->is
<LexicalEnvironmentObject
>() &&
1450 env
->as
<LexicalEnvironmentObject
>()
1451 .enclosingEnvironment()
1452 .is
<NonSyntacticVariablesObject
>();
1455 inline JSObject
* MaybeUnwrapWithEnvironment(JSObject
* env
) {
1456 if (env
->is
<WithEnvironmentObject
>()) {
1457 return &env
->as
<WithEnvironmentObject
>().object();
1462 template <typename SpecificEnvironment
>
1463 inline bool IsFrameInitialEnvironment(AbstractFramePtr frame
,
1464 SpecificEnvironment
& env
) {
1465 // A frame's initial environment is the innermost environment
1466 // corresponding to the scope chain from frame.script()->bodyScope() to
1467 // frame.script()->outermostScope(). This environment must be on the chain
1468 // for the frame to be considered initialized. That is, it must be on the
1469 // chain for the environment chain to fully match the scope chain at the
1470 // start of execution in the frame.
1472 // This logic must be in sync with the HAS_INITIAL_ENV logic in
1473 // BaselineStackBuilder::buildBaselineFrame.
1475 // A function frame's CallObject, if present, is always the initial
1477 if constexpr (std::is_same_v
<SpecificEnvironment
, CallObject
>) {
1481 // For an eval frame, the VarEnvironmentObject, if present, is always the
1482 // initial environment.
1483 if constexpr (std::is_same_v
<SpecificEnvironment
, VarEnvironmentObject
>) {
1484 if (frame
.isEvalFrame()) {
1489 // For named lambda frames without CallObjects (i.e., no binding in the
1490 // body of the function was closed over), the NamedLambdaObject
1491 // corresponding to the named lambda scope is the initial environment.
1492 if constexpr (std::is_same_v
<SpecificEnvironment
, NamedLambdaObject
>) {
1493 if (frame
.isFunctionFrame() &&
1494 frame
.callee()->needsNamedLambdaEnvironment() &&
1495 !frame
.callee()->needsCallObject()) {
1496 LexicalScope
* namedLambdaScope
= frame
.script()->maybeNamedLambdaScope();
1497 return &env
.scope() == namedLambdaScope
;
1504 extern bool CreateObjectsForEnvironmentChain(JSContext
* cx
,
1505 HandleObjectVector chain
,
1506 HandleObject terminatingEnv
,
1507 MutableHandleObject envObj
);
1509 ModuleObject
* GetModuleObjectForScript(JSScript
* script
);
1511 ModuleEnvironmentObject
* GetModuleEnvironmentForScript(JSScript
* script
);
1513 [[nodiscard
]] bool GetThisValueForDebuggerFrameMaybeOptimizedOut(
1514 JSContext
* cx
, AbstractFramePtr frame
, const jsbytecode
* pc
,
1515 MutableHandleValue res
);
1516 [[nodiscard
]] bool GetThisValueForDebuggerSuspendedGeneratorMaybeOptimizedOut(
1517 JSContext
* cx
, AbstractGeneratorObject
& genObj
, JSScript
* script
,
1518 MutableHandleValue res
);
1520 [[nodiscard
]] bool CheckCanDeclareGlobalBinding(JSContext
* cx
,
1521 Handle
<GlobalObject
*> global
,
1522 Handle
<PropertyName
*> name
,
1525 [[nodiscard
]] bool CheckLexicalNameConflict(
1526 JSContext
* cx
, Handle
<ExtensibleLexicalEnvironmentObject
*> lexicalEnv
,
1527 HandleObject varObj
, Handle
<PropertyName
*> name
);
1529 [[nodiscard
]] bool CheckGlobalDeclarationConflicts(
1530 JSContext
* cx
, HandleScript script
,
1531 Handle
<ExtensibleLexicalEnvironmentObject
*> lexicalEnv
,
1532 HandleObject varObj
);
1534 [[nodiscard
]] bool GlobalOrEvalDeclInstantiation(JSContext
* cx
,
1535 HandleObject envChain
,
1536 HandleScript script
,
1537 GCThingIndex lastFun
);
1539 [[nodiscard
]] bool InitFunctionEnvironmentObjects(JSContext
* cx
,
1540 AbstractFramePtr frame
);
1542 [[nodiscard
]] bool PushVarEnvironmentObject(JSContext
* cx
, Handle
<Scope
*> scope
,
1543 AbstractFramePtr frame
);
1545 [[nodiscard
]] bool GetFrameEnvironmentAndScope(JSContext
* cx
,
1546 AbstractFramePtr frame
,
1547 const jsbytecode
* pc
,
1548 MutableHandleObject env
,
1549 MutableHandle
<Scope
*> scope
);
1551 void GetSuspendedGeneratorEnvironmentAndScope(AbstractGeneratorObject
& genObj
,
1553 MutableHandleObject env
,
1554 MutableHandle
<Scope
*> scope
);
1557 bool AnalyzeEntrainedVariables(JSContext
* cx
, HandleScript script
);
1560 extern JSObject
* MaybeOptimizeBindGlobalName(JSContext
* cx
,
1561 Handle
<GlobalObject
*> global
,
1562 Handle
<PropertyName
*> name
);
1565 #endif /* vm_EnvironmentObject_h */