]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - runtime/Lookup.h
JavaScriptCore-1218.33.tar.gz
[apple/javascriptcore.git] / runtime / Lookup.h
... / ...
CommitLineData
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
32namespace 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_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_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 Intrinsic m_intrinsic;
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 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 HashTable copy() const
118 {
119 // Don't copy dynamic table since it's thread specific.
120 HashTable result = { compactSize, compactHashSizeMask, values, 0 };
121 return result;
122 }
123
124 ALWAYS_INLINE void initializeIfNeeded(VM* vm) const
125 {
126 if (!table)
127 createTable(vm);
128 }
129
130 ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
131 {
132 if (!table)
133 createTable(&exec->vm());
134 }
135
136 JS_EXPORT_PRIVATE void deleteTable() const;
137
138 // Find an entry in the table, and return the entry.
139 ALWAYS_INLINE const HashEntry* entry(VM* vm, PropertyName identifier) const
140 {
141 initializeIfNeeded(vm);
142 return entry(identifier);
143 }
144
145 ALWAYS_INLINE const HashEntry* entry(ExecState* exec, PropertyName identifier) const
146 {
147 initializeIfNeeded(exec);
148 return entry(identifier);
149 }
150
151 class ConstIterator {
152 public:
153 ConstIterator(const HashTable* table, int position)
154 : m_table(table)
155 , m_position(position)
156 {
157 skipInvalidKeys();
158 }
159
160 const HashEntry* operator->()
161 {
162 return &m_table->table[m_position];
163 }
164
165 const HashEntry* operator*()
166 {
167 return &m_table->table[m_position];
168 }
169
170 bool operator!=(const ConstIterator& other)
171 {
172 ASSERT(m_table == other.m_table);
173 return m_position != other.m_position;
174 }
175
176 ConstIterator& operator++()
177 {
178 ASSERT(m_position < m_table->compactSize);
179 ++m_position;
180 skipInvalidKeys();
181 return *this;
182 }
183
184 private:
185 void skipInvalidKeys()
186 {
187 ASSERT(m_position <= m_table->compactSize);
188 while (m_position < m_table->compactSize && !m_table->table[m_position].key())
189 ++m_position;
190 ASSERT(m_position <= m_table->compactSize);
191 }
192
193 const HashTable* m_table;
194 int m_position;
195 };
196
197 ConstIterator begin(VM& vm) const
198 {
199 initializeIfNeeded(&vm);
200 return ConstIterator(this, 0);
201 }
202 ConstIterator end(VM& vm) const
203 {
204 initializeIfNeeded(&vm);
205 return ConstIterator(this, compactSize);
206 }
207
208 private:
209 ALWAYS_INLINE const HashEntry* entry(PropertyName propertyName) const
210 {
211 StringImpl* impl = propertyName.publicName();
212 if (!impl)
213 return 0;
214
215 ASSERT(table);
216
217 const HashEntry* entry = &table[impl->existingHash() & compactHashSizeMask];
218
219 if (!entry->key())
220 return 0;
221
222 do {
223 if (entry->key() == impl)
224 return entry;
225 entry = entry->next();
226 } while (entry);
227
228 return 0;
229 }
230
231 // Convert the hash table keys to identifiers.
232 JS_EXPORT_PRIVATE void createTable(VM*) const;
233 };
234
235 JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, PropertyName, PropertySlot&);
236
237 /**
238 * This method does it all (looking in the hashtable, checking for function
239 * overrides, creating the function or retrieving from cache, calling
240 * getValueProperty in case of a non-function property, forwarding to parent if
241 * unknown property).
242 */
243 template <class ThisImp, class ParentImp>
244 inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
245 {
246 const HashEntry* entry = table->entry(exec, propertyName);
247
248 if (!entry) // not found, forward to parent
249 return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
250
251 if (entry->attributes() & Function)
252 return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
253
254 slot.setCacheableCustom(thisObj, entry->propertyGetter());
255 return true;
256 }
257
258 template <class ThisImp, class ParentImp>
259 inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
260 {
261 const HashEntry* entry = table->entry(exec, propertyName);
262
263 if (!entry) // not found, forward to parent
264 return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
265
266 PropertySlot slot;
267 if (entry->attributes() & Function) {
268 bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
269 if (present)
270 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
271 return present;
272 }
273
274 slot.setCustom(thisObj, entry->propertyGetter());
275 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
276 return true;
277 }
278
279 /**
280 * Simplified version of getStaticPropertySlot in case there are only functions.
281 * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
282 * a dummy getValueProperty.
283 */
284 template <class ParentImp>
285 inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
286 {
287 if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
288 return true;
289
290 const HashEntry* entry = table->entry(exec, propertyName);
291 if (!entry)
292 return false;
293
294 return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
295 }
296
297 /**
298 * Simplified version of getStaticPropertyDescriptor in case there are only functions.
299 * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing
300 * a dummy getValueProperty.
301 */
302 template <class ParentImp>
303 inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
304 {
305 if (ParentImp::getOwnPropertyDescriptor(static_cast<ParentImp*>(thisObj), exec, propertyName, descriptor))
306 return true;
307
308 const HashEntry* entry = table->entry(exec, propertyName);
309 if (!entry)
310 return false;
311
312 PropertySlot slot;
313 bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
314 if (present)
315 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
316 return present;
317 }
318
319 /**
320 * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
321 * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
322 */
323 template <class ThisImp, class ParentImp>
324 inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
325 {
326 const HashEntry* entry = table->entry(exec, propertyName);
327
328 if (!entry) // not found, forward to parent
329 return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
330
331 ASSERT(!(entry->attributes() & Function));
332
333 slot.setCacheableCustom(thisObj, entry->propertyGetter());
334 return true;
335 }
336
337 /**
338 * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values".
339 * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class.
340 */
341 template <class ThisImp, class ParentImp>
342 inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
343 {
344 const HashEntry* entry = table->entry(exec, propertyName);
345
346 if (!entry) // not found, forward to parent
347 return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
348
349 ASSERT(!(entry->attributes() & Function));
350 PropertySlot slot;
351 slot.setCustom(thisObj, entry->propertyGetter());
352 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
353 return true;
354 }
355
356 template <class ThisImp>
357 inline void putEntry(ExecState* exec, const HashEntry* entry, PropertyName propertyName, JSValue value, ThisImp* thisObj, bool shouldThrow = false)
358 {
359 // If this is a function put it as an override property.
360 if (entry->attributes() & Function)
361 thisObj->putDirect(exec->vm(), propertyName, value);
362 else if (!(entry->attributes() & ReadOnly))
363 entry->propertyPutter()(exec, thisObj, value);
364 else if (shouldThrow)
365 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
366 }
367
368 /**
369 * This one is for "put".
370 * It looks up a hash entry for the property to be set. If an entry
371 * is found it sets the value and returns true, else it returns false.
372 */
373 template <class ThisImp>
374 inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, bool shouldThrow = false)
375 {
376 const HashEntry* entry = table->entry(exec, propertyName);
377
378 if (!entry)
379 return false;
380
381 putEntry<ThisImp>(exec, entry, propertyName, value, thisObj, shouldThrow);
382 return true;
383 }
384
385 /**
386 * This one is for "put".
387 * It calls lookupPut<ThisImp>() to set the value. If that call
388 * returns false (meaning no entry in the hash table was found),
389 * then it calls put() on the ParentImp class.
390 */
391 template <class ThisImp, class ParentImp>
392 inline void lookupPut(ExecState* exec, PropertyName propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
393 {
394 if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj, slot.isStrictMode()))
395 ParentImp::put(thisObj, exec, propertyName, value, slot); // not found: forward to parent
396 }
397
398} // namespace JSC
399
400#endif // Lookup_h