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