#ifndef Lookup_h
#define Lookup_h
#include "CallFrame.h"
#include "Identifier.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSObject.h"
#include "PropertySlot.h"
#include <stdio.h>
#include <wtf/Assertions.h>
#define ENABLE_PERFECT_HASH_SIZE 1
namespace JSC {
struct HashTableValue {
const char* key; unsigned char attributes; intptr_t value1;
intptr_t value2;
};
typedef PropertySlot::GetValueFunc GetFunction;
typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValuePtr value);
class HashEntry {
public:
void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2)
{
m_key = key;
m_attributes = attributes;
m_u.store.value1 = v1;
m_u.store.value2 = v2;
#if !ENABLE(PERFECT_HASH_SIZE)
m_next = 0;
#endif
}
void setKey(UString::Rep* key) { m_key = key; }
UString::Rep* key() const { return m_key; }
unsigned char attributes() const { return m_attributes; }
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); }
GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
#if !ENABLE(PERFECT_HASH_SIZE)
void setNext(HashEntry *next) { m_next = next; }
HashEntry* next() const { return m_next; }
#endif
private:
UString::Rep* m_key;
unsigned char m_attributes;
union {
struct {
intptr_t value1;
intptr_t value2;
} store;
struct {
NativeFunction functionValue;
intptr_t length; } function;
struct {
GetFunction get;
PutFunction put;
} property;
struct {
intptr_t value;
intptr_t unused;
} lexer;
} m_u;
#if !ENABLE(PERFECT_HASH_SIZE)
HashEntry* m_next;
#endif
};
struct HashTable {
#if ENABLE(PERFECT_HASH_SIZE)
int hashSizeMask; #else
int compactSize;
int compactHashSizeMask;
#endif
const HashTableValue* values; mutable const HashEntry* table;
ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
{
if (!table)
createTable(globalData);
}
ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
{
if (!table)
createTable(&exec->globalData());
}
void deleteTable() const;
ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
{
initializeIfNeeded(globalData);
return entry(identifier);
}
ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
{
initializeIfNeeded(exec);
return entry(identifier);
}
private:
ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
{
#if ENABLE(PERFECT_HASH_SIZE)
ASSERT(table);
const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & hashSizeMask];
if (entry->key() != identifier.ustring().rep())
return 0;
return entry;
#else
ASSERT(table);
const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & compactHashSizeMask];
if (!entry->key())
return 0;
do {
if (entry->key() == identifier.ustring().rep())
return entry;
entry = entry->next();
} while (entry);
return 0;
#endif
}
void createTable(JSGlobalData*) const;
};
void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
template <class ThisImp, class ParentImp>
inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
{
const HashEntry* entry = table->entry(exec, propertyName);
if (!entry) return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
if (entry->attributes() & Function)
setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
else
slot.setCustom(thisObj, entry->propertyGetter());
return true;
}
template <class ParentImp>
inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
{
if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot))
return true;
const HashEntry* entry = table->entry(exec, propertyName);
if (!entry)
return false;
setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
return true;
}
template <class ThisImp, class ParentImp>
inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
{
const HashEntry* entry = table->entry(exec, propertyName);
if (!entry) return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
ASSERT(!(entry->attributes() & Function));
slot.setCustom(thisObj, entry->propertyGetter());
return true;
}
template <class ThisImp>
inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValuePtr value, const HashTable* table, ThisImp* thisObj)
{
const HashEntry* entry = table->entry(exec, propertyName);
if (!entry)
return false;
if (entry->attributes() & Function) thisObj->putDirect(propertyName, value);
else if (!(entry->attributes() & ReadOnly))
entry->propertyPutter()(exec, thisObj, value);
return true;
}
template <class ThisImp, class ParentImp>
inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValuePtr value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
{
if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
thisObj->ParentImp::put(exec, propertyName, value, slot); }
}
#endif // Lookup_h