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"
28 #include "PropertySlot.h"
30 #include <wtf/Assertions.h>
32 // Bug #26843: Work around Metrowerks compiler bug
34 #define JSC_CONST_HASHTABLE
36 #define JSC_CONST_HASHTABLE const
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
47 ThunkGenerator generator
;
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
);
56 class HashEntry
: public FastAllocBase
{
58 void initialize(UString::Rep
* 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(UString::Rep
* key
) { m_key
= key
; }
75 UString::Rep
* 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
.ustring().rep()->existingHash() & compactHashSizeMask
];
168 if (entry
->key() == identifier
.ustring().rep())
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(propertyName
, value
.asCell());
316 thisObj
->putDirect(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