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