Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef vm_EnvironmentObject_h
8 : #define vm_EnvironmentObject_h
9 :
10 : #include "jscntxt.h"
11 : #include "jsobj.h"
12 : #include "jsweakmap.h"
13 :
14 : #include "builtin/ModuleObject.h"
15 : #include "frontend/NameAnalysisTypes.h"
16 : #include "gc/Barrier.h"
17 : #include "js/GCHashTable.h"
18 : #include "vm/ArgumentsObject.h"
19 : #include "vm/ProxyObject.h"
20 : #include "vm/Scope.h"
21 :
22 : namespace js {
23 :
24 : class ModuleObject;
25 : typedef Handle<ModuleObject*> HandleModuleObject;
26 :
27 : /*
28 : * Return a shape representing the static scope containing the variable
29 : * accessed by the ALIASEDVAR op at 'pc'.
30 : */
31 : extern Shape*
32 : EnvironmentCoordinateToEnvironmentShape(JSScript* script, jsbytecode* pc);
33 :
34 : /* Return the name being accessed by the given ALIASEDVAR op. */
35 : extern PropertyName*
36 : EnvironmentCoordinateName(EnvironmentCoordinateNameCache& cache, JSScript* script, jsbytecode* pc);
37 :
38 : /* Return the function script accessed by the given ALIASEDVAR op, or nullptr. */
39 : extern JSScript*
40 : EnvironmentCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
41 :
42 :
43 : /*** Environment objects *****************************************************/
44 :
45 :
46 : /*** Environment objects *****************************************************/
47 :
48 : /*
49 : * About environments
50 : * ------------------
51 : *
52 : * (See also: ecma262 rev c7952de (19 Aug 2016) 8.1 "Lexical Environments".)
53 : *
54 : * Scoping in ES is specified in terms of "Environment Records". There's a
55 : * global Environment Record per realm, and a new Environment Record is created
56 : * whenever control enters a function, block, or other scope.
57 : *
58 : * A "Lexical Environment" is a list of nested Environment Records, innermost
59 : * first: everything that's in scope. Throughout SpiderMonkey, "environment"
60 : * means a Lexical Environment.
61 : *
62 : * N.B.: "Scope" means something different: a static scope, the compile-time
63 : * analogue of an environment. See Scope.h.
64 : *
65 : * How SpiderMonkey represents environments
66 : * ----------------------------------------
67 : *
68 : * Some environments are stored as JSObjects. Several kinds of objects
69 : * represent environments:
70 : *
71 : * JSObject
72 : * |
73 : * +--NativeObject
74 : * | |
75 : * | +--EnvironmentObject Engine-internal environment
76 : * | | |
77 : * | | +--CallObject Environment of entire function
78 : * | | |
79 : * | | +--ModuleEnvironmentObject Module top-level environment
80 : * | | |
81 : * | | +--LexicalEnvironmentObject Lexical (block) environment
82 : * | | | |
83 : * | | | +--NamedLambdaObject Environment for `(function f(){...})`
84 : * | | | containing only a binding for `f`
85 : * | | +--VarEnvironmentObject See VarScope in Scope.h.
86 : * | | |
87 : * | | +--WithEnvironmentObject Presents object properties as bindings
88 : * | | |
89 : * | | +--NonSyntacticVariablesObject See "Non-syntactic environments" below
90 : * | |
91 : * | +--GlobalObject The global environment
92 : * |
93 : * +--ProxyObject
94 : * |
95 : * +--DebugEnvironmentProxy Environment for debugger eval-in-frame
96 : *
97 : * EnvironmentObjects are technically real JSObjects but only belong on the
98 : * environment chain (that is, fp->environmentChain() or fun->environment()).
99 : * They are never exposed to scripts.
100 : *
101 : * Note that reserved slots in any base classes shown above are fixed for all
102 : * derived classes. So e.g. EnvironmentObject::enclosingEnvironment() can
103 : * simply access a fixed slot without further dynamic type information.
104 : *
105 : * When the current environment is represented by an object, the stack frame
106 : * has a pointer to that object (see AbstractFramePtr::environmentChain()).
107 : * However, that isn't always the case. Where possible, we store binding values
108 : * in JS stack slots. For block and function scopes where all bindings can be
109 : * stored in stack slots, nothing is allocated in the heap; there is no
110 : * environment object.
111 : *
112 : * Full information about the environment chain is always recoverable:
113 : * EnvironmentIter can do it, and we construct a fake environment for debugger
114 : * eval-in-frame (see "Debug environment objects" below).
115 : *
116 : * Syntactic Environments
117 : * ----------------------
118 : *
119 : * Environments may be syntactic, i.e., corresponding to source text, or
120 : * non-syntactic, i.e., specially created by embedding. The distinction is
121 : * necessary to maintain invariants about the environment chain: non-syntactic
122 : * environments may not occur in arbitrary positions in the chain.
123 : *
124 : * CallObject, ModuleEnvironmentObject, and LexicalEnvironmentObject always
125 : * represent syntactic environments. (CallObject is considered syntactic even
126 : * when it's used as the scope of strict eval code.) WithEnvironmentObject is
127 : * syntactic when it's used to represent the scope of a `with` block.
128 : *
129 : *
130 : * Non-syntactic Environments
131 : * --------------------------
132 : *
133 : * A non-syntactic environment is one that was not created due to JS source
134 : * code. On the scope chain, a single NonSyntactic GlobalScope maps to 0+
135 : * non-syntactic environment objects. This is contrasted with syntactic
136 : * environments, where each scope corresponds to 0 or 1 environment object.
137 : *
138 : * There are 3 kinds of dynamic environment objects:
139 : *
140 : * 1. WithEnvironmentObject
141 : *
142 : * When the embedding compiles or executes a script, it has the option to
143 : * pass in a vector of objects to be used as the initial env chain, ordered
144 : * from outermost env to innermost env. Each of those objects is wrapped by
145 : * a WithEnvironmentObject.
146 : *
147 : * The innermost object passed in by the embedding becomes a qualified
148 : * variables object that captures 'var' bindings. That is, it wraps the
149 : * holder object of 'var' bindings.
150 : *
151 : * Does not hold 'let' or 'const' bindings.
152 : *
153 : * 2. NonSyntacticVariablesObject
154 : *
155 : * When the embedding wants qualified 'var' bindings and unqualified
156 : * bareword assignments to go on a different object than the global
157 : * object. While any object can be made into a qualified variables object,
158 : * only the GlobalObject and NonSyntacticVariablesObject are considered
159 : * unqualified variables objects.
160 : *
161 : * Unlike WithEnvironmentObjects that delegate to the object they wrap,
162 : * this object is itself the holder of 'var' bindings.
163 : *
164 : * Does not hold 'let' or 'const' bindings.
165 : *
166 : * 3. LexicalEnvironmentObject
167 : *
168 : * Each non-syntactic object used as a qualified variables object needs to
169 : * enclose a non-syntactic LexicalEnvironmentObject to hold 'let' and
170 : * 'const' bindings. There is a bijection per compartment between the
171 : * non-syntactic variables objects and their non-syntactic
172 : * LexicalEnvironmentObjects.
173 : *
174 : * Does not hold 'var' bindings.
175 : *
176 : * The embedding (Gecko) uses non-syntactic envs for various things, some of
177 : * which are detailed below. All env chain listings below are, from top to
178 : * bottom, outermost to innermost.
179 : *
180 : * A. Component loading
181 : *
182 : * Components may be loaded in "reuse loader global" mode, where to save on
183 : * memory, all JSMs and JS-implemented XPCOM modules are loaded into a single
184 : * global. Each individual JSMs are compiled as functions with their own
185 : * FakeBackstagePass. They have the following env chain:
186 : *
187 : * BackstagePass global
188 : * |
189 : * Global lexical scope
190 : * |
191 : * WithEnvironmentObject wrapping FakeBackstagePass
192 : * |
193 : * LexicalEnvironmentObject
194 : *
195 : * B. Subscript loading
196 : *
197 : * Subscripts may be loaded into a target object. They have the following
198 : * env chain:
199 : *
200 : * Loader global
201 : * |
202 : * Global lexical scope
203 : * |
204 : * WithEnvironmentObject wrapping target
205 : * |
206 : * LexicalEnvironmentObject
207 : *
208 : * C. Frame scripts
209 : *
210 : * XUL frame scripts are always loaded with a NonSyntacticVariablesObject as a
211 : * "polluting global". This is done exclusively in
212 : * js::ExecuteInGlobalAndReturnScope.
213 : *
214 : * Loader global
215 : * |
216 : * Global lexical scope
217 : * |
218 : * NonSyntacticVariablesObject
219 : * |
220 : * LexicalEnvironmentObject
221 : *
222 : * D. XBL and DOM event handlers
223 : *
224 : * XBL methods are compiled as functions with XUL elements on the env chain,
225 : * and DOM event handlers are compiled as functions with HTML elements on the
226 : * env chain. For a chain of elements e0,...,eN:
227 : *
228 : * ...
229 : * |
230 : * WithEnvironmentObject wrapping eN
231 : * |
232 : * ...
233 : * |
234 : * WithEnvironmentObject wrapping e0
235 : * |
236 : * LexicalEnvironmentObject
237 : *
238 : */
239 :
240 : class EnvironmentObject : public NativeObject
241 : {
242 : protected:
243 : // The enclosing environment. Either another EnvironmentObject, a
244 : // GlobalObject, or a non-syntactic environment object.
245 : static const uint32_t ENCLOSING_ENV_SLOT = 0;
246 :
247 : inline void setAliasedBinding(JSContext* cx, uint32_t slot, PropertyName* name,
248 : const Value& v);
249 :
250 0 : void setEnclosingEnvironment(JSObject* enclosing) {
251 0 : setReservedSlot(ENCLOSING_ENV_SLOT, ObjectOrNullValue(enclosing));
252 0 : }
253 :
254 : public:
255 : // Since every env chain terminates with a global object, whether
256 : // GlobalObject or a non-syntactic one, and since those objects do not
257 : // derive EnvironmentObject (they have completely different layouts), the
258 : // enclosing environment of an EnvironmentObject is necessarily non-null.
259 170237 : JSObject& enclosingEnvironment() const {
260 170237 : return getReservedSlot(ENCLOSING_ENV_SLOT).toObject();
261 : }
262 :
263 8501 : void initEnclosingEnvironment(JSObject* enclosing) {
264 8501 : initReservedSlot(ENCLOSING_ENV_SLOT, ObjectOrNullValue(enclosing));
265 8501 : }
266 :
267 : // Get or set a name contained in this environment.
268 7223 : const Value& aliasedBinding(EnvironmentCoordinate ec) {
269 7223 : return getSlot(ec.slot());
270 : }
271 :
272 0 : const Value& aliasedBinding(const BindingIter& bi) {
273 0 : MOZ_ASSERT(bi.location().kind() == BindingLocation::Kind::Environment);
274 0 : return getSlot(bi.location().slot());
275 : }
276 :
277 : inline void setAliasedBinding(JSContext* cx, EnvironmentCoordinate ec, PropertyName* name,
278 : const Value& v);
279 :
280 : inline void setAliasedBinding(JSContext* cx, const BindingIter& bi, const Value& v);
281 :
282 : // For JITs.
283 303 : static size_t offsetOfEnclosingEnvironment() {
284 303 : return getFixedSlotOffset(ENCLOSING_ENV_SLOT);
285 : }
286 :
287 7 : static uint32_t enclosingEnvironmentSlot() {
288 7 : return ENCLOSING_ENV_SLOT;
289 : }
290 : };
291 :
292 : class CallObject : public EnvironmentObject
293 : {
294 : protected:
295 : static const uint32_t CALLEE_SLOT = 1;
296 :
297 : static CallObject* create(JSContext* cx, HandleScript script, HandleFunction callee,
298 : HandleObject enclosing);
299 :
300 : public:
301 : static const uint32_t RESERVED_SLOTS = 2;
302 : static const Class class_;
303 :
304 : /* These functions are internal and are exposed only for JITs. */
305 :
306 : /*
307 : * Construct a bare-bones call object given a shape and a non-singleton
308 : * group. The call object must be further initialized to be usable.
309 : */
310 : static CallObject* create(JSContext* cx, HandleShape shape, HandleObjectGroup group);
311 :
312 : /*
313 : * Construct a bare-bones call object given a shape and make it into
314 : * a singleton. The call object must be initialized to be usable.
315 : */
316 : static CallObject* createSingleton(JSContext* cx, HandleShape shape);
317 :
318 : static CallObject* createTemplateObject(JSContext* cx, HandleScript script,
319 : HandleObject enclosing, gc::InitialHeap heap);
320 :
321 : static CallObject* create(JSContext* cx, HandleFunction callee, HandleObject enclosing);
322 : static CallObject* create(JSContext* cx, AbstractFramePtr frame);
323 :
324 : static CallObject* createHollowForDebug(JSContext* cx, HandleFunction callee);
325 :
326 : /*
327 : * When an aliased formal (var accessed by nested closures) is also
328 : * aliased by the arguments object, it must of course exist in one
329 : * canonical location and that location is always the CallObject. For this
330 : * to work, the ArgumentsObject stores special MagicValue in its array for
331 : * forwarded-to-CallObject variables. This MagicValue's payload is the
332 : * slot of the CallObject to access.
333 : */
334 0 : const Value& aliasedFormalFromArguments(const Value& argsValue) {
335 0 : return getSlot(ArgumentsObject::SlotFromMagicScopeSlotValue(argsValue));
336 : }
337 : inline void setAliasedFormalFromArguments(JSContext* cx, const Value& argsValue, jsid id,
338 : const Value& v);
339 :
340 4773 : JSFunction& callee() const {
341 4773 : return getReservedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
342 : }
343 :
344 : /* For jit access. */
345 0 : static size_t offsetOfCallee() {
346 0 : return getFixedSlotOffset(CALLEE_SLOT);
347 : }
348 :
349 4 : static size_t calleeSlot() {
350 4 : return CALLEE_SLOT;
351 : }
352 : };
353 :
354 : class VarEnvironmentObject : public EnvironmentObject
355 : {
356 : static const uint32_t SCOPE_SLOT = 1;
357 :
358 : static VarEnvironmentObject* create(JSContext* cx, HandleShape shape, HandleObject enclosing,
359 : gc::InitialHeap heap);
360 :
361 41 : void initScope(Scope* scope) {
362 41 : initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope));
363 41 : }
364 :
365 : public:
366 : static const uint32_t RESERVED_SLOTS = 2;
367 : static const Class class_;
368 :
369 : static VarEnvironmentObject* create(JSContext* cx, HandleScope scope, AbstractFramePtr frame);
370 : static VarEnvironmentObject* createHollowForDebug(JSContext* cx, Handle<VarScope*> scope);
371 :
372 126 : Scope& scope() const {
373 126 : Value v = getReservedSlot(SCOPE_SLOT);
374 126 : MOZ_ASSERT(v.isPrivateGCThing());
375 126 : Scope& s = *static_cast<Scope*>(v.toGCThing());
376 126 : MOZ_ASSERT(s.is<VarScope>() || s.is<EvalScope>());
377 126 : return s;
378 : }
379 :
380 0 : bool isForEval() const {
381 0 : return scope().is<EvalScope>();
382 : }
383 : };
384 :
385 : class ModuleEnvironmentObject : public EnvironmentObject
386 : {
387 : static const uint32_t MODULE_SLOT = 1;
388 :
389 : static const ObjectOps objectOps_;
390 : static const ClassOps classOps_;
391 :
392 : public:
393 : static const Class class_;
394 :
395 : static const uint32_t RESERVED_SLOTS = 2;
396 :
397 : static ModuleEnvironmentObject* create(JSContext* cx, HandleModuleObject module);
398 : ModuleObject& module();
399 : IndirectBindingMap& importBindings();
400 :
401 : bool createImportBinding(JSContext* cx, HandleAtom importName, HandleModuleObject module,
402 : HandleAtom exportName);
403 :
404 : bool hasImportBinding(HandlePropertyName name);
405 :
406 : bool lookupImport(jsid name, ModuleEnvironmentObject** envOut, Shape** shapeOut);
407 :
408 : void fixEnclosingEnvironmentAfterCompartmentMerge(GlobalObject& global);
409 :
410 : private:
411 : static bool lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
412 : MutableHandleObject objp, MutableHandle<PropertyResult> propp);
413 : static bool hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
414 : static bool getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
415 : MutableHandleValue vp);
416 : static bool setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
417 : HandleValue receiver, JS::ObjectOpResult& result);
418 : static bool getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
419 : MutableHandle<PropertyDescriptor> desc);
420 : static bool deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
421 : ObjectOpResult& result);
422 : static bool newEnumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
423 : bool enumerableOnly);
424 : };
425 :
426 : typedef Rooted<ModuleEnvironmentObject*> RootedModuleEnvironmentObject;
427 : typedef Handle<ModuleEnvironmentObject*> HandleModuleEnvironmentObject;
428 : typedef MutableHandle<ModuleEnvironmentObject*> MutableHandleModuleEnvironmentObject;
429 :
430 : class WasmFunctionCallObject : public EnvironmentObject
431 : {
432 : // Currently WasmFunctionCallObjects do not use their scopes in a
433 : // meaningful way. However, it is an invariant of DebugEnvironments that
434 : // environments kept in those maps have live scopes, thus this strong
435 : // reference.
436 : static const uint32_t SCOPE_SLOT = 1;
437 :
438 : public:
439 : static const Class class_;
440 :
441 : static const uint32_t RESERVED_SLOTS = 2;
442 :
443 : static WasmFunctionCallObject* createHollowForDebug(JSContext* cx,
444 : Handle<WasmFunctionScope*> scope);
445 0 : WasmFunctionScope& scope() const {
446 0 : Value v = getReservedSlot(SCOPE_SLOT);
447 0 : MOZ_ASSERT(v.isPrivateGCThing());
448 0 : return *static_cast<WasmFunctionScope*>(v.toGCThing());
449 : }
450 : };
451 :
452 : class LexicalEnvironmentObject : public EnvironmentObject
453 : {
454 : // Global and non-syntactic lexical environments need to store a 'this'
455 : // value and all other lexical environments have a fixed shape and store a
456 : // backpointer to the LexicalScope.
457 : //
458 : // Since the two sets are disjoint, we only use one slot to save space.
459 : static const unsigned THIS_VALUE_OR_SCOPE_SLOT = 1;
460 :
461 : public:
462 : static const unsigned RESERVED_SLOTS = 2;
463 : static const Class class_;
464 :
465 : private:
466 : static LexicalEnvironmentObject* createTemplateObject(JSContext* cx, HandleShape shape,
467 : HandleObject enclosing,
468 : gc::InitialHeap heap);
469 :
470 419 : void initThisValue(JSObject* obj) {
471 419 : MOZ_ASSERT(isGlobal() || !isSyntactic());
472 419 : initReservedSlot(THIS_VALUE_OR_SCOPE_SLOT, GetThisValue(obj));
473 419 : }
474 :
475 2089 : void initScopeUnchecked(LexicalScope* scope) {
476 2089 : initReservedSlot(THIS_VALUE_OR_SCOPE_SLOT, PrivateGCThingValue(scope));
477 2089 : }
478 :
479 : void initScope(LexicalScope* scope) {
480 : MOZ_ASSERT(!isGlobal());
481 : MOZ_ASSERT(isSyntactic());
482 : initScopeUnchecked(scope);
483 : }
484 :
485 : public:
486 : static LexicalEnvironmentObject* create(JSContext* cx, Handle<LexicalScope*> scope,
487 : HandleObject enclosing, gc::InitialHeap heap);
488 : static LexicalEnvironmentObject* create(JSContext* cx, Handle<LexicalScope*> scope,
489 : AbstractFramePtr frame);
490 : static LexicalEnvironmentObject* createGlobal(JSContext* cx, Handle<GlobalObject*> global);
491 : static LexicalEnvironmentObject* createNonSyntactic(JSContext* cx, HandleObject enclosing);
492 : static LexicalEnvironmentObject* createHollowForDebug(JSContext* cx,
493 : Handle<LexicalScope*> scope);
494 :
495 : // Create a new LexicalEnvironmentObject with the same enclosing env and
496 : // variable values as this.
497 : static LexicalEnvironmentObject* clone(JSContext* cx, Handle<LexicalEnvironmentObject*> env);
498 :
499 : // Create a new LexicalEnvironmentObject with the same enclosing env as
500 : // this, with all variables uninitialized.
501 : static LexicalEnvironmentObject* recreate(JSContext* cx, Handle<LexicalEnvironmentObject*> env);
502 :
503 : // For non-extensible lexical environments, the LexicalScope that created
504 : // this environment. Otherwise asserts.
505 2585 : LexicalScope& scope() const {
506 2585 : Value v = getReservedSlot(THIS_VALUE_OR_SCOPE_SLOT);
507 2585 : MOZ_ASSERT(!isExtensible() && v.isPrivateGCThing());
508 2585 : return *static_cast<LexicalScope*>(v.toGCThing());
509 : }
510 :
511 : // Is this the global lexical scope?
512 50834 : bool isGlobal() const {
513 50834 : return enclosingEnvironment().is<GlobalObject>();
514 : }
515 :
516 2895 : GlobalObject& global() const {
517 2895 : return enclosingEnvironment().as<GlobalObject>();
518 : }
519 :
520 : // Global and non-syntactic lexical scopes are extensible. All other
521 : // lexical scopes are not.
522 : bool isExtensible() const;
523 :
524 : // Is this a syntactic (i.e. corresponds to a source text) lexical
525 : // environment?
526 28857 : bool isSyntactic() const {
527 28857 : return !isExtensible() || isGlobal();
528 : }
529 :
530 : // For extensible lexical environments, the 'this' value for its
531 : // scope. Otherwise asserts.
532 : Value thisValue() const;
533 : };
534 :
535 : class NamedLambdaObject : public LexicalEnvironmentObject
536 : {
537 : static NamedLambdaObject* create(JSContext* cx, HandleFunction callee,
538 : HandleFunction replacement,
539 : HandleObject enclosing, gc::InitialHeap heap);
540 :
541 : public:
542 : static NamedLambdaObject* createTemplateObject(JSContext* cx, HandleFunction callee,
543 : gc::InitialHeap heap);
544 :
545 : static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame);
546 : static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame,
547 : HandleFunction replacement);
548 :
549 : // For JITs.
550 : static size_t lambdaSlot();
551 : };
552 :
553 : // A non-syntactic dynamic scope object that captures non-lexical
554 : // bindings. That is, a scope object that captures both qualified var
555 : // assignments and unqualified bareword assignments. Its parent is always the
556 : // global lexical environment.
557 : //
558 : // This is used in ExecuteInGlobalAndReturnScope and sits in front of the
559 : // global scope to store 'var' bindings, and to store fresh properties created
560 : // by assignments to undeclared variables that otherwise would have gone on
561 : // the global object.
562 : class NonSyntacticVariablesObject : public EnvironmentObject
563 : {
564 : public:
565 : static const unsigned RESERVED_SLOTS = 1;
566 : static const Class class_;
567 :
568 : static NonSyntacticVariablesObject* create(JSContext* cx);
569 : };
570 :
571 : // With environment objects on the run-time environment chain.
572 : class WithEnvironmentObject : public EnvironmentObject
573 : {
574 : static const unsigned OBJECT_SLOT = 1;
575 : static const unsigned THIS_SLOT = 2;
576 : static const unsigned SCOPE_SLOT = 3;
577 :
578 : public:
579 : static const unsigned RESERVED_SLOTS = 4;
580 : static const Class class_;
581 :
582 : static WithEnvironmentObject* create(JSContext* cx, HandleObject object, HandleObject enclosing,
583 : Handle<WithScope*> scope);
584 : static WithEnvironmentObject* createNonSyntactic(JSContext* cx, HandleObject object,
585 : HandleObject enclosing);
586 :
587 : /* Return the 'o' in 'with (o)'. */
588 : JSObject& object() const;
589 :
590 : /* Return object for GetThisValue. */
591 : JSObject* withThis() const;
592 :
593 : /*
594 : * Return whether this object is a syntactic with object. If not, this is
595 : * a With object we inserted between the outermost syntactic scope and the
596 : * global object to wrap the environment chain someone explicitly passed
597 : * via JSAPI to CompileFunction or script evaluation.
598 : */
599 : bool isSyntactic() const;
600 :
601 : // For syntactic with environment objects, the with scope.
602 : WithScope& scope() const;
603 :
604 0 : static inline size_t objectSlot() {
605 0 : return OBJECT_SLOT;
606 : }
607 :
608 0 : static inline size_t thisSlot() {
609 0 : return THIS_SLOT;
610 : }
611 : };
612 :
613 : // Internal scope object used by JSOP_BINDNAME upon encountering an
614 : // uninitialized lexical slot or an assignment to a 'const' binding.
615 : //
616 : // ES6 lexical bindings cannot be accessed in any way (throwing
617 : // ReferenceErrors) until initialized. Normally, NAME operations
618 : // unconditionally check for uninitialized lexical slots. When getting or
619 : // looking up names, this can be done without slowing down normal operations
620 : // on the return value. When setting names, however, we do not want to pollute
621 : // all set-property paths with uninitialized lexical checks. For setting names
622 : // (i.e. JSOP_SETNAME), we emit an accompanying, preceding JSOP_BINDNAME which
623 : // finds the right scope on which to set the name. Moreover, when the name on
624 : // the scope is an uninitialized lexical, we cannot throw eagerly, as the spec
625 : // demands that the error be thrown after evaluating the RHS of
626 : // assignments. Instead, this sentinel scope object is pushed on the stack.
627 : // Attempting to access anything on this scope throws the appropriate
628 : // ReferenceError.
629 : //
630 : // ES6 'const' bindings induce a runtime error when assigned to outside
631 : // of initialization, regardless of strictness.
632 : class RuntimeLexicalErrorObject : public EnvironmentObject
633 : {
634 : static const unsigned ERROR_SLOT = 1;
635 :
636 : public:
637 : static const unsigned RESERVED_SLOTS = 2;
638 : static const Class class_;
639 :
640 : static RuntimeLexicalErrorObject* create(JSContext* cx, HandleObject enclosing,
641 : unsigned errorNumber);
642 :
643 0 : unsigned errorNumber() {
644 0 : return getReservedSlot(ERROR_SLOT).toInt32();
645 : }
646 : };
647 :
648 :
649 : /*****************************************************************************/
650 :
651 : // A environment iterator describes the active environments starting from an
652 : // environment, scope pair. This pair may be derived from the current point of
653 : // execution in a frame. If derived in such a fashion, the EnvironmentIter
654 : // tracks whether the current scope is within the extent of this initial
655 : // frame. Here, "frame" means a single activation of: a function, eval, or
656 : // global code.
657 14330 : class MOZ_RAII EnvironmentIter
658 : {
659 : Rooted<ScopeIter> si_;
660 : RootedObject env_;
661 : AbstractFramePtr frame_;
662 :
663 : void incrementScopeIter();
664 : void settle();
665 :
666 : // No value semantics.
667 : EnvironmentIter(const EnvironmentIter& ei) = delete;
668 :
669 : public:
670 : // Constructing from a copy of an existing EnvironmentIter.
671 : EnvironmentIter(JSContext* cx, const EnvironmentIter& ei
672 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
673 :
674 : // Constructing from an environment, scope pair. All environments
675 : // considered not to be withinInitialFrame, since no frame is given.
676 : EnvironmentIter(JSContext* cx, JSObject* env, Scope* scope
677 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
678 :
679 : // Constructing from a frame. Places the EnvironmentIter on the innermost
680 : // environment at pc.
681 : EnvironmentIter(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc
682 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
683 :
684 : // Constructing from an environment, scope and frame. The frame is given
685 : // to initialize to proper enclosing environment/scope.
686 : EnvironmentIter(JSContext* cx, JSObject* env, Scope* scope, AbstractFramePtr frame
687 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
688 :
689 :
690 40 : bool done() const {
691 40 : return si_.done();
692 : }
693 :
694 40 : explicit operator bool() const {
695 40 : return !done();
696 : }
697 :
698 14899 : void operator++(int) {
699 14899 : if (hasAnyEnvironmentObject())
700 3348 : env_ = &env_->as<EnvironmentObject>().enclosingEnvironment();
701 14899 : incrementScopeIter();
702 14899 : settle();
703 14899 : }
704 :
705 0 : EnvironmentIter& operator++() {
706 0 : operator++(1);
707 0 : return *this;
708 : }
709 :
710 : // If done():
711 : JSObject& enclosingEnvironment() const;
712 :
713 : // If !done():
714 : bool hasNonSyntacticEnvironmentObject() const;
715 :
716 42138 : bool hasSyntacticEnvironment() const {
717 42138 : return si_.hasSyntacticEnvironment();
718 : }
719 :
720 14933 : bool hasAnyEnvironmentObject() const {
721 14933 : return hasNonSyntacticEnvironmentObject() || hasSyntacticEnvironment();
722 : }
723 :
724 34 : EnvironmentObject& environment() const {
725 34 : MOZ_ASSERT(hasAnyEnvironmentObject());
726 34 : return env_->as<EnvironmentObject>();
727 : }
728 :
729 27929 : Scope& scope() const {
730 27929 : return *si_.scope();
731 : }
732 :
733 1995 : Scope* maybeScope() const {
734 1995 : if (si_)
735 1995 : return si_.scope();
736 0 : return nullptr;
737 : }
738 :
739 : JSFunction& callee() const {
740 : return env_->as<CallObject>().callee();
741 : }
742 :
743 34504 : bool withinInitialFrame() const {
744 34504 : return !!frame_;
745 : }
746 :
747 5419 : AbstractFramePtr initialFrame() const {
748 5419 : MOZ_ASSERT(withinInitialFrame());
749 5419 : return frame_;
750 : }
751 :
752 0 : AbstractFramePtr maybeInitialFrame() const {
753 0 : return frame_;
754 : }
755 :
756 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
757 : };
758 :
759 : // The key in MissingEnvironmentMap. For live frames, maps live frames to
760 : // their synthesized environments. For completely optimized-out environments,
761 : // maps the Scope to their synthesized environments. The env we synthesize for
762 : // Scopes are read-only, and we never use their parent links, so they don't
763 : // need to be distinct.
764 : //
765 : // That is, completely optimized out environments can't be distinguished by
766 : // frame. Note that even if the frame corresponding to the Scope is live on
767 : // the stack, it is unsound to synthesize an environment from that live
768 : // frame. In other words, the provenance of the environment chain is from
769 : // allocated closures (i.e., allocation sites) and is irrecoverable from
770 : // simple stack inspection (i.e., call sites).
771 : class MissingEnvironmentKey
772 : {
773 : friend class LiveEnvironmentVal;
774 :
775 : AbstractFramePtr frame_;
776 : Scope* scope_;
777 :
778 : public:
779 0 : explicit MissingEnvironmentKey(const EnvironmentIter& ei)
780 0 : : frame_(ei.maybeInitialFrame()),
781 0 : scope_(ei.maybeScope())
782 0 : { }
783 :
784 0 : MissingEnvironmentKey(AbstractFramePtr frame, Scope* scope)
785 0 : : frame_(frame),
786 0 : scope_(scope)
787 0 : { }
788 :
789 0 : AbstractFramePtr frame() const { return frame_; }
790 0 : Scope* scope() const { return scope_; }
791 :
792 0 : void updateScope(Scope* scope) { scope_ = scope; }
793 0 : void updateFrame(AbstractFramePtr frame) { frame_ = frame; }
794 :
795 : // For use as hash policy.
796 : typedef MissingEnvironmentKey Lookup;
797 : static HashNumber hash(MissingEnvironmentKey sk);
798 : static bool match(MissingEnvironmentKey sk1, MissingEnvironmentKey sk2);
799 : bool operator!=(const MissingEnvironmentKey& other) const {
800 : return frame_ != other.frame_ || scope_ != other.scope_;
801 : }
802 0 : static void rekey(MissingEnvironmentKey& k, const MissingEnvironmentKey& newKey) {
803 0 : k = newKey;
804 0 : }
805 : };
806 :
807 : // The value in LiveEnvironmentMap, mapped from by live environment objects.
808 0 : class LiveEnvironmentVal
809 : {
810 : friend class DebugEnvironments;
811 : friend class MissingEnvironmentKey;
812 :
813 : AbstractFramePtr frame_;
814 : HeapPtr<Scope*> scope_;
815 :
816 : static void staticAsserts();
817 :
818 : public:
819 0 : explicit LiveEnvironmentVal(const EnvironmentIter& ei)
820 0 : : frame_(ei.initialFrame()),
821 0 : scope_(ei.maybeScope())
822 0 : { }
823 :
824 0 : AbstractFramePtr frame() const { return frame_; }
825 : Scope* scope() const { return scope_; }
826 :
827 0 : void updateFrame(AbstractFramePtr frame) { frame_ = frame; }
828 :
829 : bool needsSweep();
830 : };
831 :
832 :
833 : /*****************************************************************************/
834 :
835 : /*
836 : * Debug environment objects
837 : *
838 : * The debugger effectively turns every opcode into a potential direct eval.
839 : * Naively, this would require creating a EnvironmentObject for every
840 : * call/block scope and using JSOP_GETALIASEDVAR for every access. To optimize
841 : * this, the engine assumes there is no debugger and optimizes scope access
842 : * and creation accordingly. When the debugger wants to perform an unexpected
843 : * eval-in-frame (or other, similar environment-requiring operations),
844 : * fp->environmentChain is now incomplete.
845 : *
846 : * To resolve this, the debugger first calls GetDebugEnvironmentFor* to
847 : * synthesize a "debug env chain". A debug env chain is just a chain of
848 : * objects that fill in missing environments and protect the engine from
849 : * unexpected access. (The latter means that some debugger operations, like
850 : * redefining a lexical binding, can fail when a true eval would succeed.) To
851 : * do both of these things, GetDebugEnvironmentFor* creates a new proxy
852 : * DebugEnvironmentProxy to sit in front of every existing EnvironmentObject.
853 : *
854 : * GetDebugEnvironmentFor* ensures the invariant that the same
855 : * DebugEnvironmentProxy is always produced for the same underlying
856 : * environment (optimized or not!). This is maintained by some bookkeeping
857 : * information stored in DebugEnvironments.
858 : */
859 :
860 : extern JSObject*
861 : GetDebugEnvironmentForFunction(JSContext* cx, HandleFunction fun);
862 :
863 : extern JSObject*
864 : GetDebugEnvironmentForFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
865 :
866 : extern JSObject*
867 : GetDebugEnvironmentForGlobalLexicalEnvironment(JSContext* cx);
868 :
869 : /* Provides debugger access to a environment. */
870 : class DebugEnvironmentProxy : public ProxyObject
871 : {
872 : /*
873 : * The enclosing environment on the dynamic environment chain. This slot is analogous
874 : * to the ENCLOSING_ENV_SLOT of a EnvironmentObject.
875 : */
876 : static const unsigned ENCLOSING_SLOT = 0;
877 :
878 : /*
879 : * NullValue or a dense array holding the unaliased variables of a function
880 : * frame that has been popped.
881 : */
882 : static const unsigned SNAPSHOT_SLOT = 1;
883 :
884 : public:
885 : static DebugEnvironmentProxy* create(JSContext* cx, EnvironmentObject& env,
886 : HandleObject enclosing);
887 :
888 : EnvironmentObject& environment() const;
889 : JSObject& enclosingEnvironment() const;
890 :
891 : /* May only be called for proxies to function call objects. */
892 : ArrayObject* maybeSnapshot() const;
893 : void initSnapshot(ArrayObject& snapshot);
894 :
895 : // Currently, the 'declarative' environments are function, module, and
896 : // lexical environments.
897 : bool isForDeclarative() const;
898 :
899 : // Get a property by 'id', but returns sentinel values instead of throwing
900 : // on exceptional cases.
901 : static bool getMaybeSentinelValue(JSContext* cx, Handle<DebugEnvironmentProxy*> env,
902 : HandleId id, MutableHandleValue vp);
903 :
904 : // Returns true iff this is a function environment with its own this-binding
905 : // (all functions except arrow functions and generator expression lambdas).
906 : bool isFunctionEnvironmentWithThis();
907 :
908 : // Does this debug environment not have a real counterpart or was never
909 : // live (and thus does not have a synthesized EnvironmentObject or a
910 : // snapshot)?
911 : bool isOptimizedOut() const;
912 : };
913 :
914 : /* Maintains per-compartment debug environment bookkeeping information. */
915 : class DebugEnvironments
916 : {
917 : Zone* zone_;
918 :
919 : /* The map from (non-debug) environments to debug environments. */
920 : ObjectWeakMap proxiedEnvs;
921 :
922 : /*
923 : * The map from live frames which have optimized-away environments to the
924 : * corresponding debug environments.
925 : */
926 : typedef HashMap<MissingEnvironmentKey,
927 : ReadBarrieredDebugEnvironmentProxy,
928 : MissingEnvironmentKey,
929 : RuntimeAllocPolicy> MissingEnvironmentMap;
930 : MissingEnvironmentMap missingEnvs;
931 :
932 : /*
933 : * The map from environment objects of live frames to the live frame. This
934 : * map updated lazily whenever the debugger needs the information. In
935 : * between two lazy updates, liveEnvs becomes incomplete (but not invalid,
936 : * onPop* removes environments as they are popped). Thus, two consecutive
937 : * debugger lazy updates of liveEnvs need only fill in the new
938 : * environments.
939 : */
940 : typedef GCHashMap<ReadBarriered<JSObject*>,
941 : LiveEnvironmentVal,
942 : MovableCellHasher<ReadBarriered<JSObject*>>,
943 : RuntimeAllocPolicy> LiveEnvironmentMap;
944 : LiveEnvironmentMap liveEnvs;
945 :
946 : public:
947 : DebugEnvironments(JSContext* cx, Zone* zone);
948 : ~DebugEnvironments();
949 :
950 : Zone* zone() const { return zone_; }
951 :
952 : private:
953 : bool init();
954 :
955 : static DebugEnvironments* ensureCompartmentData(JSContext* cx);
956 :
957 : template <typename Environment, typename Scope>
958 : static void onPopGeneric(JSContext* cx, const EnvironmentIter& ei);
959 :
960 : public:
961 : void trace(JSTracer* trc);
962 : void sweep(JSRuntime* rt);
963 : void finish();
964 : #ifdef JS_GC_ZEAL
965 : void checkHashTablesAfterMovingGC(JSRuntime* rt);
966 : #endif
967 :
968 : // If a live frame has a synthesized entry in missingEnvs, make sure it's not
969 : // collected.
970 : void traceLiveFrame(JSTracer* trc, AbstractFramePtr frame);
971 :
972 : static DebugEnvironmentProxy* hasDebugEnvironment(JSContext* cx, EnvironmentObject& env);
973 : static bool addDebugEnvironment(JSContext* cx, Handle<EnvironmentObject*> env,
974 : Handle<DebugEnvironmentProxy*> debugEnv);
975 :
976 : static DebugEnvironmentProxy* hasDebugEnvironment(JSContext* cx, const EnvironmentIter& ei);
977 : static bool addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
978 : Handle<DebugEnvironmentProxy*> debugEnv);
979 :
980 : static bool updateLiveEnvironments(JSContext* cx);
981 : static LiveEnvironmentVal* hasLiveEnvironment(EnvironmentObject& env);
982 : static void unsetPrevUpToDateUntil(JSContext* cx, AbstractFramePtr frame);
983 :
984 : // When a frame bails out from Ion to Baseline, there might be missing
985 : // envs keyed on, and live envs containing, the old
986 : // RematerializedFrame. Forward those values to the new BaselineFrame.
987 : static void forwardLiveFrame(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to);
988 :
989 : // When an environment is popped, we store a snapshot of its bindings that
990 : // live on the frame.
991 : //
992 : // This is done during frame unwinding, which cannot handle errors
993 : // gracefully. Errors result in no snapshot being set on the
994 : // DebugEnvironmentProxy.
995 : static void takeFrameSnapshot(JSContext* cx, Handle<DebugEnvironmentProxy*> debugEnv,
996 : AbstractFramePtr frame);
997 :
998 : // In debug-mode, these must be called whenever exiting a scope that might
999 : // have stack-allocated locals.
1000 : static void onPopCall(JSContext* cx, AbstractFramePtr frame);
1001 : static void onPopVar(JSContext* cx, const EnvironmentIter& ei);
1002 : static void onPopVar(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
1003 : static void onPopLexical(JSContext* cx, const EnvironmentIter& ei);
1004 : static void onPopLexical(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
1005 : static void onPopWith(AbstractFramePtr frame);
1006 : static void onCompartmentUnsetIsDebuggee(JSCompartment* c);
1007 : };
1008 :
1009 : } /* namespace js */
1010 :
1011 : template <>
1012 : inline bool
1013 292233 : JSObject::is<js::EnvironmentObject>() const
1014 : {
1015 557199 : return is<js::CallObject>() ||
1016 528935 : is<js::VarEnvironmentObject>() ||
1017 527938 : is<js::ModuleEnvironmentObject>() ||
1018 527938 : is<js::WasmFunctionCallObject>() ||
1019 351389 : is<js::LexicalEnvironmentObject>() ||
1020 157677 : is<js::WithEnvironmentObject>() ||
1021 427719 : is<js::NonSyntacticVariablesObject>() ||
1022 357462 : is<js::RuntimeLexicalErrorObject>();
1023 : }
1024 :
1025 : template<>
1026 : bool
1027 : JSObject::is<js::DebugEnvironmentProxy>() const;
1028 :
1029 : namespace js {
1030 :
1031 : inline bool
1032 36549 : IsSyntacticEnvironment(JSObject* env)
1033 : {
1034 36549 : if (!env->is<EnvironmentObject>())
1035 3226 : return false;
1036 :
1037 33323 : if (env->is<WithEnvironmentObject>())
1038 1036 : return env->as<WithEnvironmentObject>().isSyntactic();
1039 :
1040 32287 : if (env->is<LexicalEnvironmentObject>())
1041 26276 : return env->as<LexicalEnvironmentObject>().isSyntactic();
1042 :
1043 6011 : if (env->is<NonSyntacticVariablesObject>())
1044 369 : return false;
1045 :
1046 5642 : return true;
1047 : }
1048 :
1049 : inline bool
1050 825 : IsExtensibleLexicalEnvironment(JSObject* env)
1051 : {
1052 1650 : return env->is<LexicalEnvironmentObject>() &&
1053 1650 : env->as<LexicalEnvironmentObject>().isExtensible();
1054 : }
1055 :
1056 : inline bool
1057 11933 : IsGlobalLexicalEnvironment(JSObject* env)
1058 : {
1059 23866 : return env->is<LexicalEnvironmentObject>() &&
1060 23866 : env->as<LexicalEnvironmentObject>().isGlobal();
1061 : }
1062 :
1063 : inline JSObject*
1064 752 : MaybeUnwrapWithEnvironment(JSObject* env)
1065 : {
1066 752 : if (env->is<WithEnvironmentObject>())
1067 6 : return &env->as<WithEnvironmentObject>().object();
1068 746 : return env;
1069 : }
1070 :
1071 : template <typename SpecificEnvironment>
1072 : inline bool
1073 5764 : IsFrameInitialEnvironment(AbstractFramePtr frame, SpecificEnvironment& env)
1074 : {
1075 : // A frame's initial environment is the innermost environment
1076 : // corresponding to the scope chain from frame.script()->bodyScope() to
1077 : // frame.script()->outermostScope(). This environment must be on the chain
1078 : // for the frame to be considered initialized. That is, it must be on the
1079 : // chain for the environment chain to fully match the scope chain at the
1080 : // start of execution in the frame.
1081 : //
1082 : // This logic must be in sync with the HAS_INITIAL_ENV logic in
1083 : // InitFromBailout.
1084 :
1085 : // A function frame's CallObject, if present, is always the initial
1086 : // environment.
1087 : if (mozilla::IsSame<SpecificEnvironment, CallObject>::value)
1088 4253 : return true;
1089 :
1090 : // For an eval frame, the VarEnvironmentObject, if present, is always the
1091 : // initial environment.
1092 1511 : if (mozilla::IsSame<SpecificEnvironment, VarEnvironmentObject>::value &&
1093 : frame.isEvalFrame())
1094 : {
1095 2 : return true;
1096 : }
1097 :
1098 : // For named lambda frames without CallObjects (i.e., no binding in the
1099 : // body of the function was closed over), the LexicalEnvironmentObject
1100 : // corresponding to the named lambda scope is the initial environment.
1101 1509 : if (mozilla::IsSame<SpecificEnvironment, NamedLambdaObject>::value &&
1102 4 : frame.isFunctionFrame() &&
1103 4 : frame.callee()->needsNamedLambdaEnvironment() &&
1104 2 : !frame.callee()->needsCallObject())
1105 : {
1106 0 : LexicalScope* namedLambdaScope = frame.script()->maybeNamedLambdaScope();
1107 0 : return &env.template as<LexicalEnvironmentObject>().scope() == namedLambdaScope;
1108 : }
1109 :
1110 1509 : return false;
1111 : }
1112 :
1113 : extern bool
1114 : CreateObjectsForEnvironmentChain(JSContext* cx, AutoObjectVector& chain,
1115 : HandleObject terminatingEnv,
1116 : MutableHandleObject envObj);
1117 :
1118 : ModuleEnvironmentObject* GetModuleEnvironmentForScript(JSScript* script);
1119 :
1120 : MOZ_MUST_USE bool
1121 : GetThisValueForDebuggerMaybeOptimizedOut(JSContext* cx, AbstractFramePtr frame,
1122 : jsbytecode* pc, MutableHandleValue res);
1123 :
1124 : MOZ_MUST_USE bool
1125 : CheckVarNameConflict(JSContext* cx, Handle<LexicalEnvironmentObject*> lexicalEnv,
1126 : HandlePropertyName name);
1127 :
1128 : MOZ_MUST_USE bool
1129 : CheckCanDeclareGlobalBinding(JSContext* cx, Handle<GlobalObject*> global,
1130 : HandlePropertyName name, bool isFunction);
1131 :
1132 : MOZ_MUST_USE bool
1133 : CheckLexicalNameConflict(JSContext* cx, Handle<LexicalEnvironmentObject*> lexicalEnv,
1134 : HandleObject varObj, HandlePropertyName name);
1135 :
1136 : MOZ_MUST_USE bool
1137 : CheckGlobalDeclarationConflicts(JSContext* cx, HandleScript script,
1138 : Handle<LexicalEnvironmentObject*> lexicalEnv,
1139 : HandleObject varObj);
1140 :
1141 : MOZ_MUST_USE bool
1142 : CheckEvalDeclarationConflicts(JSContext* cx, HandleScript script, HandleObject envChain,
1143 : HandleObject varObj);
1144 :
1145 : MOZ_MUST_USE bool
1146 : InitFunctionEnvironmentObjects(JSContext* cx, AbstractFramePtr frame);
1147 :
1148 : MOZ_MUST_USE bool
1149 : PushVarEnvironmentObject(JSContext* cx, HandleScope scope, AbstractFramePtr frame);
1150 :
1151 : MOZ_MUST_USE bool
1152 : GetFrameEnvironmentAndScope(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc,
1153 : MutableHandleObject env, MutableHandleScope scope);
1154 :
1155 : #ifdef DEBUG
1156 : bool
1157 : AnalyzeEntrainedVariables(JSContext* cx, HandleScript script);
1158 : #endif
1159 :
1160 : } // namespace js
1161 :
1162 : namespace JS {
1163 :
1164 : template <>
1165 : struct DeletePolicy<js::DebugEnvironments> : public js::GCManagedDeletePolicy<js::DebugEnvironments>
1166 : {};
1167 :
1168 : } // namespace JS
1169 :
1170 : #endif /* vm_EnvironmentObject_h */
|