]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Lookup.h
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / runtime / Lookup.h
index 55c3221b0f498f9d9f187f105895cb0a86a51d2c..c90ceae7c32881a8bb55ab54631d6d7e5c9658c8 100644 (file)
 #define Lookup_h
 
 #include "CallFrame.h"
+#include "Intrinsic.h"
 #include "Identifier.h"
-#include "JSFunction.h"
 #include "JSGlobalObject.h"
-#include "JSObject.h"
 #include "PropertySlot.h"
 #include <stdio.h>
 #include <wtf/Assertions.h>
 
-// Set ENABLE_PERFECT_HASH_SIZE to 0 to save memory at the
-// cost of speed.  Test your platform as results may vary.
-#define ENABLE_PERFECT_HASH_SIZE 1
-
 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.
-    // ie. typedef JSValuePtr (*GetFunction)(ExecState*, JSObject* baseObject)
+    // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
     typedef PropertySlot::GetValueFunc GetFunction;
-    typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValuePtr value);
+    typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
 
     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;
-#if !ENABLE(PERFECT_HASH_SIZE)
+            m_intrinsic = intrinsic;
             m_next = 0;
-#endif
         }
 
-        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); }
 
@@ -75,14 +76,13 @@ namespace JSC {
 
         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;
+        StringImpl* m_key;
         unsigned char m_attributes; // JSObject attributes
+        Intrinsic m_intrinsic;
 
         union {
             struct {
@@ -103,80 +103,136 @@ namespace JSC {
             } lexer;
         } m_u;
 
-#if !ENABLE(PERFECT_HASH_SIZE)
         HashEntry* m_next;
-#endif
     };
 
     struct HashTable {
-#if ENABLE(PERFECT_HASH_SIZE)
-        int hashSizeMask; // Precomputed size for the hash table (minus 1).
-#else
+
         int compactSize;
         int compactHashSizeMask;
-#endif
+
         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
         {
-#if ENABLE(PERFECT_HASH_SIZE)
-            ASSERT(table);
-            const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & hashSizeMask];
-            if (entry->key() != identifier.ustring().rep())
+            StringImpl* impl = propertyName.publicName();
+            if (!impl)
                 return 0;
-            return entry;
-#else
+        
             ASSERT(table);
 
-            const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & 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);
 
             return 0;
-#endif
         }
 
         // 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
@@ -185,18 +241,38 @@ namespace JSC {
      * 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, PropertyName propertyName, PropertyDescriptor& descriptor)
+    {
+        const HashEntry* entry = table->entry(exec, propertyName);
+        
+        if (!entry) // not found, forward to parent
+            return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
+        PropertySlot slot;
+        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;
     }
 
@@ -206,17 +282,38 @@ namespace JSC {
      * 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);
+    }
+    
+    /**
+     * Simplified version of getStaticPropertyDescriptor in case there are only functions.
+     * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing
+     * a dummy getValueProperty.
+     */
+    template <class ParentImp>
+    inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
+    {
+        if (ParentImp::getOwnPropertyDescriptor(static_cast<ParentImp*>(thisObj), exec, propertyName, descriptor))
+            return true;
+        
+        const HashEntry* entry = table->entry(exec, propertyName);
+        if (!entry)
+            return false;
+        
+        PropertySlot slot;
+        bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+        if (present)
+            descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
+        return present;
     }
 
     /**
@@ -224,37 +321,64 @@ namespace JSC {
      * 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.setCacheableCustom(thisObj, entry->propertyGetter());
+        return true;
+    }
+
+    /**
+     * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values".
+     * 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, PropertyName propertyName, PropertyDescriptor& descriptor)
+    {
+        const HashEntry* entry = table->entry(exec, propertyName);
+        
+        if (!entry) // not found, forward to parent
+            return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
+        
+        ASSERT(!(entry->attributes() & Function));
+        PropertySlot slot;
         slot.setCustom(thisObj, entry->propertyGetter());
+        descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
         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, JSValuePtr 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
-            thisObj->putDirect(propertyName, value);
-        else if (!(entry->attributes() & ReadOnly))
-            entry->propertyPutter()(exec, thisObj, value);
-
+        putEntry<ThisImp>(exec, entry, propertyName, value, thisObj, shouldThrow);
         return true;
     }
 
@@ -265,10 +389,10 @@ namespace JSC {
      * then it calls put() on the ParentImp class.
      */
     template <class ThisImp, class ParentImp>
-    inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValuePtr 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