REGRESSION(r200383): Setting lazily initialized properties across frame boundaries...
[WebKit-https.git] / Source / JavaScriptCore / runtime / PropertySlot.h
1 /*
2  *  Copyright (C) 2005, 2007, 2008, 2015-2016 Apple Inc. All rights reserved.
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Library General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Library General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Library General Public License
15  *  along with this library; see the file COPYING.LIB.  If not, write to
16  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  *  Boston, MA 02110-1301, USA.
18  *
19  */
20
21 #ifndef PropertySlot_h
22 #define PropertySlot_h
23
24 #include "JSCJSValue.h"
25 #include "PropertyName.h"
26 #include "PropertyOffset.h"
27 #include <wtf/Assertions.h>
28
29 namespace JSC {
30
31 class ExecState;
32 class GetterSetter;
33 class JSObject;
34
35 // ECMA 262-3 8.6.1
36 // Property attributes
37 enum Attribute {
38     None              = 0,
39     ReadOnly          = 1 << 1,  // property can be only read, not written
40     DontEnum          = 1 << 2,  // property doesn't appear in (for .. in ..)
41     DontDelete        = 1 << 3,  // property can't be deleted
42     Accessor          = 1 << 4,  // property is a getter/setter
43     CustomAccessor    = 1 << 5,
44
45     // Things that are used by static hashtables are not in the attributes byte in PropertyMapEntry.
46     Function          = 1 << 8,  // property is a function - only used by static hashtables
47     Builtin           = 1 << 9,  // property is a builtin function - only used by static hashtables
48     ConstantInteger   = 1 << 10, // property is a constant integer - only used by static hashtables
49     CellProperty      = 1 << 11, // property is a lazy property - only used by static hashtables
50     ClassStructure    = 1 << 12, // property is a lazy class structure - only used by static hashtables
51     PropertyCallback  = 1 << 13, // property that is a lazy property callback - only used by static hashtables
52     BuiltinOrFunction = Builtin | Function, // helper only used by static hashtables
53     BuiltinOrFunctionOrLazyProperty = Builtin | Function | CellProperty | ClassStructure | PropertyCallback, // helper only used by static hashtables
54     BuiltinOrFunctionOrAccessorOrLazyProperty = Builtin | Function | Accessor | CellProperty | ClassStructure | PropertyCallback, // helper only used by static hashtables
55     BuiltinOrFunctionOrAccessorOrLazyPropertyOrConstant = Builtin | Function | Accessor | CellProperty | ClassStructure | PropertyCallback | ConstantInteger // helper only used by static hashtables
56 };
57
58 enum CacheabilityType : uint8_t {
59     CachingDisallowed,
60     CachingAllowed
61 };
62
63 inline unsigned attributesForStructure(unsigned attributes)
64 {
65     // The attributes that are used just for the static hashtable are at bit 8 and higher.
66     return static_cast<uint8_t>(attributes);
67 }
68
69 class PropertySlot {
70     enum PropertyType : uint8_t {
71         TypeUnset,
72         TypeValue,
73         TypeGetter,
74         TypeCustom
75     };
76
77 public:
78     enum class InternalMethodType : uint8_t {
79         Get, // [[Get]] internal method in the spec.
80         HasProperty, // [[HasProperty]] internal method in the spec.
81         GetOwnProperty, // [[GetOwnProperty]] internal method in the spec.
82         VMInquiry, // Our VM is just poking around. When this is the InternalMethodType, getOwnPropertySlot is not allowed to do user observable actions.
83     };
84
85     explicit PropertySlot(const JSValue thisValue, InternalMethodType internalMethodType)
86         : m_offset(invalidOffset)
87         , m_thisValue(thisValue)
88         , m_slotBase(nullptr)
89         , m_watchpointSet(nullptr)
90         , m_cacheability(CachingAllowed)
91         , m_propertyType(TypeUnset)
92         , m_internalMethodType(internalMethodType)
93         , m_isTaintedByProxy(false)
94     {
95     }
96
97     typedef EncodedJSValue (*GetValueFunc)(ExecState*, EncodedJSValue thisValue, PropertyName);
98
99     JSValue getValue(ExecState*, PropertyName) const;
100     JSValue getValue(ExecState*, unsigned propertyName) const;
101     JSValue getPureResult() const;
102
103     bool isCacheable() const { return m_cacheability == CachingAllowed && m_offset != invalidOffset; }
104     bool isUnset() const { return m_propertyType == TypeUnset; }
105     bool isValue() const { return m_propertyType == TypeValue; }
106     bool isAccessor() const { return m_propertyType == TypeGetter; }
107     bool isCustom() const { return m_propertyType == TypeCustom; }
108     bool isCacheableValue() const { return isCacheable() && isValue(); }
109     bool isCacheableGetter() const { return isCacheable() && isAccessor(); }
110     bool isCacheableCustom() const { return isCacheable() && isCustom(); }
111     void setIsTaintedByProxy() { m_isTaintedByProxy = true; }
112     bool isTaintedByProxy() const { return m_isTaintedByProxy; }
113
114     InternalMethodType internalMethodType() const { return m_internalMethodType; }
115
116     void disableCaching()
117     {
118         m_cacheability = CachingDisallowed;
119     }
120
121     unsigned attributes() const { return m_attributes; }
122
123     PropertyOffset cachedOffset() const
124     {
125         ASSERT(isCacheable());
126         return m_offset;
127     }
128
129     GetterSetter* getterSetter() const
130     {
131         ASSERT(isAccessor());
132         return m_data.getter.getterSetter;
133     }
134
135     GetValueFunc customGetter() const
136     {
137         ASSERT(isCacheableCustom());
138         return m_data.custom.getValue;
139     }
140
141     JSObject* slotBase() const
142     {
143         return m_slotBase;
144     }
145
146     WatchpointSet* watchpointSet() const
147     {
148         return m_watchpointSet;
149     }
150
151     void setValue(JSObject* slotBase, unsigned attributes, JSValue value)
152     {
153         ASSERT(attributes == attributesForStructure(attributes));
154         
155         m_data.value = JSValue::encode(value);
156         m_attributes = attributes;
157
158         ASSERT(slotBase);
159         m_slotBase = slotBase;
160         m_propertyType = TypeValue;
161         m_offset = invalidOffset;
162     }
163     
164     void setValue(JSObject* slotBase, unsigned attributes, JSValue value, PropertyOffset offset)
165     {
166         ASSERT(attributes == attributesForStructure(attributes));
167         
168         ASSERT(value);
169         m_data.value = JSValue::encode(value);
170         m_attributes = attributes;
171
172         ASSERT(slotBase);
173         m_slotBase = slotBase;
174         m_propertyType = TypeValue;
175         m_offset = offset;
176     }
177
178     void setValue(JSString*, unsigned attributes, JSValue value)
179     {
180         ASSERT(attributes == attributesForStructure(attributes));
181         
182         ASSERT(value);
183         m_data.value = JSValue::encode(value);
184         m_attributes = attributes;
185
186         m_slotBase = 0;
187         m_propertyType = TypeValue;
188         m_offset = invalidOffset;
189     }
190
191     void setCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
192     {
193         ASSERT(attributes == attributesForStructure(attributes));
194         
195         ASSERT(getValue);
196         m_data.custom.getValue = getValue;
197         m_attributes = attributes;
198
199         ASSERT(slotBase);
200         m_slotBase = slotBase;
201         m_propertyType = TypeCustom;
202         m_offset = invalidOffset;
203     }
204     
205     void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
206     {
207         ASSERT(attributes == attributesForStructure(attributes));
208         
209         ASSERT(getValue);
210         m_data.custom.getValue = getValue;
211         m_attributes = attributes;
212
213         ASSERT(slotBase);
214         m_slotBase = slotBase;
215         m_propertyType = TypeCustom;
216         m_offset = !invalidOffset;
217     }
218
219     void setGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter)
220     {
221         ASSERT(attributes == attributesForStructure(attributes));
222         
223         ASSERT(getterSetter);
224         m_data.getter.getterSetter = getterSetter;
225         m_attributes = attributes;
226
227         ASSERT(slotBase);
228         m_slotBase = slotBase;
229         m_propertyType = TypeGetter;
230         m_offset = invalidOffset;
231     }
232
233     void setCacheableGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter, PropertyOffset offset)
234     {
235         ASSERT(attributes == attributesForStructure(attributes));
236         
237         ASSERT(getterSetter);
238         m_data.getter.getterSetter = getterSetter;
239         m_attributes = attributes;
240
241         ASSERT(slotBase);
242         m_slotBase = slotBase;
243         m_propertyType = TypeGetter;
244         m_offset = offset;
245     }
246
247     void setThisValue(JSValue thisValue)
248     {
249         m_thisValue = thisValue;
250     }
251
252     void setUndefined()
253     {
254         m_data.value = JSValue::encode(jsUndefined());
255         m_attributes = ReadOnly | DontDelete | DontEnum;
256
257         m_slotBase = 0;
258         m_propertyType = TypeValue;
259         m_offset = invalidOffset;
260     }
261
262     void setWatchpointSet(WatchpointSet& set)
263     {
264         m_watchpointSet = &set;
265     }
266
267 private:
268     JS_EXPORT_PRIVATE JSValue functionGetter(ExecState*) const;
269     JS_EXPORT_PRIVATE JSValue customGetter(ExecState*, PropertyName) const;
270
271     unsigned m_attributes;
272     union {
273         EncodedJSValue value;
274         struct {
275             GetterSetter* getterSetter;
276         } getter;
277         struct {
278             GetValueFunc getValue;
279         } custom;
280     } m_data;
281
282     PropertyOffset m_offset;
283     JSValue m_thisValue;
284     JSObject* m_slotBase;
285     WatchpointSet* m_watchpointSet;
286     CacheabilityType m_cacheability;
287     PropertyType m_propertyType;
288     InternalMethodType m_internalMethodType;
289     bool m_isTaintedByProxy;
290 };
291
292 ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, PropertyName propertyName) const
293 {
294     if (m_propertyType == TypeValue)
295         return JSValue::decode(m_data.value);
296     if (m_propertyType == TypeGetter)
297         return functionGetter(exec);
298     return customGetter(exec, propertyName);
299 }
300
301 ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, unsigned propertyName) const
302 {
303     if (m_propertyType == TypeValue)
304         return JSValue::decode(m_data.value);
305     if (m_propertyType == TypeGetter)
306         return functionGetter(exec);
307     return customGetter(exec, Identifier::from(exec, propertyName));
308 }
309
310 } // namespace JSC
311
312 #endif // PropertySlot_h