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 "Intrinsic.h"
26 #include "Identifier.h"
27 #include "JSGlobalObject.h"
28 #include "PropertySlot.h"
30 #include <wtf/Assertions.h>
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
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
);
48 WTF_MAKE_FAST_ALLOCATED
;
50 void initialize(StringImpl
* key
, unsigned char attributes
, intptr_t v1
, intptr_t v2
, Intrinsic intrinsic
)
53 m_attributes
= attributes
;
54 m_u
.store
.value1
= v1
;
55 m_u
.store
.value2
= v2
;
56 m_intrinsic
= intrinsic
;
60 void setKey(StringImpl
* key
) { m_key
= key
; }
61 StringImpl
* key() const { return m_key
; }
63 unsigned char attributes() const { return m_attributes
; }
65 Intrinsic
intrinsic() const
67 ASSERT(m_attributes
& Function
);
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
); }
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
; }
77 intptr_t lexerValue() const { ASSERT(!m_attributes
); return m_u
.lexer
.value
; }
79 void setNext(HashEntry
*next
) { m_next
= next
; }
80 HashEntry
* next() const { return m_next
; }
84 unsigned char m_attributes
; // JSObject attributes
85 Intrinsic m_intrinsic
;
93 NativeFunction functionValue
;
94 intptr_t length
; // number of arguments for function
112 int compactHashSizeMask
;
114 const HashTableValue
* values
; // Fixed values generated by script.
115 mutable const HashEntry
* table
; // Table allocated at runtime.
117 ALWAYS_INLINE HashTable
copy() const
119 // Don't copy dynamic table since it's thread specific.
120 HashTable result
= { compactSize
, compactHashSizeMask
, values
, 0 };
124 ALWAYS_INLINE
void initializeIfNeeded(VM
* vm
) const
130 ALWAYS_INLINE
void initializeIfNeeded(ExecState
* exec
) const
133 createTable(&exec
->vm());
136 JS_EXPORT_PRIVATE
void deleteTable() const;
138 // Find an entry in the table, and return the entry.
139 ALWAYS_INLINE
const HashEntry
* entry(VM
* vm
, PropertyName identifier
) const
141 initializeIfNeeded(vm
);
142 return entry(identifier
);
145 ALWAYS_INLINE
const HashEntry
* entry(ExecState
* exec
, PropertyName identifier
) const
147 initializeIfNeeded(exec
);
148 return entry(identifier
);
151 class ConstIterator
{
153 ConstIterator(const HashTable
* table
, int position
)
155 , m_position(position
)
160 const HashEntry
* operator->()
162 return &m_table
->table
[m_position
];
165 const HashEntry
* operator*()
167 return &m_table
->table
[m_position
];
170 bool operator!=(const ConstIterator
& other
)
172 ASSERT(m_table
== other
.m_table
);
173 return m_position
!= other
.m_position
;
176 ConstIterator
& operator++()
178 ASSERT(m_position
< m_table
->compactSize
);
185 void skipInvalidKeys()
187 ASSERT(m_position
<= m_table
->compactSize
);
188 while (m_position
< m_table
->compactSize
&& !m_table
->table
[m_position
].key())
190 ASSERT(m_position
<= m_table
->compactSize
);
193 const HashTable
* m_table
;
197 ConstIterator
begin(VM
& vm
) const
199 initializeIfNeeded(&vm
);
200 return ConstIterator(this, 0);
202 ConstIterator
end(VM
& vm
) const
204 initializeIfNeeded(&vm
);
205 return ConstIterator(this, compactSize
);
209 ALWAYS_INLINE
const HashEntry
* entry(PropertyName propertyName
) const
211 StringImpl
* impl
= propertyName
.publicName();
217 const HashEntry
* entry
= &table
[impl
->existingHash() & compactHashSizeMask
];
223 if (entry
->key() == impl
)
225 entry
= entry
->next();
231 // Convert the hash table keys to identifiers.
232 JS_EXPORT_PRIVATE
void createTable(VM
*) const;
235 JS_EXPORT_PRIVATE
bool setUpStaticFunctionSlot(ExecState
*, const HashEntry
*, JSObject
* thisObject
, PropertyName
, PropertySlot
&);
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
243 template <class ThisImp
, class ParentImp
>
244 inline bool getStaticPropertySlot(ExecState
* exec
, const HashTable
* table
, ThisImp
* thisObj
, PropertyName propertyName
, PropertySlot
& slot
)
246 const HashEntry
* entry
= table
->entry(exec
, propertyName
);
248 if (!entry
) // not found, forward to parent
249 return ParentImp::getOwnPropertySlot(thisObj
, exec
, propertyName
, slot
);
251 if (entry
->attributes() & Function
)
252 return setUpStaticFunctionSlot(exec
, entry
, thisObj
, propertyName
, slot
);
254 slot
.setCacheableCustom(thisObj
, entry
->propertyGetter());
258 template <class ThisImp
, class ParentImp
>
259 inline bool getStaticPropertyDescriptor(ExecState
* exec
, const HashTable
* table
, ThisImp
* thisObj
, PropertyName propertyName
, PropertyDescriptor
& descriptor
)
261 const HashEntry
* entry
= table
->entry(exec
, propertyName
);
263 if (!entry
) // not found, forward to parent
264 return ParentImp::getOwnPropertyDescriptor(thisObj
, exec
, propertyName
, descriptor
);
267 if (entry
->attributes() & Function
) {
268 bool present
= setUpStaticFunctionSlot(exec
, entry
, thisObj
, propertyName
, slot
);
270 descriptor
.setDescriptor(slot
.getValue(exec
, propertyName
), entry
->attributes());
274 slot
.setCustom(thisObj
, entry
->propertyGetter());
275 descriptor
.setDescriptor(slot
.getValue(exec
, propertyName
), entry
->attributes());
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.
284 template <class ParentImp
>
285 inline bool getStaticFunctionSlot(ExecState
* exec
, const HashTable
* table
, JSObject
* thisObj
, PropertyName propertyName
, PropertySlot
& slot
)
287 if (ParentImp::getOwnPropertySlot(thisObj
, exec
, propertyName
, slot
))
290 const HashEntry
* entry
= table
->entry(exec
, propertyName
);
294 return setUpStaticFunctionSlot(exec
, entry
, thisObj
, propertyName
, slot
);
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.
302 template <class ParentImp
>
303 inline bool getStaticFunctionDescriptor(ExecState
* exec
, const HashTable
* table
, JSObject
* thisObj
, PropertyName propertyName
, PropertyDescriptor
& descriptor
)
305 if (ParentImp::getOwnPropertyDescriptor(static_cast<ParentImp
*>(thisObj
), exec
, propertyName
, descriptor
))
308 const HashEntry
* entry
= table
->entry(exec
, propertyName
);
313 bool present
= setUpStaticFunctionSlot(exec
, entry
, thisObj
, propertyName
, slot
);
315 descriptor
.setDescriptor(slot
.getValue(exec
, propertyName
), entry
->attributes());
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.
323 template <class ThisImp
, class ParentImp
>
324 inline bool getStaticValueSlot(ExecState
* exec
, const HashTable
* table
, ThisImp
* thisObj
, PropertyName propertyName
, PropertySlot
& slot
)
326 const HashEntry
* entry
= table
->entry(exec
, propertyName
);
328 if (!entry
) // not found, forward to parent
329 return ParentImp::getOwnPropertySlot(thisObj
, exec
, propertyName
, slot
);
331 ASSERT(!(entry
->attributes() & Function
));
333 slot
.setCacheableCustom(thisObj
, entry
->propertyGetter());
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.
341 template <class ThisImp
, class ParentImp
>
342 inline bool getStaticValueDescriptor(ExecState
* exec
, const HashTable
* table
, ThisImp
* thisObj
, PropertyName propertyName
, PropertyDescriptor
& descriptor
)
344 const HashEntry
* entry
= table
->entry(exec
, propertyName
);
346 if (!entry
) // not found, forward to parent
347 return ParentImp::getOwnPropertyDescriptor(thisObj
, exec
, propertyName
, descriptor
);
349 ASSERT(!(entry
->attributes() & Function
));
351 slot
.setCustom(thisObj
, entry
->propertyGetter());
352 descriptor
.setDescriptor(slot
.getValue(exec
, propertyName
), entry
->attributes());
356 template <class ThisImp
>
357 inline void putEntry(ExecState
* exec
, const HashEntry
* entry
, PropertyName propertyName
, JSValue value
, ThisImp
* thisObj
, bool shouldThrow
= false)
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
);
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.
373 template <class ThisImp
>
374 inline bool lookupPut(ExecState
* exec
, PropertyName propertyName
, JSValue value
, const HashTable
* table
, ThisImp
* thisObj
, bool shouldThrow
= false)
376 const HashEntry
* entry
= table
->entry(exec
, propertyName
);
381 putEntry
<ThisImp
>(exec
, entry
, propertyName
, value
, thisObj
, shouldThrow
);
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.
391 template <class ThisImp
, class ParentImp
>
392 inline void lookupPut(ExecState
* exec
, PropertyName propertyName
, JSValue value
, const HashTable
* table
, ThisImp
* thisObj
, PutPropertySlot
& slot
)
394 if (!lookupPut
<ThisImp
>(exec
, propertyName
, value
, table
, thisObj
, slot
.isStrictMode()))
395 ParentImp::put(thisObj
, exec
, propertyName
, value
, slot
); // not found: forward to parent