]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/Lookup.h
JavaScriptCore-525.tar.gz
[apple/javascriptcore.git] / runtime / Lookup.h
1 /*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #ifndef Lookup_h
22 #define Lookup_h
23
24 #include "CallFrame.h"
25 #include "Identifier.h"
26 #include "JSFunction.h"
27 #include "JSGlobalObject.h"
28 #include "JSObject.h"
29 #include "PropertySlot.h"
30 #include <stdio.h>
31 #include <wtf/Assertions.h>
32
33 // Set ENABLE_PERFECT_HASH_SIZE to 0 to save memory at the
34 // cost of speed. Test your platform as results may vary.
35 #define ENABLE_PERFECT_HASH_SIZE 1
36
37 namespace JSC {
38
39 // Hash table generated by the create_hash_table script.
40 struct HashTableValue {
41 const char* key; // property name
42 unsigned char attributes; // JSObject attributes
43 intptr_t value1;
44 intptr_t value2;
45 };
46
47 // FIXME: There is no reason this get function can't be simpler.
48 // ie. typedef JSValuePtr (*GetFunction)(ExecState*, JSObject* baseObject)
49 typedef PropertySlot::GetValueFunc GetFunction;
50 typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValuePtr value);
51
52 class HashEntry {
53 public:
54 void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2)
55 {
56 m_key = key;
57 m_attributes = attributes;
58 m_u.store.value1 = v1;
59 m_u.store.value2 = v2;
60 #if !ENABLE(PERFECT_HASH_SIZE)
61 m_next = 0;
62 #endif
63 }
64
65 void setKey(UString::Rep* key) { m_key = key; }
66 UString::Rep* key() const { return m_key; }
67
68 unsigned char attributes() const { return m_attributes; }
69
70 NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
71 unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
72
73 GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
74 PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
75
76 intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
77
78 #if !ENABLE(PERFECT_HASH_SIZE)
79 void setNext(HashEntry *next) { m_next = next; }
80 HashEntry* next() const { return m_next; }
81 #endif
82
83 private:
84 UString::Rep* m_key;
85 unsigned char m_attributes; // JSObject attributes
86
87 union {
88 struct {
89 intptr_t value1;
90 intptr_t value2;
91 } store;
92 struct {
93 NativeFunction functionValue;
94 intptr_t length; // number of arguments for function
95 } function;
96 struct {
97 GetFunction get;
98 PutFunction put;
99 } property;
100 struct {
101 intptr_t value;
102 intptr_t unused;
103 } lexer;
104 } m_u;
105
106 #if !ENABLE(PERFECT_HASH_SIZE)
107 HashEntry* m_next;
108 #endif
109 };
110
111 struct HashTable {
112 #if ENABLE(PERFECT_HASH_SIZE)
113 int hashSizeMask; // Precomputed size for the hash table (minus 1).
114 #else
115 int compactSize;
116 int compactHashSizeMask;
117 #endif
118 const HashTableValue* values; // Fixed values generated by script.
119 mutable const HashEntry* table; // Table allocated at runtime.
120
121 ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
122 {
123 if (!table)
124 createTable(globalData);
125 }
126
127 ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
128 {
129 if (!table)
130 createTable(&exec->globalData());
131 }
132
133 void deleteTable() const;
134
135 // Find an entry in the table, and return the entry.
136 ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
137 {
138 initializeIfNeeded(globalData);
139 return entry(identifier);
140 }
141
142 ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
143 {
144 initializeIfNeeded(exec);
145 return entry(identifier);
146 }
147
148 private:
149 ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
150 {
151 #if ENABLE(PERFECT_HASH_SIZE)
152 ASSERT(table);
153 const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & hashSizeMask];
154 if (entry->key() != identifier.ustring().rep())
155 return 0;
156 return entry;
157 #else
158 ASSERT(table);
159
160 const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & compactHashSizeMask];
161
162 if (!entry->key())
163 return 0;
164
165 do {
166 if (entry->key() == identifier.ustring().rep())
167 return entry;
168 entry = entry->next();
169 } while (entry);
170
171 return 0;
172 #endif
173 }
174
175 // Convert the hash table keys to identifiers.
176 void createTable(JSGlobalData*) const;
177 };
178
179 void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
180
181 /**
182 * This method does it all (looking in the hashtable, checking for function
183 * overrides, creating the function or retrieving from cache, calling
184 * getValueProperty in case of a non-function property, forwarding to parent if
185 * unknown property).
186 */
187 template <class ThisImp, class ParentImp>
188 inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
189 {
190 const HashEntry* entry = table->entry(exec, propertyName);
191
192 if (!entry) // not found, forward to parent
193 return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
194
195 if (entry->attributes() & Function)
196 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
197 else
198 slot.setCustom(thisObj, entry->propertyGetter());
199
200 return true;
201 }
202
203 /**
204 * Simplified version of getStaticPropertySlot in case there are only functions.
205 * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
206 * a dummy getValueProperty.
207 */
208 template <class ParentImp>
209 inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
210 {
211 if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot))
212 return true;
213
214 const HashEntry* entry = table->entry(exec, propertyName);
215 if (!entry)
216 return false;
217
218 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
219 return true;
220 }
221
222 /**
223 * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
224 * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
225 */
226 template <class ThisImp, class ParentImp>
227 inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
228 {
229 const HashEntry* entry = table->entry(exec, propertyName);
230
231 if (!entry) // not found, forward to parent
232 return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
233
234 ASSERT(!(entry->attributes() & Function));
235
236 slot.setCustom(thisObj, entry->propertyGetter());
237 return true;
238 }
239
240 /**
241 * This one is for "put".
242 * It looks up a hash entry for the property to be set. If an entry
243 * is found it sets the value and returns true, else it returns false.
244 */
245 template <class ThisImp>
246 inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValuePtr value, const HashTable* table, ThisImp* thisObj)
247 {
248 const HashEntry* entry = table->entry(exec, propertyName);
249
250 if (!entry)
251 return false;
252
253 if (entry->attributes() & Function) // function: put as override property
254 thisObj->putDirect(propertyName, value);
255 else if (!(entry->attributes() & ReadOnly))
256 entry->propertyPutter()(exec, thisObj, value);
257
258 return true;
259 }
260
261 /**
262 * This one is for "put".
263 * It calls lookupPut<ThisImp>() to set the value. If that call
264 * returns false (meaning no entry in the hash table was found),
265 * then it calls put() on the ParentImp class.
266 */
267 template <class ThisImp, class ParentImp>
268 inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValuePtr value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
269 {
270 if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
271 thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent
272 }
273
274 } // namespace JSC
275
276 #endif // Lookup_h