#define Lookup_h
#include "CallFrame.h"
+#include "Intrinsic.h"
#include "Identifier.h"
#include "JSGlobalObject.h"
-#include "JSObject.h"
#include "PropertySlot.h"
#include <stdio.h>
#include <wtf/Assertions.h>
-// Bug #26843: Work around Metrowerks compiler bug
-#if COMPILER(WINSCW)
-#define JSC_CONST_HASHTABLE
-#else
-#define JSC_CONST_HASHTABLE const
-#endif
-
namespace JSC {
-
// Hash table generated by the create_hash_table script.
struct HashTableValue {
const char* key; // property name
unsigned char attributes; // JSObject attributes
intptr_t value1;
intptr_t value2;
+ Intrinsic intrinsic;
};
// FIXME: There is no reason this get function can't be simpler.
typedef PropertySlot::GetValueFunc GetFunction;
typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
- class HashEntry : public FastAllocBase {
+ class HashEntry {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2)
+ void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2, Intrinsic intrinsic)
{
m_key = key;
m_attributes = attributes;
m_u.store.value1 = v1;
m_u.store.value2 = v2;
+ m_intrinsic = intrinsic;
m_next = 0;
}
- void setKey(UString::Rep* key) { m_key = key; }
- UString::Rep* key() const { return m_key; }
+ void setKey(StringImpl* key) { m_key = key; }
+ StringImpl* key() const { return m_key; }
unsigned char attributes() const { return m_attributes; }
+ Intrinsic intrinsic() const
+ {
+ ASSERT(m_attributes & Function);
+ return m_intrinsic;
+ }
+
NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
HashEntry* next() const { return m_next; }
private:
- UString::Rep* m_key;
+ StringImpl* m_key;
unsigned char m_attributes; // JSObject attributes
+ Intrinsic m_intrinsic;
union {
struct {
const HashTableValue* values; // Fixed values generated by script.
mutable const HashEntry* table; // Table allocated at runtime.
- ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
+ ALWAYS_INLINE HashTable copy() const
+ {
+ // Don't copy dynamic table since it's thread specific.
+ HashTable result = { compactSize, compactHashSizeMask, values, 0 };
+ return result;
+ }
+
+ ALWAYS_INLINE void initializeIfNeeded(VM* vm) const
{
if (!table)
- createTable(globalData);
+ createTable(vm);
}
ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
{
if (!table)
- createTable(&exec->globalData());
+ createTable(&exec->vm());
}
- void deleteTable() const;
+ JS_EXPORT_PRIVATE void deleteTable() const;
// Find an entry in the table, and return the entry.
- ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
+ ALWAYS_INLINE const HashEntry* entry(VM* vm, PropertyName identifier) const
{
- initializeIfNeeded(globalData);
+ initializeIfNeeded(vm);
return entry(identifier);
}
- ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
+ ALWAYS_INLINE const HashEntry* entry(ExecState* exec, PropertyName identifier) const
{
initializeIfNeeded(exec);
return entry(identifier);
}
+ class ConstIterator {
+ public:
+ ConstIterator(const HashTable* table, int position)
+ : m_table(table)
+ , m_position(position)
+ {
+ skipInvalidKeys();
+ }
+
+ const HashEntry* operator->()
+ {
+ return &m_table->table[m_position];
+ }
+
+ const HashEntry* operator*()
+ {
+ return &m_table->table[m_position];
+ }
+
+ bool operator!=(const ConstIterator& other)
+ {
+ ASSERT(m_table == other.m_table);
+ return m_position != other.m_position;
+ }
+
+ ConstIterator& operator++()
+ {
+ ASSERT(m_position < m_table->compactSize);
+ ++m_position;
+ skipInvalidKeys();
+ return *this;
+ }
+
+ private:
+ void skipInvalidKeys()
+ {
+ ASSERT(m_position <= m_table->compactSize);
+ while (m_position < m_table->compactSize && !m_table->table[m_position].key())
+ ++m_position;
+ ASSERT(m_position <= m_table->compactSize);
+ }
+
+ const HashTable* m_table;
+ int m_position;
+ };
+
+ ConstIterator begin(VM& vm) const
+ {
+ initializeIfNeeded(&vm);
+ return ConstIterator(this, 0);
+ }
+ ConstIterator end(VM& vm) const
+ {
+ initializeIfNeeded(&vm);
+ return ConstIterator(this, compactSize);
+ }
+
private:
- ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
+ ALWAYS_INLINE const HashEntry* entry(PropertyName propertyName) const
{
+ StringImpl* impl = propertyName.publicName();
+ if (!impl)
+ return 0;
+
ASSERT(table);
- const HashEntry* entry = &table[identifier.ustring().rep()->existingHash() & compactHashSizeMask];
+ const HashEntry* entry = &table[impl->existingHash() & compactHashSizeMask];
if (!entry->key())
return 0;
do {
- if (entry->key() == identifier.ustring().rep())
+ if (entry->key() == impl)
return entry;
entry = entry->next();
} while (entry);
}
// Convert the hash table keys to identifiers.
- void createTable(JSGlobalData*) const;
+ JS_EXPORT_PRIVATE void createTable(VM*) const;
};
- void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
+ JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, PropertyName, PropertySlot&);
/**
* This method does it all (looking in the hashtable, checking for function
* unknown property).
*/
template <class ThisImp, class ParentImp>
- inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
{
const HashEntry* entry = table->entry(exec, propertyName);
if (!entry) // not found, forward to parent
- return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
+ return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
if (entry->attributes() & Function)
- setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
- else
- slot.setCustom(thisObj, entry->propertyGetter());
+ return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+ slot.setCacheableCustom(thisObj, entry->propertyGetter());
return true;
}
template <class ThisImp, class ParentImp>
- inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
+ inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
{
const HashEntry* entry = table->entry(exec, propertyName);
if (!entry) // not found, forward to parent
- return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+ return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
PropertySlot slot;
- if (entry->attributes() & Function)
- setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
- else
- slot.setCustom(thisObj, entry->propertyGetter());
+ if (entry->attributes() & Function) {
+ bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+ if (present)
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
+ return present;
+ }
+ slot.setCustom(thisObj, entry->propertyGetter());
descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
return true;
}
* a dummy getValueProperty.
*/
template <class ParentImp>
- inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
{
- if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot))
+ if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
return true;
const HashEntry* entry = table->entry(exec, propertyName);
if (!entry)
return false;
- setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
- return true;
+ return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
}
/**
* a dummy getValueProperty.
*/
template <class ParentImp>
- inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
+ inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
{
- if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor))
+ if (ParentImp::getOwnPropertyDescriptor(static_cast<ParentImp*>(thisObj), exec, propertyName, descriptor))
return true;
const HashEntry* entry = table->entry(exec, propertyName);
return false;
PropertySlot slot;
- setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
- descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
- return true;
+ bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+ if (present)
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
+ return present;
}
/**
* Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
*/
template <class ThisImp, class ParentImp>
- inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
{
const HashEntry* entry = table->entry(exec, propertyName);
if (!entry) // not found, forward to parent
- return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
+ return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
ASSERT(!(entry->attributes() & Function));
- slot.setCustom(thisObj, entry->propertyGetter());
+ slot.setCacheableCustom(thisObj, entry->propertyGetter());
return true;
}
* Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class.
*/
template <class ThisImp, class ParentImp>
- inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
+ inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
{
const HashEntry* entry = table->entry(exec, propertyName);
if (!entry) // not found, forward to parent
- return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+ return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
ASSERT(!(entry->attributes() & Function));
PropertySlot slot;
return true;
}
+ template <class ThisImp>
+ inline void putEntry(ExecState* exec, const HashEntry* entry, PropertyName propertyName, JSValue value, ThisImp* thisObj, bool shouldThrow = false)
+ {
+ // If this is a function put it as an override property.
+ if (entry->attributes() & Function)
+ thisObj->putDirect(exec->vm(), propertyName, value);
+ else if (!(entry->attributes() & ReadOnly))
+ entry->propertyPutter()(exec, thisObj, value);
+ else if (shouldThrow)
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ }
+
/**
* This one is for "put".
* It looks up a hash entry for the property to be set. If an entry
* is found it sets the value and returns true, else it returns false.
*/
template <class ThisImp>
- inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj)
+ inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, bool shouldThrow = false)
{
const HashEntry* entry = table->entry(exec, propertyName);
-
+
if (!entry)
return false;
- if (entry->attributes() & Function) { // function: put as override property
- if (LIKELY(value.isCell()))
- thisObj->putDirectFunction(propertyName, value.asCell());
- else
- thisObj->putDirect(propertyName, value);
- } else if (!(entry->attributes() & ReadOnly))
- entry->propertyPutter()(exec, thisObj, value);
-
+ putEntry<ThisImp>(exec, entry, propertyName, value, thisObj, shouldThrow);
return true;
}
* then it calls put() on the ParentImp class.
*/
template <class ThisImp, class ParentImp>
- inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
+ inline void lookupPut(ExecState* exec, PropertyName propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
{
- if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
- thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent
+ if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj, slot.isStrictMode()))
+ ParentImp::put(thisObj, exec, propertyName, value, slot); // not found: forward to parent
}
} // namespace JSC