74e7d8cb26d1e03b97da63b4b4719016e0259357
[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     BuiltinOrFunctionOrAccessorOrLazyProperty = Builtin | Function | Accessor | CellProperty | ClassStructure | PropertyCallback, // helper only used by static hashtables
54     BuiltinOrFunctionOrAccessorOrLazyPropertyOrConstant = Builtin | Function | Accessor | CellProperty | ClassStructure | PropertyCallback | ConstantInteger // helper only used by static hashtables
55 };
56
57 enum CacheabilityType : uint8_t {
58     CachingDisallowed,
59     CachingAllowed
60 };
61
62 inline unsigned attributesForStructure(unsigned attributes)
63 {
64     // The attributes that are used just for the static hashtable are at bit 8 and higher.
65     return static_cast<uint8_t>(attributes);
66 }
67
68 class PropertySlot {
69     enum PropertyType : uint8_t {
70         TypeUnset,
71         TypeValue,
72         TypeGetter,
73         TypeCustom
74     };
75
76 public:
77     enum class InternalMethodType : uint8_t {
78         Get, // [[Get]] internal method in the spec.
79         HasProperty, // [[HasProperty]] internal method in the spec.
80         GetOwnProperty, // [[GetOwnProperty]] internal method in the spec.
81         VMInquiry, // Our VM is just poking around. When this is the InternalMethodType, getOwnPropertySlot is not allowed to do user observable actions.
82     };
83
84     explicit PropertySlot(const JSValue thisValue, InternalMethodType internalMethodType)
85         : m_offset(invalidOffset)
86         , m_thisValue(thisValue)
87         , m_slotBase(nullptr)
88         , m_watchpointSet(nullptr)
89         , m_cacheability(CachingAllowed)
90         , m_propertyType(TypeUnset)
91         , m_internalMethodType(internalMethodType)
92         , m_isTaintedByProxy(false)
93     {
94     }
95
96     typedef EncodedJSValue (*GetValueFunc)(ExecState*, EncodedJSValue thisValue, PropertyName);
97
98     JSValue getValue(ExecState*, PropertyName) const;
99     JSValue getValue(ExecState*, unsigned propertyName) const;
100     JSValue getPureResult() const;
101
102     bool isCacheable() const { return m_cacheability == CachingAllowed && m_offset != invalidOffset; }
103     bool isUnset() const { return m_propertyType == TypeUnset; }
104     bool isValue() const { return m_propertyType == TypeValue; }
105     bool isAccessor() const { return m_propertyType == TypeGetter; }
106     bool isCustom() const { return m_propertyType == TypeCustom; }
107     bool isCacheableValue() const { return isCacheable() && isValue(); }
108     bool isCacheableGetter() const { return isCacheable() && isAccessor(); }
109     bool isCacheableCustom() const { return isCacheable() && isCustom(); }
110     void setIsTaintedByProxy() { m_isTaintedByProxy = true; }
111     bool isTaintedByProxy() const { return m_isTaintedByProxy; }
112
113     InternalMethodType internalMethodType() const { return m_internalMethodType; }
114
115     void disableCaching()
116     {
117         m_cacheability = CachingDisallowed;
118     }
119
120     unsigned attributes() const { return m_attributes; }
121
122     PropertyOffset cachedOffset() const
123     {
124         ASSERT(isCacheable());
125         return m_offset;
126     }
127
128     GetterSetter* getterSetter() const
129     {
130         ASSERT(isAccessor());
131         return m_data.getter.getterSetter;
132     }
133
134     GetValueFunc customGetter() const
135     {
136         ASSERT(isCacheableCustom());
137         return m_data.custom.getValue;
138     }
139
140     JSObject* slotBase() const
141     {
142         return m_slotBase;
143     }
144
145     WatchpointSet* watchpointSet() const
146     {
147         return m_watchpointSet;
148     }
149
150     void setValue(JSObject* slotBase, unsigned attributes, JSValue value)
151     {
152         ASSERT(attributes == attributesForStructure(attributes));
153         
154         m_data.value = JSValue::encode(value);
155         m_attributes = attributes;
156
157         ASSERT(slotBase);
158         m_slotBase = slotBase;
159         m_propertyType = TypeValue;
160         m_offset = invalidOffset;
161     }
162     
163     void setValue(JSObject* slotBase, unsigned attributes, JSValue value, PropertyOffset offset)
164     {
165         ASSERT(attributes == attributesForStructure(attributes));
166         
167         ASSERT(value);
168         m_data.value = JSValue::encode(value);
169         m_attributes = attributes;
170
171         ASSERT(slotBase);
172         m_slotBase = slotBase;
173         m_propertyType = TypeValue;
174         m_offset = offset;
175     }
176
177     void setValue(JSString*, unsigned attributes, JSValue value)
178     {
179         ASSERT(attributes == attributesForStructure(attributes));
180         
181         ASSERT(value);
182         m_data.value = JSValue::encode(value);
183         m_attributes = attributes;
184
185         m_slotBase = 0;
186         m_propertyType = TypeValue;
187         m_offset = invalidOffset;
188     }
189
190     void setCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
191     {
192         ASSERT(attributes == attributesForStructure(attributes));
193         
194         ASSERT(getValue);
195         m_data.custom.getValue = getValue;
196         m_attributes = attributes;
197
198         ASSERT(slotBase);
199         m_slotBase = slotBase;
200         m_propertyType = TypeCustom;
201         m_offset = invalidOffset;
202     }
203     
204     void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
205     {
206         ASSERT(attributes == attributesForStructure(attributes));
207         
208         ASSERT(getValue);
209         m_data.custom.getValue = getValue;
210         m_attributes = attributes;
211
212         ASSERT(slotBase);
213         m_slotBase = slotBase;
214         m_propertyType = TypeCustom;
215         m_offset = !invalidOffset;
216     }
217
218     void setGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter)
219     {
220         ASSERT(attributes == attributesForStructure(attributes));
221         
222         ASSERT(getterSetter);
223         m_data.getter.getterSetter = getterSetter;
224         m_attributes = attributes;
225
226         ASSERT(slotBase);
227         m_slotBase = slotBase;
228         m_propertyType = TypeGetter;
229         m_offset = invalidOffset;
230     }
231
232     void setCacheableGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter, PropertyOffset offset)
233     {
234         ASSERT(attributes == attributesForStructure(attributes));
235         
236         ASSERT(getterSetter);
237         m_data.getter.getterSetter = getterSetter;
238         m_attributes = attributes;
239
240         ASSERT(slotBase);
241         m_slotBase = slotBase;
242         m_propertyType = TypeGetter;
243         m_offset = offset;
244     }
245
246     void setThisValue(JSValue thisValue)
247     {
248         m_thisValue = thisValue;
249     }
250
251     void setUndefined()
252     {
253         m_data.value = JSValue::encode(jsUndefined());
254         m_attributes = ReadOnly | DontDelete | DontEnum;
255
256         m_slotBase = 0;
257         m_propertyType = TypeValue;
258         m_offset = invalidOffset;
259     }
260
261     void setWatchpointSet(WatchpointSet& set)
262     {
263         m_watchpointSet = &set;
264     }
265
266 private:
267     JS_EXPORT_PRIVATE JSValue functionGetter(ExecState*) const;
268     JS_EXPORT_PRIVATE JSValue customGetter(ExecState*, PropertyName) const;
269
270     unsigned m_attributes;
271     union {
272         EncodedJSValue value;
273         struct {
274             GetterSetter* getterSetter;
275         } getter;
276         struct {
277             GetValueFunc getValue;
278         } custom;
279     } m_data;
280
281     PropertyOffset m_offset;
282     JSValue m_thisValue;
283     JSObject* m_slotBase;
284     WatchpointSet* m_watchpointSet;
285     CacheabilityType m_cacheability;
286     PropertyType m_propertyType;
287     InternalMethodType m_internalMethodType;
288     bool m_isTaintedByProxy;
289 };
290
291 ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, PropertyName propertyName) const
292 {
293     if (m_propertyType == TypeValue)
294         return JSValue::decode(m_data.value);
295     if (m_propertyType == TypeGetter)
296         return functionGetter(exec);
297     return customGetter(exec, propertyName);
298 }
299
300 ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, unsigned propertyName) const
301 {
302     if (m_propertyType == TypeValue)
303         return JSValue::decode(m_data.value);
304     if (m_propertyType == TypeGetter)
305         return functionGetter(exec);
306     return customGetter(exec, Identifier::from(exec, propertyName));
307 }
308
309 } // namespace JSC
310
311 #endif // PropertySlot_h