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