2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
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.
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.
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
24 #include "CallFrame.h"
25 #include "Identifier.h"
26 #include "JSGlobalObject.h"
27 #include "PropertySlot.h"
29 #include <wtf/Assertions.h>
31 // Bug #26843: Work around Metrowerks compiler bug
33 #define JSC_CONST_HASHTABLE
35 #define JSC_CONST_HASHTABLE const
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
46 ThunkGenerator generator;
50 // FIXME: There is no reason this get function can't be simpler.
51 // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
52 typedef PropertySlot::GetValueFunc GetFunction;
53 typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
56 WTF_MAKE_FAST_ALLOCATED;
58 void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2
60 , ThunkGenerator generator = 0
65 m_attributes = attributes;
66 m_u.store.value1 = v1;
67 m_u.store.value2 = v2;
69 m_u.function.generator = generator;
74 void setKey(StringImpl* key) { m_key = key; }
75 StringImpl* key() const { return m_key; }
77 unsigned char attributes() const { return m_attributes; }
80 ThunkGenerator generator() const { ASSERT(m_attributes & Function); return m_u.function.generator; }
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); }
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; }
88 intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
90 void setNext(HashEntry *next) { m_next = next; }
91 HashEntry* next() const { return m_next; }
95 unsigned char m_attributes; // JSObject attributes
103 NativeFunction functionValue;
104 intptr_t length; // number of arguments for function
106 ThunkGenerator generator;
125 int compactHashSizeMask;
127 const HashTableValue* values; // Fixed values generated by script.
128 mutable const HashEntry* table; // Table allocated at runtime.
130 ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
133 createTable(globalData);
136 ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
139 createTable(&exec->globalData());
142 void deleteTable() const;
144 // Find an entry in the table, and return the entry.
145 ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
147 initializeIfNeeded(globalData);
148 return entry(identifier);
151 ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
153 initializeIfNeeded(exec);
154 return entry(identifier);
158 ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
162 const HashEntry* entry = &table[identifier.impl()->existingHash() & compactHashSizeMask];
168 if (entry->key() == identifier.impl())
170 entry = entry->next();
176 // Convert the hash table keys to identifiers.
177 void createTable(JSGlobalData*) const;
180 void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
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
188 template <class ThisImp, class ParentImp>
189 inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
191 const HashEntry* entry = table->entry(exec, propertyName);
193 if (!entry) // not found, forward to parent
194 return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
196 if (entry->attributes() & Function)
197 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
199 slot.setCacheableCustom(thisObj, entry->propertyGetter());
204 template <class ThisImp, class ParentImp>
205 inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
207 const HashEntry* entry = table->entry(exec, propertyName);
209 if (!entry) // not found, forward to parent
210 return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
213 if (entry->attributes() & Function)
214 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
216 slot.setCustom(thisObj, entry->propertyGetter());
218 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
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.
227 template <class ParentImp>
228 inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
230 if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot))
233 const HashEntry* entry = table->entry(exec, propertyName);
237 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
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.
246 template <class ParentImp>
247 inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
249 if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor))
252 const HashEntry* entry = table->entry(exec, propertyName);
257 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
258 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
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.
266 template <class ThisImp, class ParentImp>
267 inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
269 const HashEntry* entry = table->entry(exec, propertyName);
271 if (!entry) // not found, forward to parent
272 return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
274 ASSERT(!(entry->attributes() & Function));
276 slot.setCacheableCustom(thisObj, entry->propertyGetter());
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.
284 template <class ThisImp, class ParentImp>
285 inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
287 const HashEntry* entry = table->entry(exec, propertyName);
289 if (!entry) // not found, forward to parent
290 return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
292 ASSERT(!(entry->attributes() & Function));
294 slot.setCustom(thisObj, entry->propertyGetter());
295 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
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.
304 template <class ThisImp>
305 inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj)
307 const HashEntry* entry = table->entry(exec, propertyName);
312 if (entry->attributes() & Function) { // function: put as override property
313 if (LIKELY(value.isCell()))
314 thisObj->putDirectFunction(exec->globalData(), propertyName, value.asCell());
316 thisObj->putDirect(exec->globalData(), propertyName, value);
317 } else if (!(entry->attributes() & ReadOnly))
318 entry->propertyPutter()(exec, thisObj, value);
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.
329 template <class ThisImp, class ParentImp>
330 inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
332 if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
333 thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent