]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/Lookup.h
JavaScriptCore-903.5.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 "JSGlobalObject.h"
27 #include "JSObject.h"
28 #include "PropertySlot.h"
29 #include <stdio.h>
30 #include <wtf/Assertions.h>
31
32 // Bug #26843: Work around Metrowerks compiler bug
33 #if COMPILER(WINSCW)
34 #define JSC_CONST_HASHTABLE
35 #else
36 #define JSC_CONST_HASHTABLE const
37 #endif
38
39 namespace JSC {
40 // Hash table generated by the create_hash_table script.
41 struct HashTableValue {
42 const char* key; // property name
43 unsigned char attributes; // JSObject attributes
44 intptr_t value1;
45 intptr_t value2;
46 #if ENABLE(JIT)
47 ThunkGenerator generator;
48 #endif
49 };
50
51 // FIXME: There is no reason this get function can't be simpler.
52 // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
53 typedef PropertySlot::GetValueFunc GetFunction;
54 typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
55
56 class HashEntry {
57 WTF_MAKE_FAST_ALLOCATED;
58 public:
59 void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2
60 #if ENABLE(JIT)
61 , ThunkGenerator generator = 0
62 #endif
63 )
64 {
65 m_key = key;
66 m_attributes = attributes;
67 m_u.store.value1 = v1;
68 m_u.store.value2 = v2;
69 #if ENABLE(JIT)
70 m_u.function.generator = generator;
71 #endif
72 m_next = 0;
73 }
74
75 void setKey(StringImpl* key) { m_key = key; }
76 StringImpl* key() const { return m_key; }
77
78 unsigned char attributes() const { return m_attributes; }
79
80 #if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
81 ThunkGenerator generator() const { ASSERT(m_attributes & Function); return m_u.function.generator; }
82 #endif
83 NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
84 unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
85
86 GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
87 PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
88
89 intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
90
91 void setNext(HashEntry *next) { m_next = next; }
92 HashEntry* next() const { return m_next; }
93
94 private:
95 StringImpl* m_key;
96 unsigned char m_attributes; // JSObject attributes
97
98 union {
99 struct {
100 intptr_t value1;
101 intptr_t value2;
102 } store;
103 struct {
104 NativeFunction functionValue;
105 intptr_t length; // number of arguments for function
106 #if ENABLE(JIT)
107 ThunkGenerator generator;
108 #endif
109 } function;
110 struct {
111 GetFunction get;
112 PutFunction put;
113 } property;
114 struct {
115 intptr_t value;
116 intptr_t unused;
117 } lexer;
118 } m_u;
119
120 HashEntry* m_next;
121 };
122
123 struct HashTable {
124
125 int compactSize;
126 int compactHashSizeMask;
127
128 const HashTableValue* values; // Fixed values generated by script.
129 mutable const HashEntry* table; // Table allocated at runtime.
130
131 ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
132 {
133 if (!table)
134 createTable(globalData);
135 }
136
137 ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
138 {
139 if (!table)
140 createTable(&exec->globalData());
141 }
142
143 void deleteTable() const;
144
145 // Find an entry in the table, and return the entry.
146 ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
147 {
148 initializeIfNeeded(globalData);
149 return entry(identifier);
150 }
151
152 ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
153 {
154 initializeIfNeeded(exec);
155 return entry(identifier);
156 }
157
158 private:
159 ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
160 {
161 ASSERT(table);
162
163 const HashEntry* entry = &table[identifier.impl()->existingHash() & compactHashSizeMask];
164
165 if (!entry->key())
166 return 0;
167
168 do {
169 if (entry->key() == identifier.impl())
170 return entry;
171 entry = entry->next();
172 } while (entry);
173
174 return 0;
175 }
176
177 // Convert the hash table keys to identifiers.
178 void createTable(JSGlobalData*) const;
179 };
180
181 void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
182
183 /**
184 * This method does it all (looking in the hashtable, checking for function
185 * overrides, creating the function or retrieving from cache, calling
186 * getValueProperty in case of a non-function property, forwarding to parent if
187 * unknown property).
188 */
189 template <class ThisImp, class ParentImp>
190 inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
191 {
192 const HashEntry* entry = table->entry(exec, propertyName);
193
194 if (!entry) // not found, forward to parent
195 return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
196
197 if (entry->attributes() & Function)
198 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
199 else
200 slot.setCacheableCustom(thisObj, entry->propertyGetter());
201
202 return true;
203 }
204
205 template <class ThisImp, class ParentImp>
206 inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
207 {
208 const HashEntry* entry = table->entry(exec, propertyName);
209
210 if (!entry) // not found, forward to parent
211 return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
212
213 PropertySlot slot;
214 if (entry->attributes() & Function)
215 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
216 else
217 slot.setCustom(thisObj, entry->propertyGetter());
218
219 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
220 return true;
221 }
222
223 /**
224 * Simplified version of getStaticPropertySlot in case there are only functions.
225 * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
226 * a dummy getValueProperty.
227 */
228 template <class ParentImp>
229 inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
230 {
231 if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot))
232 return true;
233
234 const HashEntry* entry = table->entry(exec, propertyName);
235 if (!entry)
236 return false;
237
238 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
239 return true;
240 }
241
242 /**
243 * Simplified version of getStaticPropertyDescriptor in case there are only functions.
244 * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing
245 * a dummy getValueProperty.
246 */
247 template <class ParentImp>
248 inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
249 {
250 if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor))
251 return true;
252
253 const HashEntry* entry = table->entry(exec, propertyName);
254 if (!entry)
255 return false;
256
257 PropertySlot slot;
258 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
259 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
260 return true;
261 }
262
263 /**
264 * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
265 * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
266 */
267 template <class ThisImp, class ParentImp>
268 inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
269 {
270 const HashEntry* entry = table->entry(exec, propertyName);
271
272 if (!entry) // not found, forward to parent
273 return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
274
275 ASSERT(!(entry->attributes() & Function));
276
277 slot.setCacheableCustom(thisObj, entry->propertyGetter());
278 return true;
279 }
280
281 /**
282 * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values".
283 * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class.
284 */
285 template <class ThisImp, class ParentImp>
286 inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
287 {
288 const HashEntry* entry = table->entry(exec, propertyName);
289
290 if (!entry) // not found, forward to parent
291 return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
292
293 ASSERT(!(entry->attributes() & Function));
294 PropertySlot slot;
295 slot.setCustom(thisObj, entry->propertyGetter());
296 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
297 return true;
298 }
299
300 /**
301 * This one is for "put".
302 * It looks up a hash entry for the property to be set. If an entry
303 * is found it sets the value and returns true, else it returns false.
304 */
305 template <class ThisImp>
306 inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj)
307 {
308 const HashEntry* entry = table->entry(exec, propertyName);
309
310 if (!entry)
311 return false;
312
313 if (entry->attributes() & Function) { // function: put as override property
314 if (LIKELY(value.isCell()))
315 thisObj->putDirectFunction(exec->globalData(), propertyName, value.asCell());
316 else
317 thisObj->putDirect(exec->globalData(), propertyName, value);
318 } else if (!(entry->attributes() & ReadOnly))
319 entry->propertyPutter()(exec, thisObj, value);
320
321 return true;
322 }
323
324 /**
325 * This one is for "put".
326 * It calls lookupPut<ThisImp>() to set the value. If that call
327 * returns false (meaning no entry in the hash table was found),
328 * then it calls put() on the ParentImp class.
329 */
330 template <class ThisImp, class ParentImp>
331 inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
332 {
333 if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
334 thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent
335 }
336
337 } // namespace JSC
338
339 #endif // Lookup_h