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 
  41     // Hash table generated by the create_hash_table script. 
  42     struct HashTableValue 
{ 
  43         const char* key
; // property name 
  44         unsigned char attributes
; // JSObject attributes 
  49     // FIXME: There is no reason this get function can't be simpler. 
  50     // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject) 
  51     typedef PropertySlot::GetValueFunc GetFunction
; 
  52     typedef void (*PutFunction
)(ExecState
*, JSObject
* baseObject
, JSValue value
); 
  54     class HashEntry 
: public FastAllocBase 
{ 
  56         void initialize(UString::Rep
* key
, unsigned char attributes
, intptr_t v1
, intptr_t v2
) 
  59             m_attributes 
= attributes
; 
  60             m_u
.store
.value1 
= v1
; 
  61             m_u
.store
.value2 
= v2
; 
  65         void setKey(UString::Rep
* key
) { m_key 
= key
; } 
  66         UString::Rep
* key() const { return m_key
; } 
  68         unsigned char attributes() const { return m_attributes
; } 
  70         NativeFunction 
function() const { ASSERT(m_attributes 
& Function
); return m_u
.function
.functionValue
; } 
  71         unsigned char functionLength() const { ASSERT(m_attributes 
& Function
); return static_cast<unsigned char>(m_u
.function
.length
); } 
  73         GetFunction 
propertyGetter() const { ASSERT(!(m_attributes 
& Function
)); return m_u
.property
.get
; } 
  74         PutFunction 
propertyPutter() const { ASSERT(!(m_attributes 
& Function
)); return m_u
.property
.put
; } 
  76         intptr_t lexerValue() const { ASSERT(!m_attributes
); return m_u
.lexer
.value
; } 
  78         void setNext(HashEntry 
*next
) { m_next 
= next
; } 
  79         HashEntry
* next() const { return m_next
; } 
  83         unsigned char m_attributes
; // JSObject attributes 
  91                 NativeFunction functionValue
; 
  92                 intptr_t length
; // number of arguments for function 
 110         int compactHashSizeMask
; 
 112         const HashTableValue
* values
; // Fixed values generated by script. 
 113         mutable const HashEntry
* table
; // Table allocated at runtime. 
 115         ALWAYS_INLINE 
void initializeIfNeeded(JSGlobalData
* globalData
) const 
 118                 createTable(globalData
); 
 121         ALWAYS_INLINE 
void initializeIfNeeded(ExecState
* exec
) const 
 124                 createTable(&exec
->globalData()); 
 127         void deleteTable() const; 
 129         // Find an entry in the table, and return the entry. 
 130         ALWAYS_INLINE 
const HashEntry
* entry(JSGlobalData
* globalData
, const Identifier
& identifier
) const 
 132             initializeIfNeeded(globalData
); 
 133             return entry(identifier
); 
 136         ALWAYS_INLINE 
const HashEntry
* entry(ExecState
* exec
, const Identifier
& identifier
) const 
 138             initializeIfNeeded(exec
); 
 139             return entry(identifier
); 
 143         ALWAYS_INLINE 
const HashEntry
* entry(const Identifier
& identifier
) const 
 147             const HashEntry
* entry 
= &table
[identifier
.ustring().rep()->existingHash() & compactHashSizeMask
]; 
 153                 if (entry
->key() == identifier
.ustring().rep()) 
 155                 entry 
= entry
->next(); 
 161         // Convert the hash table keys to identifiers. 
 162         void createTable(JSGlobalData
*) const; 
 165     void setUpStaticFunctionSlot(ExecState
*, const HashEntry
*, JSObject
* thisObject
, const Identifier
& propertyName
, PropertySlot
&); 
 168      * This method does it all (looking in the hashtable, checking for function 
 169      * overrides, creating the function or retrieving from cache, calling 
 170      * getValueProperty in case of a non-function property, forwarding to parent if 
 173     template <class ThisImp
, class ParentImp
> 
 174     inline bool getStaticPropertySlot(ExecState
* exec
, const HashTable
* table
, ThisImp
* thisObj
, const Identifier
& propertyName
, PropertySlot
& slot
) 
 176         const HashEntry
* entry 
= table
->entry(exec
, propertyName
); 
 178         if (!entry
) // not found, forward to parent 
 179             return thisObj
->ParentImp::getOwnPropertySlot(exec
, propertyName
, slot
); 
 181         if (entry
->attributes() & Function
) 
 182             setUpStaticFunctionSlot(exec
, entry
, thisObj
, propertyName
, slot
); 
 184             slot
.setCustom(thisObj
, entry
->propertyGetter()); 
 189     template <class ThisImp
, class ParentImp
> 
 190     inline bool getStaticPropertyDescriptor(ExecState
* exec
, const HashTable
* table
, ThisImp
* thisObj
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
) 
 192         const HashEntry
* entry 
= table
->entry(exec
, propertyName
); 
 194         if (!entry
) // not found, forward to parent 
 195             return thisObj
->ParentImp::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
); 
 198         if (entry
->attributes() & Function
) 
 199             setUpStaticFunctionSlot(exec
, entry
, thisObj
, propertyName
, slot
); 
 201             slot
.setCustom(thisObj
, entry
->propertyGetter()); 
 203         descriptor
.setDescriptor(slot
.getValue(exec
, propertyName
), entry
->attributes()); 
 208      * Simplified version of getStaticPropertySlot in case there are only functions. 
 209      * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing 
 210      * a dummy getValueProperty. 
 212     template <class ParentImp
> 
 213     inline bool getStaticFunctionSlot(ExecState
* exec
, const HashTable
* table
, JSObject
* thisObj
, const Identifier
& propertyName
, PropertySlot
& slot
) 
 215         if (static_cast<ParentImp
*>(thisObj
)->ParentImp::getOwnPropertySlot(exec
, propertyName
, slot
)) 
 218         const HashEntry
* entry 
= table
->entry(exec
, propertyName
); 
 222         setUpStaticFunctionSlot(exec
, entry
, thisObj
, propertyName
, slot
); 
 227      * Simplified version of getStaticPropertyDescriptor in case there are only functions. 
 228      * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing 
 229      * a dummy getValueProperty. 
 231     template <class ParentImp
> 
 232     inline bool getStaticFunctionDescriptor(ExecState
* exec
, const HashTable
* table
, JSObject
* thisObj
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
) 
 234         if (static_cast<ParentImp
*>(thisObj
)->ParentImp::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
)) 
 237         const HashEntry
* entry 
= table
->entry(exec
, propertyName
); 
 242         setUpStaticFunctionSlot(exec
, entry
, thisObj
, propertyName
, slot
); 
 243         descriptor
.setDescriptor(slot
.getValue(exec
, propertyName
), entry
->attributes()); 
 248      * Simplified version of getStaticPropertySlot in case there are no functions, only "values". 
 249      * Using this instead of getStaticPropertySlot removes the need for a FuncImp class. 
 251     template <class ThisImp
, class ParentImp
> 
 252     inline bool getStaticValueSlot(ExecState
* exec
, const HashTable
* table
, ThisImp
* thisObj
, const Identifier
& propertyName
, PropertySlot
& slot
) 
 254         const HashEntry
* entry 
= table
->entry(exec
, propertyName
); 
 256         if (!entry
) // not found, forward to parent 
 257             return thisObj
->ParentImp::getOwnPropertySlot(exec
, propertyName
, slot
); 
 259         ASSERT(!(entry
->attributes() & Function
)); 
 261         slot
.setCustom(thisObj
, entry
->propertyGetter()); 
 266      * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values". 
 267      * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class. 
 269     template <class ThisImp
, class ParentImp
> 
 270     inline bool getStaticValueDescriptor(ExecState
* exec
, const HashTable
* table
, ThisImp
* thisObj
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
) 
 272         const HashEntry
* entry 
= table
->entry(exec
, propertyName
); 
 274         if (!entry
) // not found, forward to parent 
 275             return thisObj
->ParentImp::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
); 
 277         ASSERT(!(entry
->attributes() & Function
)); 
 279         slot
.setCustom(thisObj
, entry
->propertyGetter()); 
 280         descriptor
.setDescriptor(slot
.getValue(exec
, propertyName
), entry
->attributes()); 
 285      * This one is for "put". 
 286      * It looks up a hash entry for the property to be set.  If an entry 
 287      * is found it sets the value and returns true, else it returns false. 
 289     template <class ThisImp
> 
 290     inline bool lookupPut(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, const HashTable
* table
, ThisImp
* thisObj
) 
 292         const HashEntry
* entry 
= table
->entry(exec
, propertyName
); 
 297         if (entry
->attributes() & Function
) { // function: put as override property 
 298             if (LIKELY(value
.isCell())) 
 299                 thisObj
->putDirectFunction(propertyName
, value
.asCell()); 
 301                 thisObj
->putDirect(propertyName
, value
); 
 302         } else if (!(entry
->attributes() & ReadOnly
)) 
 303             entry
->propertyPutter()(exec
, thisObj
, value
); 
 309      * This one is for "put". 
 310      * It calls lookupPut<ThisImp>() to set the value.  If that call 
 311      * returns false (meaning no entry in the hash table was found), 
 312      * then it calls put() on the ParentImp class. 
 314     template <class ThisImp
, class ParentImp
> 
 315     inline void lookupPut(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, const HashTable
* table
, ThisImp
* thisObj
, PutPropertySlot
& slot
) 
 317         if (!lookupPut
<ThisImp
>(exec
, propertyName
, value
, table
, thisObj
)) 
 318             thisObj
->ParentImp::put(exec
, propertyName
, value
, slot
); // not found: forward to parent