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