1/*
2 *  Copyright (C) 2005, 2007, 2008 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    Function          = 1 << 4,  // property is a function - only used by static hashtables
44    Accessor          = 1 << 5,  // property is a getter/setter
45    CustomAccessor    = 1 << 6,
46    Builtin           = 1 << 7, // property is a builtin function - only used by static hashtables
47    ConstantInteger   = 1 << 8, // property is a constant integer - only used by static hashtables
48    BuiltinOrFunction = Builtin | Function, // helper only used by static hashtables
49    BuiltinOrFunctionOrConstant = Builtin | Function | ConstantInteger, // helper only used by static hashtables
50};
51
52class PropertySlot {
53    enum PropertyType {
54        TypeUnset,
55        TypeValue,
56        TypeGetter,
57        TypeCustom
58    };
59
60    enum CacheabilityType {
61        CachingDisallowed,
62        CachingAllowed
63    };
64
65public:
66    explicit PropertySlot(const JSValue thisValue)
67        : m_propertyType(TypeUnset)
68        , m_offset(invalidOffset)
69        , m_thisValue(thisValue)
70        , m_watchpointSet(nullptr)
71        , m_cacheability(CachingAllowed)
72    {
73    }
74
75    typedef EncodedJSValue (*GetValueFunc)(ExecState*, JSObject* slotBase, EncodedJSValue thisValue, PropertyName);
76
77    JSValue getValue(ExecState*, PropertyName) const;
78    JSValue getValue(ExecState*, unsigned propertyName) const;
79
80    bool isCacheable() const { return m_cacheability == CachingAllowed && m_offset != invalidOffset; }
81    bool isValue() const { return m_propertyType == TypeValue; }
82    bool isAccessor() const { return m_propertyType == TypeGetter; }
83    bool isCustom() const { return m_propertyType == TypeCustom; }
84    bool isCacheableValue() const { return isCacheable() && isValue(); }
85    bool isCacheableGetter() const { return isCacheable() && isAccessor(); }
86    bool isCacheableCustom() const { return isCacheable() && isCustom(); }
87
88    void disableCaching()
89    {
90        m_cacheability = CachingDisallowed;
91    }
92
93    unsigned attributes() const { return m_attributes; }
94
95    PropertyOffset cachedOffset() const
96    {
97        ASSERT(isCacheable());
98        return m_offset;
99    }
100
101    GetterSetter* getterSetter() const
102    {
103        ASSERT(isAccessor());
104        return m_data.getter.getterSetter;
105    }
106
107    GetValueFunc customGetter() const
108    {
109        ASSERT(isCacheableCustom());
110        return m_data.custom.getValue;
111    }
112
113    JSObject* slotBase() const
114    {
115        ASSERT(m_propertyType != TypeUnset);
116        return m_slotBase;
117    }
118
119    WatchpointSet* watchpointSet() const
120    {
121        return m_watchpointSet;
122    }
123
124    void setValue(JSObject* slotBase, unsigned attributes, JSValue value)
125    {
126        ASSERT(value);
127        m_data.value = JSValue::encode(value);
128        m_attributes = attributes;
129
130        ASSERT(slotBase);
131        m_slotBase = slotBase;
132        m_propertyType = TypeValue;
133        m_offset = invalidOffset;
134    }
135
136    void setValue(JSObject* slotBase, unsigned attributes, JSValue value, PropertyOffset offset)
137    {
138        ASSERT(value);
139        m_data.value = JSValue::encode(value);
140        m_attributes = attributes;
141
142        ASSERT(slotBase);
143        m_slotBase = slotBase;
144        m_propertyType = TypeValue;
145        m_offset = offset;
146    }
147
148    void setValue(JSString*, unsigned attributes, JSValue value)
149    {
150        ASSERT(value);
151        m_data.value = JSValue::encode(value);
152        m_attributes = attributes;
153
154        m_slotBase = 0;
155        m_propertyType = TypeValue;
156        m_offset = invalidOffset;
157    }
158
159    void setCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
160    {
161        ASSERT(getValue);
162        m_data.custom.getValue = getValue;
163        m_attributes = attributes;
164
165        ASSERT(slotBase);
166        m_slotBase = slotBase;
167        m_propertyType = TypeCustom;
168        m_offset = invalidOffset;
169    }
170
171    void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
172    {
173        ASSERT(getValue);
174        m_data.custom.getValue = getValue;
175        m_attributes = attributes;
176
177        ASSERT(slotBase);
178        m_slotBase = slotBase;
179        m_propertyType = TypeCustom;
180        m_offset = !invalidOffset;
181    }
182
183    void setGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter)
184    {
185        ASSERT(getterSetter);
186        m_data.getter.getterSetter = getterSetter;
187        m_attributes = attributes;
188
189        ASSERT(slotBase);
190        m_slotBase = slotBase;
191        m_propertyType = TypeGetter;
192        m_offset = invalidOffset;
193    }
194
195    void setCacheableGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter, PropertyOffset offset)
196    {
197        ASSERT(getterSetter);
198        m_data.getter.getterSetter = getterSetter;
199        m_attributes = attributes;
200
201        ASSERT(slotBase);
202        m_slotBase = slotBase;
203        m_propertyType = TypeGetter;
204        m_offset = offset;
205    }
206
207    void setUndefined()
208    {
209        m_data.value = JSValue::encode(jsUndefined());
210        m_attributes = ReadOnly | DontDelete | DontEnum;
211
212        m_slotBase = 0;
213        m_propertyType = TypeValue;
214        m_offset = invalidOffset;
215    }
216
217    void setWatchpointSet(WatchpointSet& set)
218    {
219        m_watchpointSet = &set;
220    }
221
222private:
223    JS_EXPORT_PRIVATE JSValue functionGetter(ExecState*) const;
224
225    unsigned m_attributes;
226    union {
227        EncodedJSValue value;
228        struct {
229            GetterSetter* getterSetter;
230        } getter;
231        struct {
232            GetValueFunc getValue;
233        } custom;
234    } m_data;
235
236    PropertyType m_propertyType;
237    PropertyOffset m_offset;
238    const JSValue m_thisValue;
239    JSObject* m_slotBase;
240    WatchpointSet* m_watchpointSet;
241    CacheabilityType m_cacheability;
242};
243
244} // namespace JSC
245
246#endif // PropertySlot_h
247