JavaScriptCore/runtime/Lookup.h
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
       
     3  *  Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
       
     4  *
       
     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.
       
     9  *
       
    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.
       
    14  *
       
    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
       
    18  *
       
    19  */
       
    20 
       
    21 #ifndef Lookup_h
       
    22 #define Lookup_h
       
    23 
       
    24 #include "CallFrame.h"
       
    25 #include "Identifier.h"
       
    26 #include "JSGlobalObject.h"
       
    27 #include "JSObject.h"
       
    28 #include "PropertySlot.h"
       
    29 #include <stdio.h>
       
    30 #include <wtf/Assertions.h>
       
    31 
       
    32 // Bug #26843: Work around Metrowerks compiler bug
       
    33 #if COMPILER(WINSCW)
       
    34 #define JSC_CONST_HASHTABLE
       
    35 #else
       
    36 #define JSC_CONST_HASHTABLE const
       
    37 #endif
       
    38 
       
    39 namespace JSC {
       
    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
       
    44         intptr_t value1;
       
    45         intptr_t value2;
       
    46 #if ENABLE(JIT)
       
    47         ThunkGenerator generator;
       
    48 #endif
       
    49     };
       
    50 
       
    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);
       
    55 
       
    56     class HashEntry : public FastAllocBase {
       
    57     public:
       
    58         void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2
       
    59 #if ENABLE(JIT)
       
    60                         , ThunkGenerator generator = 0
       
    61 #endif
       
    62                         )
       
    63         {
       
    64             m_key = key;
       
    65             m_attributes = attributes;
       
    66             m_u.store.value1 = v1;
       
    67             m_u.store.value2 = v2;
       
    68 #if ENABLE(JIT)
       
    69             m_u.function.generator = generator;
       
    70 #endif
       
    71             m_next = 0;
       
    72         }
       
    73 
       
    74         void setKey(UString::Rep* key) { m_key = key; }
       
    75         UString::Rep* key() const { return m_key; }
       
    76 
       
    77         unsigned char attributes() const { return m_attributes; }
       
    78 
       
    79 #if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
       
    80         ThunkGenerator generator() const { ASSERT(m_attributes & Function); return m_u.function.generator; }
       
    81 #endif
       
    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); }
       
    84 
       
    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; }
       
    87 
       
    88         intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
       
    89 
       
    90         void setNext(HashEntry *next) { m_next = next; }
       
    91         HashEntry* next() const { return m_next; }
       
    92 
       
    93     private:
       
    94         UString::Rep* m_key;
       
    95         unsigned char m_attributes; // JSObject attributes
       
    96 
       
    97         union {
       
    98             struct {
       
    99                 intptr_t value1;
       
   100                 intptr_t value2;
       
   101             } store;
       
   102             struct {
       
   103                 NativeFunction functionValue;
       
   104                 intptr_t length; // number of arguments for function
       
   105 #if ENABLE(JIT)
       
   106                 ThunkGenerator generator;
       
   107 #endif
       
   108             } function;
       
   109             struct {
       
   110                 GetFunction get;
       
   111                 PutFunction put;
       
   112             } property;
       
   113             struct {
       
   114                 intptr_t value;
       
   115                 intptr_t unused;
       
   116             } lexer;
       
   117         } m_u;
       
   118 
       
   119         HashEntry* m_next;
       
   120     };
       
   121 
       
   122     struct HashTable {
       
   123 
       
   124         int compactSize;
       
   125         int compactHashSizeMask;
       
   126 
       
   127         const HashTableValue* values; // Fixed values generated by script.
       
   128         mutable const HashEntry* table; // Table allocated at runtime.
       
   129 
       
   130         ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
       
   131         {
       
   132             if (!table)
       
   133                 createTable(globalData);
       
   134         }
       
   135 
       
   136         ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
       
   137         {
       
   138             if (!table)
       
   139                 createTable(&exec->globalData());
       
   140         }
       
   141 
       
   142         void deleteTable() const;
       
   143 
       
   144         // Find an entry in the table, and return the entry.
       
   145         ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
       
   146         {
       
   147             initializeIfNeeded(globalData);
       
   148             return entry(identifier);
       
   149         }
       
   150 
       
   151         ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
       
   152         {
       
   153             initializeIfNeeded(exec);
       
   154             return entry(identifier);
       
   155         }
       
   156 
       
   157     private:
       
   158         ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
       
   159         {
       
   160             ASSERT(table);
       
   161 
       
   162             const HashEntry* entry = &table[identifier.ustring().rep()->existingHash() & compactHashSizeMask];
       
   163 
       
   164             if (!entry->key())
       
   165                 return 0;
       
   166 
       
   167             do {
       
   168                 if (entry->key() == identifier.ustring().rep())
       
   169                     return entry;
       
   170                 entry = entry->next();
       
   171             } while (entry);
       
   172 
       
   173             return 0;
       
   174         }
       
   175 
       
   176         // Convert the hash table keys to identifiers.
       
   177         void createTable(JSGlobalData*) const;
       
   178     };
       
   179 
       
   180     void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
       
   181 
       
   182     /**
       
   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
       
   186      * unknown property).
       
   187      */
       
   188     template <class ThisImp, class ParentImp>
       
   189     inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
       
   190     {
       
   191         const HashEntry* entry = table->entry(exec, propertyName);
       
   192 
       
   193         if (!entry) // not found, forward to parent
       
   194             return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
       
   195 
       
   196         if (entry->attributes() & Function)
       
   197             setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
       
   198         else
       
   199             slot.setCacheableCustom(thisObj, entry->propertyGetter());
       
   200 
       
   201         return true;
       
   202     }
       
   203 
       
   204     template <class ThisImp, class ParentImp>
       
   205     inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
       
   206     {
       
   207         const HashEntry* entry = table->entry(exec, propertyName);
       
   208         
       
   209         if (!entry) // not found, forward to parent
       
   210             return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
       
   211  
       
   212         PropertySlot slot;
       
   213         if (entry->attributes() & Function)
       
   214             setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
       
   215         else
       
   216             slot.setCustom(thisObj, entry->propertyGetter());
       
   217 
       
   218         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
       
   219         return true;
       
   220     }
       
   221 
       
   222     /**
       
   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.
       
   226      */
       
   227     template <class ParentImp>
       
   228     inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
       
   229     {
       
   230         if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot))
       
   231             return true;
       
   232 
       
   233         const HashEntry* entry = table->entry(exec, propertyName);
       
   234         if (!entry)
       
   235             return false;
       
   236 
       
   237         setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
       
   238         return true;
       
   239     }
       
   240     
       
   241     /**
       
   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.
       
   245      */
       
   246     template <class ParentImp>
       
   247     inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
       
   248     {
       
   249         if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor))
       
   250             return true;
       
   251         
       
   252         const HashEntry* entry = table->entry(exec, propertyName);
       
   253         if (!entry)
       
   254             return false;
       
   255         
       
   256         PropertySlot slot;
       
   257         setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
       
   258         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
       
   259         return true;
       
   260     }
       
   261 
       
   262     /**
       
   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.
       
   265      */
       
   266     template <class ThisImp, class ParentImp>
       
   267     inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
       
   268     {
       
   269         const HashEntry* entry = table->entry(exec, propertyName);
       
   270 
       
   271         if (!entry) // not found, forward to parent
       
   272             return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
       
   273 
       
   274         ASSERT(!(entry->attributes() & Function));
       
   275 
       
   276         slot.setCacheableCustom(thisObj, entry->propertyGetter());
       
   277         return true;
       
   278     }
       
   279 
       
   280     /**
       
   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.
       
   283      */
       
   284     template <class ThisImp, class ParentImp>
       
   285     inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
       
   286     {
       
   287         const HashEntry* entry = table->entry(exec, propertyName);
       
   288         
       
   289         if (!entry) // not found, forward to parent
       
   290             return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
       
   291         
       
   292         ASSERT(!(entry->attributes() & Function));
       
   293         PropertySlot slot;
       
   294         slot.setCustom(thisObj, entry->propertyGetter());
       
   295         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
       
   296         return true;
       
   297     }
       
   298 
       
   299     /**
       
   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.
       
   303      */
       
   304     template <class ThisImp>
       
   305     inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj)
       
   306     {
       
   307         const HashEntry* entry = table->entry(exec, propertyName);
       
   308 
       
   309         if (!entry)
       
   310             return false;
       
   311 
       
   312         if (entry->attributes() & Function) { // function: put as override property
       
   313             if (LIKELY(value.isCell()))
       
   314                 thisObj->putDirectFunction(propertyName, value.asCell());
       
   315             else
       
   316                 thisObj->putDirect(propertyName, value);
       
   317         } else if (!(entry->attributes() & ReadOnly))
       
   318             entry->propertyPutter()(exec, thisObj, value);
       
   319 
       
   320         return true;
       
   321     }
       
   322 
       
   323     /**
       
   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.
       
   328      */
       
   329     template <class ThisImp, class ParentImp>
       
   330     inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
       
   331     {
       
   332         if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
       
   333             thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent
       
   334     }
       
   335 
       
   336 } // namespace JSC
       
   337 
       
   338 #endif // Lookup_h