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_ScopeObject_inl_h
8 #define vm_ScopeObject_inl_h
9 
10 #include "vm/ScopeObject.h"
11 #include "frontend/SharedContext.h"
12 
13 #include "jsobjinlines.h"
14 
15 #include "vm/TypeInference-inl.h"
16 
17 namespace js {
18 
19 inline ClonedBlockObject&
NearestEnclosingExtensibleLexicalScope(JSObject * scope)20 NearestEnclosingExtensibleLexicalScope(JSObject* scope)
21 {
22     while (!IsExtensibleLexicalScope(scope))
23         scope = scope->enclosingScope();
24     return scope->as<ClonedBlockObject>();
25 }
26 
27 inline void
setAliasedVar(JSContext * cx,ScopeCoordinate sc,PropertyName * name,const Value & v)28 ScopeObject::setAliasedVar(JSContext* cx, ScopeCoordinate sc, PropertyName* name, const Value& v)
29 {
30     MOZ_ASSERT(is<LexicalScopeBase>() || is<ClonedBlockObject>());
31     JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == BlockObject::RESERVED_SLOTS);
32 
33     // name may be null if we don't need to track side effects on the object.
34     MOZ_ASSERT_IF(isSingleton(), name);
35 
36     if (isSingleton()) {
37         MOZ_ASSERT(name);
38         AddTypePropertyId(cx, this, NameToId(name), v);
39 
40         // Keep track of properties which have ever been overwritten.
41         if (!getSlot(sc.slot()).isUndefined()) {
42             Shape* shape = lookup(cx, name);
43             shape->setOverwritten();
44         }
45     }
46 
47     setSlot(sc.slot(), v);
48 }
49 
50 inline void
setAliasedVar(JSContext * cx,AliasedFormalIter fi,PropertyName * name,const Value & v)51 LexicalScopeBase::setAliasedVar(JSContext* cx, AliasedFormalIter fi, PropertyName* name,
52                                 const Value& v)
53 {
54     MOZ_ASSERT(name == fi->name());
55     setSlot(fi.scopeSlot(), v);
56     if (isSingleton())
57         AddTypePropertyId(cx, this, NameToId(name), v);
58 }
59 
60 inline void
setAliasedVarFromArguments(JSContext * cx,const Value & argsValue,jsid id,const Value & v)61 LexicalScopeBase::setAliasedVarFromArguments(JSContext* cx, const Value& argsValue, jsid id,
62                                              const Value& v)
63 {
64     setSlot(ArgumentsObject::SlotFromMagicScopeSlotValue(argsValue), v);
65     if (isSingleton())
66         AddTypePropertyId(cx, this, id, v);
67 }
68 
69 inline void
initRemainingSlotsToUninitializedLexicals(uint32_t begin)70 LexicalScopeBase::initRemainingSlotsToUninitializedLexicals(uint32_t begin)
71 {
72     uint32_t end = slotSpan();
73     for (uint32_t slot = begin; slot < end; slot++)
74         initSlot(slot, MagicValue(JS_UNINITIALIZED_LEXICAL));
75 }
76 
77 inline void
initAliasedLexicalsToThrowOnTouch(JSScript * script)78 LexicalScopeBase::initAliasedLexicalsToThrowOnTouch(JSScript* script)
79 {
80     initRemainingSlotsToUninitializedLexicals(script->bindings.aliasedBodyLevelLexicalBegin());
81 }
82 
83 template <AllowGC allowGC>
84 inline void
85 StaticScopeIter<allowGC>::operator++(int)
86 {
87     if (obj->template is<NestedScopeObject>()) {
88         obj = obj->template as<NestedScopeObject>().enclosingScopeForStaticScopeIter();
89     } else if (obj->template is<StaticEvalObject>()) {
90         obj = obj->template as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
91     } else if (obj->template is<StaticNonSyntacticScopeObjects>()) {
92         obj = obj->template as<StaticNonSyntacticScopeObjects>().enclosingScopeForStaticScopeIter();
93     } else if (obj->template is<ModuleObject>()) {
94         obj = obj->template as<ModuleObject>().enclosingStaticScope();
95     } else if (onNamedLambda || !obj->template as<JSFunction>().isNamedLambda()) {
96         onNamedLambda = false;
97         JSFunction& fun = obj->template as<JSFunction>();
98         if (fun.isBeingParsed())
99             obj = fun.functionBox()->enclosingStaticScope();
100         else
101             obj = fun.nonLazyScript()->enclosingStaticScope();
102     } else {
103         onNamedLambda = true;
104     }
105     MOZ_ASSERT_IF(obj, IsStaticScope(obj));
106     MOZ_ASSERT_IF(onNamedLambda, obj->template is<JSFunction>());
107 }
108 
109 template <AllowGC allowGC>
110 inline bool
hasSyntacticDynamicScopeObject()111 StaticScopeIter<allowGC>::hasSyntacticDynamicScopeObject() const
112 {
113     if (obj->template is<JSFunction>()) {
114         JSFunction& fun = obj->template as<JSFunction>();
115         if (fun.isBeingParsed())
116             return fun.functionBox()->needsCallObject();
117         return fun.needsCallObject();
118     }
119     if (obj->template is<ModuleObject>())
120         return true;
121     if (obj->template is<StaticBlockObject>()) {
122         return obj->template as<StaticBlockObject>().needsClone() ||
123                obj->template as<StaticBlockObject>().isGlobal();
124     }
125     if (obj->template is<StaticWithObject>())
126         return true;
127     if (obj->template is<StaticEvalObject>())
128         return obj->template as<StaticEvalObject>().isStrict();
129     MOZ_ASSERT(obj->template is<StaticNonSyntacticScopeObjects>());
130     return false;
131 }
132 
133 template <AllowGC allowGC>
134 inline Shape*
scopeShape()135 StaticScopeIter<allowGC>::scopeShape() const
136 {
137     MOZ_ASSERT(hasSyntacticDynamicScopeObject());
138     MOZ_ASSERT(type() != NamedLambda && type() != Eval);
139     if (type() == Block)
140         return block().lastProperty();
141     if (type() == Module)
142         return moduleScript()->callObjShape();
143     return funScript()->callObjShape();
144 }
145 
146 template <AllowGC allowGC>
147 inline typename StaticScopeIter<allowGC>::Type
type()148 StaticScopeIter<allowGC>::type() const
149 {
150     if (onNamedLambda)
151         return NamedLambda;
152     if (obj->template is<StaticBlockObject>())
153         return Block;
154     if (obj->template is<StaticWithObject>())
155         return With;
156     if (obj->template is<StaticEvalObject>())
157         return Eval;
158     if (obj->template is<StaticNonSyntacticScopeObjects>())
159         return NonSyntactic;
160     if (obj->template is<ModuleObject>())
161         return Module;
162     MOZ_ASSERT(obj->template is<JSFunction>());
163     return Function;
164 }
165 
166 template <AllowGC allowGC>
167 inline StaticBlockObject&
block()168 StaticScopeIter<allowGC>::block() const
169 {
170     MOZ_ASSERT(type() == Block);
171     return obj->template as<StaticBlockObject>();
172 }
173 
174 template <AllowGC allowGC>
175 inline StaticWithObject&
staticWith()176 StaticScopeIter<allowGC>::staticWith() const
177 {
178     MOZ_ASSERT(type() == With);
179     return obj->template as<StaticWithObject>();
180 }
181 
182 template <AllowGC allowGC>
183 inline StaticEvalObject&
eval()184 StaticScopeIter<allowGC>::eval() const
185 {
186     MOZ_ASSERT(type() == Eval);
187     return obj->template as<StaticEvalObject>();
188 }
189 
190 template <AllowGC allowGC>
191 inline StaticNonSyntacticScopeObjects&
nonSyntactic()192 StaticScopeIter<allowGC>::nonSyntactic() const
193 {
194     MOZ_ASSERT(type() == NonSyntactic);
195     return obj->template as<StaticNonSyntacticScopeObjects>();
196 }
197 
198 template <AllowGC allowGC>
199 inline JSScript*
funScript()200 StaticScopeIter<allowGC>::funScript() const
201 {
202     MOZ_ASSERT(type() == Function);
203     return obj->template as<JSFunction>().nonLazyScript();
204 }
205 
206 template <AllowGC allowGC>
207 inline JSFunction&
fun()208 StaticScopeIter<allowGC>::fun() const
209 {
210     MOZ_ASSERT(type() == Function);
211     return obj->template as<JSFunction>();
212 }
213 
214 template <AllowGC allowGC>
215 inline frontend::FunctionBox*
maybeFunctionBox()216 StaticScopeIter<allowGC>::maybeFunctionBox() const
217 {
218     MOZ_ASSERT(type() == Function);
219     if (fun().isBeingParsed())
220         return fun().functionBox();
221     return nullptr;
222 }
223 
224 template <AllowGC allowGC>
225 inline JSScript*
moduleScript()226 StaticScopeIter<allowGC>::moduleScript() const
227 {
228     MOZ_ASSERT(type() == Module);
229     return obj->template as<ModuleObject>().script();
230 }
231 
232 template <AllowGC allowGC>
233 inline ModuleObject&
module()234 StaticScopeIter<allowGC>::module() const
235 {
236     MOZ_ASSERT(type() == Module);
237     return obj->template as<ModuleObject>();
238 }
239 
240 }  /* namespace js */
241 
242 inline JSObject*
enclosingScope()243 JSObject::enclosingScope()
244 {
245     if (is<js::ScopeObject>())
246         return &as<js::ScopeObject>().enclosingScope();
247 
248     if (is<js::DebugScopeObject>())
249         return &as<js::DebugScopeObject>().enclosingScope();
250 
251     if (is<js::GlobalObject>())
252         return nullptr;
253 
254     MOZ_ASSERT_IF(is<JSFunction>(), as<JSFunction>().isInterpreted());
255     return &global();
256 }
257 
258 #endif /* vm_ScopeObject_inl_h */
259