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.
210 * A. Component loading
212 * Components may be loaded in a shared global mode where most JSMs share a
213 * single global in order to save on memory and avoid CCWs. To support this, a
214 * NonSyntacticVariablesObject is used for each JSM to provide a basic form of
215 * isolation. 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.
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
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 (Shared-global JSM)
249 * The target object of a subscript load may be in a JSM with a shared global,
250 * in which case we will also have the NonSyntacticVariablesObject on the
252 * NonSyntacticLexicalEnvironmentObject for target object holds lexical
253 * variables and WithEnvironmentObject holds qualified variables.
254 * Unqualified names goes to NonSyntacticVariablesObject.
256 * Target object's global
258 * GlobalLexicalEnvironmentObject[this=global]
260 * NonSyntacticVariablesObject (unqualified names)
262 * NonSyntacticLexicalEnvironmentObject[this=nsvo]
264 * WithEnvironmentObject wrapping target (qualified 'var's)
266 * NonSyntacticLexicalEnvironmentObject[this=target] (lexical vars)
268 * C.1. Frame scripts with unique scope
270 * XUL frame scripts with unique scope are loaded in the same global as
271 * components, with a NonSyntacticVariablesObject as a "polluting global" for
272 * both qualified 'var' variables and unqualified names, and a with
273 * environment wrapping a message manager object, and
274 * NonSyntacticLexicalEnvironmentObject holding the message manager as `this`,
275 * that holds lexical variables.
276 * These environment objects except for globals are created for each run and
277 * not shared across multiple runs. This is done exclusively in
278 * js::ExecuteInScopeChainAndReturnNewScope.
280 * BackstagePass global
282 * GlobalLexicalEnvironmentObject[this=global]
284 * NonSyntacticVariablesObject (qualified 'var's and unqualified names)
286 * WithEnvironmentObject wrapping messageManager
288 * NonSyntacticLexicalEnvironmentObject[this=messageManager] (lexical vars)
290 * C.2. Frame scripts without unique scope
292 * XUL frame scripts without unique scope are loaded in the same global as
293 * components, with a with environment wrapping a message manager object for
294 * qualified 'var' variables, and NonSyntacticLexicalEnvironmentObject holding
295 * the message manager as `this`, that holds lexical variables.
296 * The environment chain is associated with the message manager object
297 * and cached for subsequent runs.
299 * BackstagePass global (unqualified names)
301 * GlobalLexicalEnvironmentObject[this=global]
303 * WithEnvironmentObject wrapping messageManager (qualified names)
305 * NonSyntacticLexicalEnvironmentObject[this=messageManager] (lexical vars)
307 * D.1. DOM event handlers without direct eval
309 * DOM event handlers are compiled as functions with HTML elements on the
310 * environment chain. For a chain of elements e0, e1, ..., eN, where innerrmost
311 * element is the target element, enclosing elements are such as forms, and the
312 * outermost one is the document.
313 * If the DOM event handlers don't have direct eval, the function's scopes are
314 * optimized and frame slots are used for qualified 'var's and lexical vars.
315 * NonSyntacticLexicalEnvironmentObject's `this` value is not used, given
316 * the function's `this` value is used instead:
318 * global (unqualified names)
320 * GlobalLexicalEnvironmentObject[this=global]
322 * WithEnvironmentObject wrapping eN
326 * WithEnvironmentObject wrapping e1
328 * WithEnvironmentObject wrapping e0
330 * NonSyntacticLexicalEnvironmentObject [this=*unused*]
332 * D.2. DOM event handlers with direct eval
334 * If DOM event handlers have direct eval, the function's scopes are allocated
335 * as environment object:
337 * global (unqualified names)
339 * GlobalLexicalEnvironmentObject[this=global]
343 * WithEnvironmentObject wrapping e1
345 * WithEnvironmentObject wrapping e0
347 * NonSyntacticLexicalEnvironmentObject [this=*unused*]
349 * CallObject (qualified 'var's)
351 * BlockLexicalEnvironmentObject (lexical vars)
353 * E.1. Debugger.Frame.prototype.evalWithBindings
355 * Debugger.Frame.prototype.evalWithBindings uses WithEnvironmentObject for
356 * given bindings, and the frame's enclosing scope
358 * If the frame is function, it has the following env chain.
359 * lexical variables are optimized and uses frame slots:
361 * global (unqualified names)
363 * [DebugProxy] GlobalLexicalEnvironmentObject[this=global]
365 * [DebugProxy] CallObject (qualified 'var's)
367 * WithEnvironmentObject wrapping bindings
369 * If the script has direct eval, BlockLexicalEnvironmentObject is created for
372 * global (unqualified names)
374 * [DebugProxy] GlobalLexicalEnvironmentObject[this=global]
376 * [DebugProxy] CallObject (qualified 'var's)
378 * BlockLexicalEnvironmentObject (lexical)
380 * WithEnvironmentObject wrapping bindings
382 * NOTE: Debugger.Frame.prototype.eval uses the frame's enclosing scope only,
383 * and it doesn't use any dynamic environment, but still uses
384 * non-syntactic scope to perform `eval` operation.
386 * E.2. Debugger.Object.prototype.executeInGlobalWithBindings
388 * Debugger.Object.prototype.executeInGlobalWithBindings uses
389 * WithEnvironmentObject for given bindings, and the object's global scope:
391 * global (qualified 'var's and unqualified names)
393 * GlobalLexicalEnvironmentObject[this=global] (lexical)
395 * WithEnvironmentObject wrapping bindings
397 * NOTE: Debugger.Object.prototype.executeInGlobal uses the object's global
398 * scope only, and it doesn't use any dynamic environment or
399 * non-syntactic scope.
404 class EnvironmentObject
: public NativeObject
{
406 // The enclosing environment. Either another EnvironmentObject, a
407 // GlobalObject, or a non-syntactic environment object.
408 static const uint32_t ENCLOSING_ENV_SLOT
= 0;
410 inline void setAliasedBinding(uint32_t slot
, const Value
& v
);
413 // Since every env chain terminates with a global object, whether
414 // GlobalObject or a non-syntactic one, and since those objects do not
415 // derive EnvironmentObject (they have completely different layouts), the
416 // enclosing environment of an EnvironmentObject is necessarily non-null.
417 JSObject
& enclosingEnvironment() const {
418 return getReservedSlot(ENCLOSING_ENV_SLOT
).toObject();
421 void initEnclosingEnvironment(JSObject
* enclosing
) {
422 initReservedSlot(ENCLOSING_ENV_SLOT
, ObjectOrNullValue(enclosing
));
425 static bool nonExtensibleIsFixedSlot(EnvironmentCoordinate ec
) {
426 // For non-extensible environment objects isFixedSlot(slot) is equivalent to
427 // slot < MAX_FIXED_SLOTS.
428 return ec
.slot() < MAX_FIXED_SLOTS
;
430 static size_t nonExtensibleDynamicSlotIndex(EnvironmentCoordinate ec
) {
431 MOZ_ASSERT(!nonExtensibleIsFixedSlot(ec
));
432 return ec
.slot() - MAX_FIXED_SLOTS
;
435 // Get or set a name contained in this environment.
436 inline const Value
& aliasedBinding(EnvironmentCoordinate ec
);
438 const Value
& aliasedBinding(const BindingIter
& bi
) {
439 MOZ_ASSERT(bi
.location().kind() == BindingLocation::Kind::Environment
);
440 return getSlot(bi
.location().slot());
443 inline void setAliasedBinding(EnvironmentCoordinate ec
, const Value
& v
);
445 inline void setAliasedBinding(const BindingIter
& bi
, const Value
& v
);
448 static size_t offsetOfEnclosingEnvironment() {
449 return getFixedSlotOffset(ENCLOSING_ENV_SLOT
);
452 static uint32_t enclosingEnvironmentSlot() { return ENCLOSING_ENV_SLOT
; }
454 const char* typeString() const;
456 #if defined(DEBUG) || defined(JS_JITSPEW)
458 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
461 class CallObject
: public EnvironmentObject
{
463 static constexpr uint32_t CALLEE_SLOT
= 1;
465 static CallObject
* create(JSContext
* cx
, HandleScript script
,
466 HandleObject enclosing
, gc::InitialHeap heap
);
469 static const JSClass class_
;
471 static constexpr uint32_t RESERVED_SLOTS
= 2;
472 static constexpr ObjectFlags OBJECT_FLAGS
= {ObjectFlag::QualifiedVarObj
};
474 /* These functions are internal and are exposed only for JITs. */
477 * Construct a bare-bones call object given a shape.
478 * The call object must be further initialized to be usable.
480 static CallObject
* createWithShape(JSContext
* cx
, Handle
<SharedShape
*> shape
);
482 static CallObject
* createTemplateObject(JSContext
* cx
, HandleScript script
,
483 HandleObject enclosing
);
485 static CallObject
* create(JSContext
* cx
, AbstractFramePtr frame
);
487 static CallObject
* createHollowForDebug(JSContext
* cx
, HandleFunction callee
);
489 // If `env` or any enclosing environment is a CallObject, return that
490 // CallObject; else null.
492 // `env` may be a DebugEnvironmentProxy, but not a hollow environment.
493 static CallObject
* find(JSObject
* env
);
496 * When an aliased formal (var accessed by nested closures) is also
497 * aliased by the arguments object, it must of course exist in one
498 * canonical location and that location is always the CallObject. For this
499 * to work, the ArgumentsObject stores special MagicValue in its array for
500 * forwarded-to-CallObject variables. This MagicValue's payload is the
501 * slot of the CallObject to access.
503 const Value
& aliasedFormalFromArguments(const Value
& argsValue
) {
504 return getSlot(ArgumentsObject::SlotFromMagicScopeSlotValue(argsValue
));
506 inline void setAliasedFormalFromArguments(const Value
& argsValue
,
509 JSFunction
& callee() const {
510 return getReservedSlot(CALLEE_SLOT
).toObject().as
<JSFunction
>();
513 /* For jit access. */
514 static size_t offsetOfCallee() { return getFixedSlotOffset(CALLEE_SLOT
); }
516 static size_t calleeSlot() { return CALLEE_SLOT
; }
519 class VarEnvironmentObject
: public EnvironmentObject
{
520 static constexpr uint32_t SCOPE_SLOT
= 1;
522 static VarEnvironmentObject
* createInternal(JSContext
* cx
,
523 Handle
<SharedShape
*> shape
,
524 HandleObject enclosing
,
525 gc::InitialHeap heap
);
527 static VarEnvironmentObject
* create(JSContext
* cx
, Handle
<Scope
*> scope
,
528 HandleObject enclosing
,
529 gc::InitialHeap heap
);
531 void initScope(Scope
* scope
) {
532 initReservedSlot(SCOPE_SLOT
, PrivateGCThingValue(scope
));
536 static const JSClass class_
;
538 static constexpr uint32_t RESERVED_SLOTS
= 2;
539 static constexpr ObjectFlags OBJECT_FLAGS
= {ObjectFlag::QualifiedVarObj
};
541 static VarEnvironmentObject
* createForFrame(JSContext
* cx
,
542 Handle
<Scope
*> scope
,
543 AbstractFramePtr frame
);
544 static VarEnvironmentObject
* createHollowForDebug(JSContext
* cx
,
545 Handle
<Scope
*> scope
);
546 static VarEnvironmentObject
* createTemplateObject(JSContext
* cx
,
547 Handle
<VarScope
*> scope
);
548 static VarEnvironmentObject
* createWithoutEnclosing(JSContext
* cx
,
549 Handle
<VarScope
*> scope
);
551 Scope
& scope() const {
552 Value v
= getReservedSlot(SCOPE_SLOT
);
553 MOZ_ASSERT(v
.isPrivateGCThing());
554 Scope
& s
= *static_cast<Scope
*>(v
.toGCThing());
555 MOZ_ASSERT(s
.is
<VarScope
>() || s
.is
<EvalScope
>());
559 bool isForEval() const { return scope().is
<EvalScope
>(); }
560 bool isForNonStrictEval() const { return scope().kind() == ScopeKind::Eval
; }
563 class ModuleEnvironmentObject
: public EnvironmentObject
{
564 static constexpr uint32_t MODULE_SLOT
= 1;
566 static const ObjectOps objectOps_
;
567 static const JSClassOps classOps_
;
570 static const JSClass class_
;
572 static constexpr uint32_t RESERVED_SLOTS
= 2;
573 static constexpr ObjectFlags OBJECT_FLAGS
= {ObjectFlag::NotExtensible
,
574 ObjectFlag::QualifiedVarObj
};
576 static ModuleEnvironmentObject
* create(JSContext
* cx
,
577 Handle
<ModuleObject
*> module
);
578 ModuleObject
& module() const;
579 IndirectBindingMap
& importBindings() const;
581 bool createImportBinding(JSContext
* cx
, Handle
<JSAtom
*> importName
,
582 Handle
<ModuleObject
*> module
,
583 Handle
<JSAtom
*> exportName
);
585 bool hasImportBinding(Handle
<PropertyName
*> name
);
587 bool lookupImport(jsid name
, ModuleEnvironmentObject
** envOut
,
588 mozilla::Maybe
<PropertyInfo
>* propOut
);
590 // If `env` or any enclosing environment is a ModuleEnvironmentObject,
591 // return that ModuleEnvironmentObject; else null.
593 // `env` may be a DebugEnvironmentProxy, but not a hollow environment.
594 static ModuleEnvironmentObject
* find(JSObject
* env
);
597 static bool lookupProperty(JSContext
* cx
, HandleObject obj
, HandleId id
,
598 MutableHandleObject objp
, PropertyResult
* propp
);
599 static bool hasProperty(JSContext
* cx
, HandleObject obj
, HandleId id
,
601 static bool getProperty(JSContext
* cx
, HandleObject obj
, HandleValue receiver
,
602 HandleId id
, MutableHandleValue vp
);
603 static bool setProperty(JSContext
* cx
, HandleObject obj
, HandleId id
,
604 HandleValue v
, HandleValue receiver
,
605 JS::ObjectOpResult
& result
);
606 static bool getOwnPropertyDescriptor(
607 JSContext
* cx
, HandleObject obj
, HandleId id
,
608 MutableHandle
<mozilla::Maybe
<PropertyDescriptor
>> desc
);
609 static bool deleteProperty(JSContext
* cx
, HandleObject obj
, HandleId id
,
610 ObjectOpResult
& result
);
611 static bool newEnumerate(JSContext
* cx
, HandleObject obj
,
612 MutableHandleIdVector properties
,
613 bool enumerableOnly
);
616 class WasmInstanceEnvironmentObject
: public EnvironmentObject
{
617 // Currently WasmInstanceScopes do not use their scopes in a
618 // meaningful way. However, it is an invariant of DebugEnvironments that
619 // environments kept in those maps have live scopes, thus this strong
621 static constexpr uint32_t SCOPE_SLOT
= 1;
624 static const JSClass class_
;
626 static constexpr uint32_t RESERVED_SLOTS
= 2;
627 static constexpr ObjectFlags OBJECT_FLAGS
= {ObjectFlag::NotExtensible
};
629 static WasmInstanceEnvironmentObject
* createHollowForDebug(
630 JSContext
* cx
, Handle
<WasmInstanceScope
*> scope
);
631 WasmInstanceScope
& scope() const {
632 Value v
= getReservedSlot(SCOPE_SLOT
);
633 MOZ_ASSERT(v
.isPrivateGCThing());
634 return *static_cast<WasmInstanceScope
*>(v
.toGCThing());
638 class WasmFunctionCallObject
: public EnvironmentObject
{
639 // Currently WasmFunctionCallObjects do not use their scopes in a
640 // meaningful way. However, it is an invariant of DebugEnvironments that
641 // environments kept in those maps have live scopes, thus this strong
643 static constexpr uint32_t SCOPE_SLOT
= 1;
646 static const JSClass class_
;
648 // TODO Check what Debugger behavior should be when it evaluates a
650 static constexpr uint32_t RESERVED_SLOTS
= 2;
651 static constexpr ObjectFlags OBJECT_FLAGS
= {ObjectFlag::NotExtensible
};
653 static WasmFunctionCallObject
* createHollowForDebug(
654 JSContext
* cx
, HandleObject enclosing
, Handle
<WasmFunctionScope
*> scope
);
655 WasmFunctionScope
& scope() const {
656 Value v
= getReservedSlot(SCOPE_SLOT
);
657 MOZ_ASSERT(v
.isPrivateGCThing());
658 return *static_cast<WasmFunctionScope
*>(v
.toGCThing());
662 // Abstract base class for environments that can contain let/const bindings,
663 // plus a few other kinds of environments, such as `catch` blocks, that have
665 class LexicalEnvironmentObject
: public EnvironmentObject
{
667 // Global and non-syntactic lexical environments need to store a 'this'
668 // object and all other lexical environments have a fixed shape and store a
669 // backpointer to the LexicalScope.
671 // Since the two sets are disjoint, we only use one slot to save space.
672 static constexpr uint32_t THIS_VALUE_OR_SCOPE_SLOT
= 1;
675 static const JSClass class_
;
677 static constexpr uint32_t RESERVED_SLOTS
= 2;
680 static LexicalEnvironmentObject
* create(JSContext
* cx
,
681 Handle
<SharedShape
*> shape
,
682 HandleObject enclosing
,
683 gc::InitialHeap heap
);
686 // Is this the global lexical scope?
687 bool isGlobal() const { return enclosingEnvironment().is
<GlobalObject
>(); }
689 // Global and non-syntactic lexical scopes are extensible. All other
690 // lexical scopes are not.
691 bool isExtensible() const;
693 // Is this a syntactic (i.e. corresponds to a source text) lexical
695 bool isSyntactic() const { return !isExtensible() || isGlobal(); }
698 // A non-extensible lexical environment.
700 // Used for blocks (ScopeKind::Lexical) and several other scope kinds,
701 // including Catch, NamedLambda, FunctionLexical, and ClassBody.
702 class ScopedLexicalEnvironmentObject
: public LexicalEnvironmentObject
{
704 static constexpr ObjectFlags OBJECT_FLAGS
= {ObjectFlag::NotExtensible
};
706 Scope
& scope() const {
707 Value v
= getReservedSlot(THIS_VALUE_OR_SCOPE_SLOT
);
708 MOZ_ASSERT(!isExtensible() && v
.isPrivateGCThing());
709 return *static_cast<Scope
*>(v
.toGCThing());
712 bool isClassBody() const { return scope().kind() == ScopeKind::ClassBody
; }
714 void initScope(Scope
* scope
) {
715 initReservedSlot(THIS_VALUE_OR_SCOPE_SLOT
, PrivateGCThingValue(scope
));
719 class BlockLexicalEnvironmentObject
: public ScopedLexicalEnvironmentObject
{
721 static BlockLexicalEnvironmentObject
* create(JSContext
* cx
,
722 Handle
<LexicalScope
*> scope
,
723 HandleObject enclosing
,
724 gc::InitialHeap heap
);
727 static constexpr ObjectFlags OBJECT_FLAGS
= {ObjectFlag::NotExtensible
};
729 static BlockLexicalEnvironmentObject
* createForFrame(
730 JSContext
* cx
, Handle
<LexicalScope
*> scope
, AbstractFramePtr frame
);
732 static BlockLexicalEnvironmentObject
* createHollowForDebug(
733 JSContext
* cx
, Handle
<LexicalScope
*> scope
);
735 static BlockLexicalEnvironmentObject
* createTemplateObject(
736 JSContext
* cx
, Handle
<LexicalScope
*> scope
);
738 static BlockLexicalEnvironmentObject
* createWithoutEnclosing(
739 JSContext
* cx
, Handle
<LexicalScope
*> scope
);
741 // Create a new BlockLexicalEnvironmentObject with the same enclosing env and
742 // variable values as this.
743 static BlockLexicalEnvironmentObject
* clone(
744 JSContext
* cx
, Handle
<BlockLexicalEnvironmentObject
*> env
);
746 // Create a new BlockLexicalEnvironmentObject with the same enclosing env as
747 // this, with all variables uninitialized.
748 static BlockLexicalEnvironmentObject
* recreate(
749 JSContext
* cx
, Handle
<BlockLexicalEnvironmentObject
*> env
);
751 // The LexicalScope that created this environment.
752 LexicalScope
& scope() const {
753 return ScopedLexicalEnvironmentObject::scope().as
<LexicalScope
>();
757 class NamedLambdaObject
: public BlockLexicalEnvironmentObject
{
758 static NamedLambdaObject
* create(JSContext
* cx
, HandleFunction callee
,
759 HandleObject enclosing
,
760 gc::InitialHeap heap
);
763 static NamedLambdaObject
* createTemplateObject(JSContext
* cx
,
764 HandleFunction callee
);
766 static NamedLambdaObject
* createWithoutEnclosing(JSContext
* cx
,
767 HandleFunction callee
);
769 static NamedLambdaObject
* create(JSContext
* cx
, AbstractFramePtr frame
);
772 static size_t lambdaSlot();
774 static size_t offsetOfLambdaSlot() {
775 return getFixedSlotOffset(lambdaSlot());
779 class ClassBodyLexicalEnvironmentObject
780 : public ScopedLexicalEnvironmentObject
{
781 static ClassBodyLexicalEnvironmentObject
* create(
782 JSContext
* cx
, Handle
<ClassBodyScope
*> scope
, HandleObject enclosing
,
783 gc::InitialHeap heap
);
786 static ClassBodyLexicalEnvironmentObject
* createForFrame(
787 JSContext
* cx
, Handle
<ClassBodyScope
*> scope
, AbstractFramePtr frame
);
789 static ClassBodyLexicalEnvironmentObject
* createTemplateObject(
790 JSContext
* cx
, Handle
<ClassBodyScope
*> scope
);
792 static ClassBodyLexicalEnvironmentObject
* createWithoutEnclosing(
793 JSContext
* cx
, Handle
<ClassBodyScope
*> scope
);
795 // The ClassBodyScope that created this environment.
796 ClassBodyScope
& scope() const {
797 return ScopedLexicalEnvironmentObject::scope().as
<ClassBodyScope
>();
800 static uint32_t privateBrandSlot() { return JSSLOT_FREE(&class_
); }
803 // Global and non-syntactic lexical environments are extensible.
804 class ExtensibleLexicalEnvironmentObject
: public LexicalEnvironmentObject
{
806 JSObject
* thisObject() const;
808 // For a given global object or JSMEnvironment `obj`, return the associated
809 // global lexical or non-syntactic lexical environment, where top-level `let`
810 // bindings are added.
811 static ExtensibleLexicalEnvironmentObject
* forVarEnvironment(JSObject
* obj
);
814 void initThisObject(JSObject
* obj
) {
815 MOZ_ASSERT(isGlobal() || !isSyntactic());
816 JSObject
* thisObj
= GetThisObject(obj
);
817 initReservedSlot(THIS_VALUE_OR_SCOPE_SLOT
, ObjectValue(*thisObj
));
821 // The global lexical environment, where global let/const/class bindings are
823 class GlobalLexicalEnvironmentObject
824 : public ExtensibleLexicalEnvironmentObject
{
826 static GlobalLexicalEnvironmentObject
* create(JSContext
* cx
,
827 Handle
<GlobalObject
*> global
);
829 GlobalObject
& global() const {
830 return enclosingEnvironment().as
<GlobalObject
>();
833 void setWindowProxyThisObject(JSObject
* obj
);
835 static constexpr size_t offsetOfThisValueSlot() {
836 return getFixedSlotOffset(THIS_VALUE_OR_SCOPE_SLOT
);
840 // Non-standard. See "Non-syntactic Environments" above.
841 class NonSyntacticLexicalEnvironmentObject
842 : public ExtensibleLexicalEnvironmentObject
{
844 static NonSyntacticLexicalEnvironmentObject
* create(JSContext
* cx
,
845 HandleObject enclosing
,
849 // A non-syntactic dynamic scope object that captures non-lexical
850 // bindings. That is, a scope object that captures both qualified var
851 // assignments and unqualified bareword assignments. Its parent is always the
852 // global lexical environment.
854 // This is used in ExecuteInGlobalAndReturnScope and sits in front of the
855 // global scope to store 'var' bindings, and to store fresh properties created
856 // by assignments to undeclared variables that otherwise would have gone on
857 // the global object.
858 class NonSyntacticVariablesObject
: public EnvironmentObject
{
860 static const JSClass class_
;
862 static constexpr uint32_t RESERVED_SLOTS
= 1;
863 static constexpr ObjectFlags OBJECT_FLAGS
= {};
865 static NonSyntacticVariablesObject
* create(JSContext
* cx
);
868 extern bool CreateNonSyntacticEnvironmentChain(JSContext
* cx
,
869 JS::HandleObjectVector envChain
,
870 MutableHandleObject env
);
872 // With environment objects on the run-time environment chain.
873 class WithEnvironmentObject
: public EnvironmentObject
{
874 static constexpr uint32_t OBJECT_SLOT
= 1;
875 static constexpr uint32_t THIS_SLOT
= 2;
876 static constexpr uint32_t SCOPE_SLOT
= 3;
879 static const JSClass class_
;
881 static constexpr uint32_t RESERVED_SLOTS
= 4;
882 static constexpr ObjectFlags OBJECT_FLAGS
= {};
884 static WithEnvironmentObject
* create(JSContext
* cx
, HandleObject object
,
885 HandleObject enclosing
,
886 Handle
<WithScope
*> scope
);
887 static WithEnvironmentObject
* createNonSyntactic(JSContext
* cx
,
889 HandleObject enclosing
);
891 /* Return the 'o' in 'with (o)'. */
892 JSObject
& object() const;
894 /* Return object for GetThisValue. */
895 JSObject
* withThis() const;
898 * Return whether this object is a syntactic with object. If not, this is
899 * a With object we inserted between the outermost syntactic scope and the
900 * global object to wrap the environment chain someone explicitly passed
901 * via JSAPI to CompileFunction or script evaluation.
903 bool isSyntactic() const;
905 // For syntactic with environment objects, the with scope.
906 WithScope
& scope() const;
908 static inline size_t objectSlot() { return OBJECT_SLOT
; }
910 static inline size_t thisSlot() { return THIS_SLOT
; }
913 // Internal scope object used by JSOp::BindName upon encountering an
914 // uninitialized lexical slot or an assignment to a 'const' binding.
916 // ES6 lexical bindings cannot be accessed in any way (throwing
917 // ReferenceErrors) until initialized. Normally, NAME operations
918 // unconditionally check for uninitialized lexical slots. When getting or
919 // looking up names, this can be done without slowing down normal operations
920 // on the return value. When setting names, however, we do not want to pollute
921 // all set-property paths with uninitialized lexical checks. For setting names
922 // (i.e. JSOp::SetName), we emit an accompanying, preceding JSOp::BindName which
923 // finds the right scope on which to set the name. Moreover, when the name on
924 // the scope is an uninitialized lexical, we cannot throw eagerly, as the spec
925 // demands that the error be thrown after evaluating the RHS of
926 // assignments. Instead, this sentinel scope object is pushed on the stack.
927 // Attempting to access anything on this scope throws the appropriate
930 // ES6 'const' bindings induce a runtime error when assigned to outside
931 // of initialization, regardless of strictness.
932 class RuntimeLexicalErrorObject
: public EnvironmentObject
{
933 static const unsigned ERROR_SLOT
= 1;
936 static const unsigned RESERVED_SLOTS
= 2;
937 static const JSClass class_
;
939 static RuntimeLexicalErrorObject
* create(JSContext
* cx
,
940 HandleObject enclosing
,
941 unsigned errorNumber
);
943 unsigned errorNumber() { return getReservedSlot(ERROR_SLOT
).toInt32(); }
946 /****************************************************************************/
948 // A environment iterator describes the active environments starting from an
949 // environment, scope pair. This pair may be derived from the current point of
950 // execution in a frame. If derived in such a fashion, the EnvironmentIter
951 // tracks whether the current scope is within the extent of this initial
952 // frame. Here, "frame" means a single activation of: a function, eval, or
954 class MOZ_RAII EnvironmentIter
{
955 Rooted
<ScopeIter
> si_
;
957 AbstractFramePtr frame_
;
959 void incrementScopeIter();
962 // No value semantics.
963 EnvironmentIter(const EnvironmentIter
& ei
) = delete;
966 // Constructing from a copy of an existing EnvironmentIter.
967 EnvironmentIter(JSContext
* cx
, const EnvironmentIter
& ei
);
969 // Constructing from an environment, scope pair. All environments
970 // considered not to be withinInitialFrame, since no frame is given.
971 EnvironmentIter(JSContext
* cx
, JSObject
* env
, Scope
* scope
);
973 // Constructing from a frame. Places the EnvironmentIter on the innermost
974 // environment at pc.
975 EnvironmentIter(JSContext
* cx
, AbstractFramePtr frame
, const jsbytecode
* pc
);
977 // Constructing from an environment, scope and frame. The frame is given
978 // to initialize to proper enclosing environment/scope.
979 EnvironmentIter(JSContext
* cx
, JSObject
* env
, Scope
* scope
,
980 AbstractFramePtr frame
);
982 bool done() const { return si_
.done(); }
984 explicit operator bool() const { return !done(); }
986 void operator++(int) {
987 if (hasAnyEnvironmentObject()) {
988 env_
= &env_
->as
<EnvironmentObject
>().enclosingEnvironment();
990 incrementScopeIter();
994 EnvironmentIter
& operator++() {
1000 JSObject
& enclosingEnvironment() const;
1003 bool hasNonSyntacticEnvironmentObject() const;
1005 bool hasSyntacticEnvironment() const { return si_
.hasSyntacticEnvironment(); }
1007 bool hasAnyEnvironmentObject() const {
1008 return hasNonSyntacticEnvironmentObject() || hasSyntacticEnvironment();
1011 EnvironmentObject
& environment() const {
1012 MOZ_ASSERT(hasAnyEnvironmentObject());
1013 return env_
->as
<EnvironmentObject
>();
1016 Scope
& scope() const { return *si_
.scope(); }
1018 Scope
* maybeScope() const {
1025 JSFunction
& callee() const { return env_
->as
<CallObject
>().callee(); }
1027 bool withinInitialFrame() const { return !!frame_
; }
1029 AbstractFramePtr
initialFrame() const {
1030 MOZ_ASSERT(withinInitialFrame());
1034 AbstractFramePtr
maybeInitialFrame() const { return frame_
; }
1037 // The key in MissingEnvironmentMap. For live frames, maps live frames to
1038 // their synthesized environments. For completely optimized-out environments,
1039 // maps the Scope to their synthesized environments. The env we synthesize for
1040 // Scopes are read-only, and we never use their parent links, so they don't
1041 // need to be distinct.
1043 // That is, completely optimized out environments can't be distinguished by
1044 // frame. Note that even if the frame corresponding to the Scope is live on
1045 // the stack, it is unsound to synthesize an environment from that live
1046 // frame. In other words, the provenance of the environment chain is from
1047 // allocated closures (i.e., allocation sites) and is irrecoverable from
1048 // simple stack inspection (i.e., call sites).
1049 class MissingEnvironmentKey
{
1050 friend class LiveEnvironmentVal
;
1052 AbstractFramePtr frame_
;
1056 explicit MissingEnvironmentKey(const EnvironmentIter
& ei
)
1057 : frame_(ei
.maybeInitialFrame()), scope_(ei
.maybeScope()) {}
1059 MissingEnvironmentKey(AbstractFramePtr frame
, Scope
* scope
)
1060 : frame_(frame
), scope_(scope
) {}
1062 AbstractFramePtr
frame() const { return frame_
; }
1063 Scope
* scope() const { return scope_
; }
1065 void updateScope(Scope
* scope
) { scope_
= scope
; }
1066 void updateFrame(AbstractFramePtr frame
) { frame_
= frame
; }
1068 // For use as hash policy.
1069 using Lookup
= MissingEnvironmentKey
;
1070 static HashNumber
hash(MissingEnvironmentKey sk
);
1071 static bool match(MissingEnvironmentKey sk1
, MissingEnvironmentKey sk2
);
1072 bool operator!=(const MissingEnvironmentKey
& other
) const {
1073 return frame_
!= other
.frame_
|| scope_
!= other
.scope_
;
1075 static void rekey(MissingEnvironmentKey
& k
,
1076 const MissingEnvironmentKey
& newKey
) {
1081 // The value in LiveEnvironmentMap, mapped from by live environment objects.
1082 class LiveEnvironmentVal
{
1083 friend class DebugEnvironments
;
1084 friend class MissingEnvironmentKey
;
1086 AbstractFramePtr frame_
;
1087 HeapPtr
<Scope
*> scope_
;
1089 static void staticAsserts();
1092 explicit LiveEnvironmentVal(const EnvironmentIter
& ei
)
1093 : frame_(ei
.initialFrame()), scope_(ei
.maybeScope()) {}
1095 AbstractFramePtr
frame() const { return frame_
; }
1097 void updateFrame(AbstractFramePtr frame
) { frame_
= frame
; }
1099 bool traceWeak(JSTracer
* trc
);
1102 /****************************************************************************/
1105 * [SMDOC] Debug environment objects
1107 * The frontend optimizes unaliased variables into stack slots and can optimize
1108 * away whole EnvironmentObjects. So when the debugger wants to perform an
1109 * unexpected eval-in-frame (or otherwise access the environment),
1110 * `fp->environmentChain` is often incomplete. This is a problem: a major use
1111 * case for eval-in-frame is to access the local variables in debuggee code.
1113 * Even when all EnvironmentObjects exist, giving complete information for all
1114 * bindings, stack and heap, there's another issue: eval-in-frame code can
1115 * create closures that capture stack locals. The variable slots go away when
1116 * the frame is popped, but the closure, which uses them, may survive.
1118 * To solve both problems, eval-in-frame code is compiled and run against a
1119 * "debug environment chain" of DebugEnvironmentProxy objects rather than real
1120 * EnvironmentObjects. The `GetDebugEnvironmentFor` functions below create
1121 * these proxies, one to sit in front of each existing EnvironmentObject. They
1122 * also create bogus "hollow" EnvironmentObjects to stand in for environments
1123 * that were optimized away; and proxies for those. The frontend sees these
1124 * environments as something like `with` scopes, and emits deoptimized bytecode
1125 * instructions for all variable accesses.
1127 * When eval-in-frame code runs, `fp->environmentChain` points to this chain of
1128 * proxies. On each variable access, the proxy laboriously figures out what to
1129 * do. See e.g. `DebuggerEnvironmentProxyHandler::handleUnaliasedAccess`.
1131 * There's a limit to what the proxies can manage, since they're proxying
1132 * environments that are already optimized. Some debugger operations, like
1133 * redefining a lexical binding, can fail when a true direct eval would
1134 * succeed. Even plain variable accesses can throw, if the variable has been
1137 * To support accessing stack variables after they've gone out of scope, we
1138 * copy the variables to the heap as they leave scope. See
1139 * `DebugEnvironments::onPopCall` and `onPopLexical`.
1141 * `GetDebugEnvironmentFor*` guarantees that the same DebugEnvironmentProxy is
1142 * always produced for the same underlying environment (optimized or not!).
1143 * This is maintained by some bookkeeping information stored in
1144 * `DebugEnvironments`.
1147 extern JSObject
* GetDebugEnvironmentForFunction(JSContext
* cx
,
1148 HandleFunction fun
);
1150 extern JSObject
* GetDebugEnvironmentForSuspendedGenerator(
1151 JSContext
* cx
, JSScript
* script
, AbstractGeneratorObject
& genObj
);
1153 extern JSObject
* GetDebugEnvironmentForFrame(JSContext
* cx
,
1154 AbstractFramePtr frame
,
1157 extern JSObject
* GetDebugEnvironmentForGlobalLexicalEnvironment(JSContext
* cx
);
1158 extern Scope
* GetEnvironmentScope(const JSObject
& env
);
1160 /* Provides debugger access to a environment. */
1161 class DebugEnvironmentProxy
: public ProxyObject
{
1163 * The enclosing environment on the dynamic environment chain. This slot is
1164 * analogous to the ENCLOSING_ENV_SLOT of a EnvironmentObject.
1166 static const unsigned ENCLOSING_SLOT
= 0;
1169 * NullValue or a dense array holding the unaliased variables of a function
1170 * frame that has been popped.
1172 static const unsigned SNAPSHOT_SLOT
= 1;
1175 static DebugEnvironmentProxy
* create(JSContext
* cx
, EnvironmentObject
& env
,
1176 HandleObject enclosing
);
1178 // NOTE: The environment may be a debug hollow with invalid
1179 // enclosingEnvironment. Always use the enclosingEnvironment accessor on
1180 // the DebugEnvironmentProxy in order to walk the environment chain.
1181 EnvironmentObject
& environment() const;
1182 JSObject
& enclosingEnvironment() const;
1184 // May only be called for proxies to function call objects or modules
1185 // with top-level-await.
1186 ArrayObject
* maybeSnapshot() const;
1187 void initSnapshot(ArrayObject
& snapshot
);
1189 // Currently, the 'declarative' environments are function, module, and
1190 // lexical environments.
1191 bool isForDeclarative() const;
1193 // Get a property by 'id', but returns sentinel values instead of throwing
1194 // on exceptional cases.
1195 static bool getMaybeSentinelValue(JSContext
* cx
,
1196 Handle
<DebugEnvironmentProxy
*> env
,
1197 HandleId id
, MutableHandleValue vp
);
1199 // Returns true iff this is a function environment with its own this-binding
1200 // (all functions except arrow functions).
1201 bool isFunctionEnvironmentWithThis();
1203 // Does this debug environment not have a real counterpart or was never
1204 // live (and thus does not have a synthesized EnvironmentObject or a
1206 bool isOptimizedOut() const;
1208 #if defined(DEBUG) || defined(JS_JITSPEW)
1210 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
1213 /* Maintains per-realm debug environment bookkeeping information. */
1214 class DebugEnvironments
{
1217 /* The map from (non-debug) environments to debug environments. */
1218 ObjectWeakMap proxiedEnvs
;
1221 * The map from live frames which have optimized-away environments to the
1222 * corresponding debug environments.
1224 typedef HashMap
<MissingEnvironmentKey
, WeakHeapPtr
<DebugEnvironmentProxy
*>,
1225 MissingEnvironmentKey
, ZoneAllocPolicy
>
1226 MissingEnvironmentMap
;
1227 MissingEnvironmentMap missingEnvs
;
1230 * The map from environment objects of live frames to the live frame. This
1231 * map updated lazily whenever the debugger needs the information. In
1232 * between two lazy updates, liveEnvs becomes incomplete (but not invalid,
1233 * onPop* removes environments as they are popped). Thus, two consecutive
1234 * debugger lazy updates of liveEnvs need only fill in the new
1237 typedef GCHashMap
<WeakHeapPtr
<JSObject
*>, LiveEnvironmentVal
,
1238 StableCellHasher
<WeakHeapPtr
<JSObject
*>>, ZoneAllocPolicy
>
1240 LiveEnvironmentMap liveEnvs
;
1243 DebugEnvironments(JSContext
* cx
, Zone
* zone
);
1244 ~DebugEnvironments();
1246 Zone
* zone() const { return zone_
; }
1249 static DebugEnvironments
* ensureRealmData(JSContext
* cx
);
1251 template <typename Environment
, typename Scope
>
1252 static void onPopGeneric(JSContext
* cx
, const EnvironmentIter
& ei
);
1255 void trace(JSTracer
* trc
);
1256 void traceWeak(JSTracer
* trc
);
1259 void checkHashTablesAfterMovingGC();
1262 // If a live frame has a synthesized entry in missingEnvs, make sure it's not
1264 void traceLiveFrame(JSTracer
* trc
, AbstractFramePtr frame
);
1266 static DebugEnvironmentProxy
* hasDebugEnvironment(JSContext
* cx
,
1267 EnvironmentObject
& env
);
1268 static bool addDebugEnvironment(JSContext
* cx
, Handle
<EnvironmentObject
*> env
,
1269 Handle
<DebugEnvironmentProxy
*> debugEnv
);
1271 static DebugEnvironmentProxy
* hasDebugEnvironment(JSContext
* cx
,
1272 const EnvironmentIter
& ei
);
1273 static bool addDebugEnvironment(JSContext
* cx
, const EnvironmentIter
& ei
,
1274 Handle
<DebugEnvironmentProxy
*> debugEnv
);
1276 static bool updateLiveEnvironments(JSContext
* cx
);
1277 static LiveEnvironmentVal
* hasLiveEnvironment(EnvironmentObject
& env
);
1278 static void unsetPrevUpToDateUntil(JSContext
* cx
, AbstractFramePtr frame
);
1280 // When a frame bails out from Ion to Baseline, there might be missing
1281 // envs keyed on, and live envs containing, the old
1282 // RematerializedFrame. Forward those values to the new BaselineFrame.
1283 static void forwardLiveFrame(JSContext
* cx
, AbstractFramePtr from
,
1284 AbstractFramePtr to
);
1286 // When an environment is popped, we store a snapshot of its bindings that
1287 // live on the frame.
1289 // This is done during frame unwinding, which cannot handle errors
1290 // gracefully. Errors result in no snapshot being set on the
1291 // DebugEnvironmentProxy.
1292 static void takeFrameSnapshot(JSContext
* cx
,
1293 Handle
<DebugEnvironmentProxy
*> debugEnv
,
1294 AbstractFramePtr frame
);
1296 // In debug-mode, these must be called whenever exiting a scope that might
1297 // have stack-allocated locals.
1298 static void onPopCall(JSContext
* cx
, AbstractFramePtr frame
);
1299 static void onPopVar(JSContext
* cx
, const EnvironmentIter
& ei
);
1300 static void onPopLexical(JSContext
* cx
, const EnvironmentIter
& ei
);
1301 static void onPopLexical(JSContext
* cx
, AbstractFramePtr frame
,
1302 const jsbytecode
* pc
);
1303 static void onPopWith(AbstractFramePtr frame
);
1304 static void onPopModule(JSContext
* cx
, const EnvironmentIter
& ei
);
1305 static void onRealmUnsetIsDebuggee(Realm
* realm
);
1308 } /* namespace js */
1311 inline bool JSObject::is
<js::EnvironmentObject
>() const {
1312 return is
<js::CallObject
>() || is
<js::VarEnvironmentObject
>() ||
1313 is
<js::ModuleEnvironmentObject
>() ||
1314 is
<js::WasmInstanceEnvironmentObject
>() ||
1315 is
<js::WasmFunctionCallObject
>() ||
1316 is
<js::LexicalEnvironmentObject
>() ||
1317 is
<js::WithEnvironmentObject
>() ||
1318 is
<js::NonSyntacticVariablesObject
>() ||
1319 is
<js::RuntimeLexicalErrorObject
>();
1323 inline bool JSObject::is
<js::ScopedLexicalEnvironmentObject
>() const {
1324 return is
<js::LexicalEnvironmentObject
>() &&
1325 !as
<js::LexicalEnvironmentObject
>().isExtensible();
1329 inline bool JSObject::is
<js::BlockLexicalEnvironmentObject
>() const {
1330 return is
<js::ScopedLexicalEnvironmentObject
>() &&
1331 !as
<js::ScopedLexicalEnvironmentObject
>().isClassBody();
1335 inline bool JSObject::is
<js::ClassBodyLexicalEnvironmentObject
>() const {
1336 return is
<js::ScopedLexicalEnvironmentObject
>() &&
1337 as
<js::ScopedLexicalEnvironmentObject
>().isClassBody();
1341 inline bool JSObject::is
<js::ExtensibleLexicalEnvironmentObject
>() const {
1342 return is
<js::LexicalEnvironmentObject
>() &&
1343 as
<js::LexicalEnvironmentObject
>().isExtensible();
1347 inline bool JSObject::is
<js::GlobalLexicalEnvironmentObject
>() const {
1348 return is
<js::LexicalEnvironmentObject
>() &&
1349 as
<js::LexicalEnvironmentObject
>().isGlobal();
1353 inline bool JSObject::is
<js::NonSyntacticLexicalEnvironmentObject
>() const {
1354 return is
<js::LexicalEnvironmentObject
>() &&
1355 !as
<js::LexicalEnvironmentObject
>().isSyntactic();
1359 inline bool JSObject::is
<js::NamedLambdaObject
>() const {
1360 return is
<js::BlockLexicalEnvironmentObject
>() &&
1361 as
<js::BlockLexicalEnvironmentObject
>().scope().isNamedLambda();
1365 bool JSObject::is
<js::DebugEnvironmentProxy
>() const;
1369 inline bool IsSyntacticEnvironment(JSObject
* env
) {
1370 if (!env
->is
<EnvironmentObject
>()) {
1374 if (env
->is
<WithEnvironmentObject
>()) {
1375 return env
->as
<WithEnvironmentObject
>().isSyntactic();
1378 if (env
->is
<LexicalEnvironmentObject
>()) {
1379 return env
->as
<LexicalEnvironmentObject
>().isSyntactic();
1382 if (env
->is
<NonSyntacticVariablesObject
>()) {
1389 inline bool IsExtensibleLexicalEnvironment(JSObject
* env
) {
1390 return env
->is
<ExtensibleLexicalEnvironmentObject
>();
1393 inline bool IsGlobalLexicalEnvironment(JSObject
* env
) {
1394 return env
->is
<GlobalLexicalEnvironmentObject
>();
1397 inline bool IsNSVOLexicalEnvironment(JSObject
* env
) {
1398 return env
->is
<LexicalEnvironmentObject
>() &&
1399 env
->as
<LexicalEnvironmentObject
>()
1400 .enclosingEnvironment()
1401 .is
<NonSyntacticVariablesObject
>();
1404 inline JSObject
* MaybeUnwrapWithEnvironment(JSObject
* env
) {
1405 if (env
->is
<WithEnvironmentObject
>()) {
1406 return &env
->as
<WithEnvironmentObject
>().object();
1411 template <typename SpecificEnvironment
>
1412 inline bool IsFrameInitialEnvironment(AbstractFramePtr frame
,
1413 SpecificEnvironment
& env
) {
1414 // A frame's initial environment is the innermost environment
1415 // corresponding to the scope chain from frame.script()->bodyScope() to
1416 // frame.script()->outermostScope(). This environment must be on the chain
1417 // for the frame to be considered initialized. That is, it must be on the
1418 // chain for the environment chain to fully match the scope chain at the
1419 // start of execution in the frame.
1421 // This logic must be in sync with the HAS_INITIAL_ENV logic in
1422 // BaselineStackBuilder::buildBaselineFrame.
1424 // A function frame's CallObject, if present, is always the initial
1426 if constexpr (std::is_same_v
<SpecificEnvironment
, CallObject
>) {
1430 // For an eval frame, the VarEnvironmentObject, if present, is always the
1431 // initial environment.
1432 if constexpr (std::is_same_v
<SpecificEnvironment
, VarEnvironmentObject
>) {
1433 if (frame
.isEvalFrame()) {
1438 // For named lambda frames without CallObjects (i.e., no binding in the
1439 // body of the function was closed over), the NamedLambdaObject
1440 // corresponding to the named lambda scope is the initial environment.
1441 if constexpr (std::is_same_v
<SpecificEnvironment
, NamedLambdaObject
>) {
1442 if (frame
.isFunctionFrame() &&
1443 frame
.callee()->needsNamedLambdaEnvironment() &&
1444 !frame
.callee()->needsCallObject()) {
1445 LexicalScope
* namedLambdaScope
= frame
.script()->maybeNamedLambdaScope();
1446 return &env
.scope() == namedLambdaScope
;
1453 extern bool CreateObjectsForEnvironmentChain(JSContext
* cx
,
1454 HandleObjectVector chain
,
1455 HandleObject terminatingEnv
,
1456 MutableHandleObject envObj
);
1458 ModuleObject
* GetModuleObjectForScript(JSScript
* script
);
1460 ModuleEnvironmentObject
* GetModuleEnvironmentForScript(JSScript
* script
);
1462 [[nodiscard
]] bool GetThisValueForDebuggerFrameMaybeOptimizedOut(
1463 JSContext
* cx
, AbstractFramePtr frame
, const jsbytecode
* pc
,
1464 MutableHandleValue res
);
1465 [[nodiscard
]] bool GetThisValueForDebuggerSuspendedGeneratorMaybeOptimizedOut(
1466 JSContext
* cx
, AbstractGeneratorObject
& genObj
, JSScript
* script
,
1467 MutableHandleValue res
);
1469 [[nodiscard
]] bool CheckCanDeclareGlobalBinding(JSContext
* cx
,
1470 Handle
<GlobalObject
*> global
,
1471 Handle
<PropertyName
*> name
,
1474 [[nodiscard
]] bool CheckLexicalNameConflict(
1475 JSContext
* cx
, Handle
<ExtensibleLexicalEnvironmentObject
*> lexicalEnv
,
1476 HandleObject varObj
, Handle
<PropertyName
*> name
);
1478 [[nodiscard
]] bool CheckGlobalDeclarationConflicts(
1479 JSContext
* cx
, HandleScript script
,
1480 Handle
<ExtensibleLexicalEnvironmentObject
*> lexicalEnv
,
1481 HandleObject varObj
);
1483 [[nodiscard
]] bool GlobalOrEvalDeclInstantiation(JSContext
* cx
,
1484 HandleObject envChain
,
1485 HandleScript script
,
1486 GCThingIndex lastFun
);
1488 [[nodiscard
]] bool InitFunctionEnvironmentObjects(JSContext
* cx
,
1489 AbstractFramePtr frame
);
1491 [[nodiscard
]] bool PushVarEnvironmentObject(JSContext
* cx
, Handle
<Scope
*> scope
,
1492 AbstractFramePtr frame
);
1494 [[nodiscard
]] bool GetFrameEnvironmentAndScope(JSContext
* cx
,
1495 AbstractFramePtr frame
,
1496 const jsbytecode
* pc
,
1497 MutableHandleObject env
,
1498 MutableHandle
<Scope
*> scope
);
1500 void GetSuspendedGeneratorEnvironmentAndScope(AbstractGeneratorObject
& genObj
,
1502 MutableHandleObject env
,
1503 MutableHandle
<Scope
*> scope
);
1506 bool AnalyzeEntrainedVariables(JSContext
* cx
, HandleScript script
);
1509 extern JSObject
* MaybeOptimizeBindGlobalName(JSContext
* cx
,
1510 Handle
<GlobalObject
*> global
,
1511 Handle
<PropertyName
*> name
);
1514 #endif /* vm_EnvironmentObject_h */