Bug 1832044 - Part 1: Rename MovableCellHasher to StableCellHasher r=sfink
[gecko.git] / js / src / vm / EnvironmentObject.h
blob86ffe5bf733b9374e5033c794214eab269beba0c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef vm_EnvironmentObject_h
8 #define vm_EnvironmentObject_h
10 #include <type_traits>
12 #include "frontend/NameAnalysisTypes.h"
13 #include "gc/Barrier.h"
14 #include "gc/WeakMap.h"
15 #include "js/GCHashTable.h"
16 #include "vm/ArgumentsObject.h"
17 #include "vm/GlobalObject.h"
18 #include "vm/JSObject.h"
19 #include "vm/ProxyObject.h"
20 #include "vm/Scope.h"
21 #include "vm/ScopeKind.h" // ScopeKind
23 namespace js {
25 class AbstractGeneratorObject;
26 class IndirectBindingMap;
27 class ModuleObject;
30 * Return a shape representing the static scope containing the variable
31 * accessed by the ALIASEDVAR op at 'pc'.
33 extern SharedShape* EnvironmentCoordinateToEnvironmentShape(JSScript* script,
34 jsbytecode* pc);
36 // Return the name being accessed by the given ALIASEDVAR op. This function is
37 // relatively slow so it should not be used on hot paths.
38 extern PropertyName* EnvironmentCoordinateNameSlow(JSScript* script,
39 jsbytecode* pc);
41 /*** Environment objects ****************************************************/
43 // clang-format off
45 * [SMDOC] Environment Objects
47 * About environments
48 * ------------------
50 * See also: https://tc39.es/ecma262/#sec-environment-records
52 * Scoping in ES is specified in terms of "Environment Records". There's a
53 * global Environment Record per realm, and a new Environment Record is created
54 * whenever control enters a function, block, or other scope.
56 * A "Lexical Environment" is a list of nested Environment Records, innermost
57 * first: everything that's in scope. Throughout SpiderMonkey, "environment"
58 * means a Lexical Environment.
60 * N.B.: "Scope" means something different: a static scope, the compile-time
61 * analogue of an environment. See Scope.h.
63 * How SpiderMonkey represents environments
64 * ----------------------------------------
66 * Some environments are stored as JSObjects. Several kinds of objects
67 * represent environments:
69 * JSObject
70 * |
71 * +--NativeObject
72 * | |
73 * | +--EnvironmentObject Engine-internal environment
74 * | | |
75 * | | +--CallObject Environment of entire function
76 * | | |
77 * | | +--VarEnvironmentObject See VarScope in Scope.h.
78 * | | |
79 * | | +--ModuleEnvironmentObject
80 * | | | Module top-level environment
81 * | | |
82 * | | +--WasmInstanceEnvironmentObject
83 * | | |
84 * | | +--WasmFunctionCallObject
85 * | | |
86 * | | +--LexicalEnvironmentObject
87 * | | | |
88 * | | | +--ScopedLexicalEnvironmentObject
89 * | | | | | Non-extensible lexical environment
90 * | | | | |
91 * | | | | +--BlockLexicalEnvironmentObject
92 * | | | | | | Blocks and such: syntactic,
93 * | | | | | | non-extensible
94 * | | | | | |
95 * | | | | | +--NamedLambdaObject
96 * | | | | | Environment for `(function f(){...})`
97 * | | | | | containing only a binding for `f`
98 * | | | | |
99 * | | | | +--ClassBodyLexicalEnvironmentObject
100 * | | | | Environment for class body, containing
101 * | | | | private names, private brands, and
102 * | | | | static initializers list
103 * | | | |
104 * | | | +--ExtensibleLexicalEnvironmentObject
105 * | | | |
106 * | | | +--GlobalLexicalEnvironmentObject
107 * | | | | Top-level let/const/class in scripts
108 * | | | |
109 * | | | +--NonSyntacticLexicalEnvironmentObject
110 * | | | See "Non-syntactic environments" below
111 * | | |
112 * | | +--NonSyntacticVariablesObject
113 * | | | See "Non-syntactic environments" below
114 * | | |
115 * | | +--WithEnvironmentObject Presents object properties as bindings
116 * | | |
117 * | | +--RuntimeLexicalErrorObject
118 * | | Special value represents uninitialized
119 * | | lexical slots
120 * | |
121 * | +--GlobalObject The global environment (dynamically
122 * | presents its properties as bindings)
123 * +--ProxyObject
125 * +--DebugEnvironmentProxy Environment for debugger eval-in-frame
127 * EnvironmentObjects are technically real JSObjects but only belong on the
128 * environment chain (that is, fp->environmentChain() or fun->environment()).
129 * They are never exposed to scripts.
131 * Note that reserved slots in any base classes shown above are fixed for all
132 * derived classes. So e.g. EnvironmentObject::enclosingEnvironment() can
133 * simply access a fixed slot without further dynamic type information.
135 * When the current environment is represented by an object, the stack frame
136 * has a pointer to that object (see AbstractFramePtr::environmentChain()).
137 * However, that isn't always the case. Where possible, we store binding values
138 * in JS stack slots. For block and function scopes where all bindings can be
139 * stored in stack slots, nothing is allocated in the heap; there is no
140 * environment object.
142 * Full information about the environment chain is always recoverable:
143 * EnvironmentIter can do it, and we construct a fake environment for debugger
144 * eval-in-frame (see "Debug environment objects" below).
146 * Syntactic Environments
147 * ----------------------
149 * Environments may be syntactic, i.e., corresponding to source text, or
150 * non-syntactic, i.e., specially created by embedding. The distinction is
151 * necessary to maintain invariants about the environment chain: non-syntactic
152 * environments may not occur in arbitrary positions in the chain.
154 * CallObject, ModuleEnvironmentObject, BlockLexicalEnvironmentObject, and
155 * GlobalLexicalEnvironmentObject always represent syntactic
156 * environments. (CallObject is considered syntactic even when it's used as the
157 * scope of strict eval code.) WithEnvironmentObject is syntactic when it's
158 * used to represent the scope of a `with` block.
161 * Non-syntactic Environments
162 * --------------------------
164 * A non-syntactic environment is one that was not created due to JS source
165 * code. On the scope chain, a single NonSyntactic GlobalScope maps to 0+
166 * non-syntactic environment objects. This is contrasted with syntactic
167 * environments, where each scope corresponds to 0 or 1 environment object.
169 * There are 3 kinds of dynamic environment objects:
171 * 1. WithEnvironmentObject
173 * When the embedding compiles or executes a script, it has the option to
174 * pass in a vector of objects to be used as the initial env chain, ordered
175 * from outermost env to innermost env. Each of those objects is wrapped by
176 * a WithEnvironmentObject.
178 * The innermost object passed in by the embedding becomes a qualified
179 * variables object that captures 'var' bindings. That is, it wraps the
180 * holder object of 'var' bindings.
182 * Does not hold 'let' or 'const' bindings.
184 * 2. NonSyntacticVariablesObject
186 * When the embedding wants qualified 'var' bindings and unqualified
187 * bareword assignments to go on a different object than the global
188 * object. While any object can be made into a qualified variables object,
189 * only the GlobalObject and NonSyntacticVariablesObject are considered
190 * unqualified variables objects.
192 * Unlike WithEnvironmentObjects that delegate to the object they wrap,
193 * this object is itself the holder of 'var' bindings.
195 * Does not hold 'let' or 'const' bindings.
197 * 3. NonSyntacticLexicalEnvironmentObject
199 * Each non-syntactic object used as a qualified variables object needs to
200 * enclose a non-syntactic lexical environment to hold 'let' and 'const'
201 * bindings. There is a bijection per realm between the non-syntactic
202 * variables objects and their non-syntactic LexicalEnvironmentObjects.
204 * Does not hold 'var' bindings.
206 * The embedding (Gecko) and debugger uses non-syntactic envs for various
207 * things, all of which are detailed below. All env chain listings below are,
208 * from top to bottom, outermost to innermost.
210 * A. 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
251 * chain.
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
324 * ...
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]
341 * ...
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
370 * it:
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.
402 // clang-format on
404 class EnvironmentObject : public NativeObject {
405 protected:
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);
412 public:
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);
447 // For JITs.
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)
457 void dump();
458 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
461 class CallObject : public EnvironmentObject {
462 protected:
463 static constexpr uint32_t CALLEE_SLOT = 1;
465 static CallObject* create(JSContext* cx, HandleScript script,
466 HandleObject enclosing, gc::InitialHeap heap);
468 public:
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,
507 const Value& v);
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));
535 public:
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>());
556 return s;
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_;
569 public:
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);
596 private:
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,
600 bool* foundp);
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
620 // reference.
621 static constexpr uint32_t SCOPE_SLOT = 1;
623 public:
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
642 // reference.
643 static constexpr uint32_t SCOPE_SLOT = 1;
645 public:
646 static const JSClass class_;
648 // TODO Check what Debugger behavior should be when it evaluates a
649 // var declaration.
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
664 // similar behavior.
665 class LexicalEnvironmentObject : public EnvironmentObject {
666 protected:
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;
674 public:
675 static const JSClass class_;
677 static constexpr uint32_t RESERVED_SLOTS = 2;
679 protected:
680 static LexicalEnvironmentObject* create(JSContext* cx,
681 Handle<SharedShape*> shape,
682 HandleObject enclosing,
683 gc::InitialHeap heap);
685 public:
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
694 // environment?
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 {
703 public:
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 {
720 protected:
721 static BlockLexicalEnvironmentObject* create(JSContext* cx,
722 Handle<LexicalScope*> scope,
723 HandleObject enclosing,
724 gc::InitialHeap heap);
726 public:
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);
762 public:
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);
771 // For JITs.
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);
785 public:
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 {
805 public:
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);
813 protected:
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
822 // added.
823 class GlobalLexicalEnvironmentObject
824 : public ExtensibleLexicalEnvironmentObject {
825 public:
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 {
843 public:
844 static NonSyntacticLexicalEnvironmentObject* create(JSContext* cx,
845 HandleObject enclosing,
846 HandleObject thisv);
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 {
859 public:
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;
878 public:
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,
888 HandleObject object,
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
928 // ReferenceError.
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;
935 public:
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
953 // global code.
954 class MOZ_RAII EnvironmentIter {
955 Rooted<ScopeIter> si_;
956 RootedObject env_;
957 AbstractFramePtr frame_;
959 void incrementScopeIter();
960 void settle();
962 // No value semantics.
963 EnvironmentIter(const EnvironmentIter& ei) = delete;
965 public:
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();
991 settle();
994 EnvironmentIter& operator++() {
995 operator++(1);
996 return *this;
999 // If done():
1000 JSObject& enclosingEnvironment() const;
1002 // If !done():
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 {
1019 if (si_) {
1020 return si_.scope();
1022 return nullptr;
1025 JSFunction& callee() const { return env_->as<CallObject>().callee(); }
1027 bool withinInitialFrame() const { return !!frame_; }
1029 AbstractFramePtr initialFrame() const {
1030 MOZ_ASSERT(withinInitialFrame());
1031 return frame_;
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_;
1053 Scope* scope_;
1055 public:
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) {
1077 k = 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();
1091 public:
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
1135 * optimized away.
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,
1155 jsbytecode* pc);
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;
1174 public:
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
1205 // snapshot)?
1206 bool isOptimizedOut() const;
1208 #if defined(DEBUG) || defined(JS_JITSPEW)
1209 void dump();
1210 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
1213 /* Maintains per-realm debug environment bookkeeping information. */
1214 class DebugEnvironments {
1215 Zone* zone_;
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
1235 * environments.
1237 typedef GCHashMap<WeakHeapPtr<JSObject*>, LiveEnvironmentVal,
1238 StableCellHasher<WeakHeapPtr<JSObject*>>, ZoneAllocPolicy>
1239 LiveEnvironmentMap;
1240 LiveEnvironmentMap liveEnvs;
1242 public:
1243 DebugEnvironments(JSContext* cx, Zone* zone);
1244 ~DebugEnvironments();
1246 Zone* zone() const { return zone_; }
1248 private:
1249 static DebugEnvironments* ensureRealmData(JSContext* cx);
1251 template <typename Environment, typename Scope>
1252 static void onPopGeneric(JSContext* cx, const EnvironmentIter& ei);
1254 public:
1255 void trace(JSTracer* trc);
1256 void traceWeak(JSTracer* trc);
1257 void finish();
1258 #ifdef JS_GC_ZEAL
1259 void checkHashTablesAfterMovingGC();
1260 #endif
1262 // If a live frame has a synthesized entry in missingEnvs, make sure it's not
1263 // collected.
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 */
1310 template <>
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>();
1322 template <>
1323 inline bool JSObject::is<js::ScopedLexicalEnvironmentObject>() const {
1324 return is<js::LexicalEnvironmentObject>() &&
1325 !as<js::LexicalEnvironmentObject>().isExtensible();
1328 template <>
1329 inline bool JSObject::is<js::BlockLexicalEnvironmentObject>() const {
1330 return is<js::ScopedLexicalEnvironmentObject>() &&
1331 !as<js::ScopedLexicalEnvironmentObject>().isClassBody();
1334 template <>
1335 inline bool JSObject::is<js::ClassBodyLexicalEnvironmentObject>() const {
1336 return is<js::ScopedLexicalEnvironmentObject>() &&
1337 as<js::ScopedLexicalEnvironmentObject>().isClassBody();
1340 template <>
1341 inline bool JSObject::is<js::ExtensibleLexicalEnvironmentObject>() const {
1342 return is<js::LexicalEnvironmentObject>() &&
1343 as<js::LexicalEnvironmentObject>().isExtensible();
1346 template <>
1347 inline bool JSObject::is<js::GlobalLexicalEnvironmentObject>() const {
1348 return is<js::LexicalEnvironmentObject>() &&
1349 as<js::LexicalEnvironmentObject>().isGlobal();
1352 template <>
1353 inline bool JSObject::is<js::NonSyntacticLexicalEnvironmentObject>() const {
1354 return is<js::LexicalEnvironmentObject>() &&
1355 !as<js::LexicalEnvironmentObject>().isSyntactic();
1358 template <>
1359 inline bool JSObject::is<js::NamedLambdaObject>() const {
1360 return is<js::BlockLexicalEnvironmentObject>() &&
1361 as<js::BlockLexicalEnvironmentObject>().scope().isNamedLambda();
1364 template <>
1365 bool JSObject::is<js::DebugEnvironmentProxy>() const;
1367 namespace js {
1369 inline bool IsSyntacticEnvironment(JSObject* env) {
1370 if (!env->is<EnvironmentObject>()) {
1371 return false;
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>()) {
1383 return false;
1386 return true;
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();
1408 return env;
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
1425 // environment.
1426 if constexpr (std::is_same_v<SpecificEnvironment, CallObject>) {
1427 return true;
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()) {
1434 return true;
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;
1450 return false;
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,
1472 bool isFunction);
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,
1501 JSScript* script,
1502 MutableHandleObject env,
1503 MutableHandle<Scope*> scope);
1505 #ifdef DEBUG
1506 bool AnalyzeEntrainedVariables(JSContext* cx, HandleScript script);
1507 #endif
1509 extern JSObject* MaybeOptimizeBindGlobalName(JSContext* cx,
1510 Handle<GlobalObject*> global,
1511 Handle<PropertyName*> name);
1512 } // namespace js
1514 #endif /* vm_EnvironmentObject_h */