]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Lookup.h
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / runtime / Lookup.h
index c90ceae7c32881a8bb55ab54631d6d7e5c9658c8..909734b4448f7e749392888ddf741303d53308c6 100644 (file)
 #ifndef Lookup_h
 #define Lookup_h
 
+#include "BatchedTransitionOptimizer.h"
 #include "CallFrame.h"
-#include "Intrinsic.h"
+#include "CustomGetterSetter.h"
 #include "Identifier.h"
+#include "IdentifierInlines.h"
+#include "Intrinsic.h"
 #include "JSGlobalObject.h"
 #include "PropertySlot.h"
-#include <stdio.h>
+#include "PutPropertySlot.h"
 #include <wtf/Assertions.h>
 
 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;
+    struct CompactHashIndex {
+        const int16_t value;
+        const int16_t next;
     };
 
     // FIXME: There is no reason this get function can't be simpler.
     // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
     typedef PropertySlot::GetValueFunc GetFunction;
-    typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
-
-    class HashEntry {
-        WTF_MAKE_FAST_ALLOCATED;
-    public:
-        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(StringImpl* key) { m_key = key; }
-        StringImpl* key() const { return m_key; }
+    typedef PutPropertySlot::PutValueFunc PutFunction;
+    typedef FunctionExecutable* (*BuiltinGenerator)(VM&);
 
-        unsigned char attributes() const { return m_attributes; }
-
-        Intrinsic intrinsic() const
-        {
-            ASSERT(m_attributes & Function);
-            return m_intrinsic;
-        }
+    // Hash table generated by the create_hash_table script.
+    struct HashTableValue {
+        const char* m_key; // property name
+        unsigned m_attributes; // JSObject attributes
+        Intrinsic m_intrinsic;
+        intptr_t m_value1;
+        intptr_t m_value2;
 
-        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); }
+        unsigned attributes() const { return m_attributes; }
 
-        GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
-        PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
+        Intrinsic intrinsic() const { ASSERT(m_attributes & Function); return m_intrinsic; }
+        BuiltinGenerator builtinGenerator() const { ASSERT(m_attributes & Builtin); return reinterpret_cast<BuiltinGenerator>(m_value1); }
+        NativeFunction function() const { ASSERT(m_attributes & Function); return reinterpret_cast<NativeFunction>(m_value1); }
+        unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_value2); }
 
-        intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
+        GetFunction propertyGetter() const { ASSERT(!(m_attributes & BuiltinOrFunctionOrConstant)); return reinterpret_cast<GetFunction>(m_value1); }
+        PutFunction propertyPutter() const { ASSERT(!(m_attributes & BuiltinOrFunctionOrConstant)); return reinterpret_cast<PutFunction>(m_value2); }
 
-        void setNext(HashEntry *next) { m_next = next; }
-        HashEntry* next() const { return m_next; }
+        intptr_t constantInteger() const { ASSERT(m_attributes & ConstantInteger); return m_value1; }
 
-    private:
-        StringImpl* m_key;
-        unsigned char m_attributes; // JSObject attributes
-        Intrinsic m_intrinsic;
-
-        union {
-            struct {
-                intptr_t value1;
-                intptr_t value2;
-            } store;
-            struct {
-                NativeFunction functionValue;
-                intptr_t length; // number of arguments for function
-            } function;
-            struct {
-                GetFunction get;
-                PutFunction put;
-            } property;
-            struct {
-                intptr_t value;
-                intptr_t unused;
-            } lexer;
-        } m_u;
-
-        HashEntry* m_next;
+        intptr_t lexerValue() const { ASSERT(!m_attributes); return m_value1; }
     };
 
     struct HashTable {
-
-        int compactSize;
-        int compactHashSizeMask;
+        mutable int numberOfValues;
+        int indexMask;
+        bool hasSetterOrReadonlyProperties;
 
         const HashTableValue* values; // Fixed values generated by script.
-        mutable const HashEntry* table; // Table allocated at runtime.
+        mutable const char** keys; // Table allocated at runtime.
+        const CompactHashIndex* index;
 
         ALWAYS_INLINE HashTable copy() const
         {
             // Don't copy dynamic table since it's thread specific.
-            HashTable result = { compactSize, compactHashSizeMask, values, 0 };
+            HashTable result = { numberOfValues, indexMask, hasSetterOrReadonlyProperties, values, 0, index };
             return result;
         }
 
-        ALWAYS_INLINE void initializeIfNeeded(VM* vm) const
+        ALWAYS_INLINE void initializeIfNeeded(VM& vm) const
         {
-            if (!table)
+            if (!keys)
                 createTable(vm);
         }
 
         ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
         {
-            if (!table)
-                createTable(&exec->vm());
+            if (!keys)
+                createTable(exec->vm());
         }
 
         JS_EXPORT_PRIVATE void deleteTable() const;
 
         // Find an entry in the table, and return the entry.
-        ALWAYS_INLINE const HashEntry* entry(VM* vm, PropertyName identifier) const
+        ALWAYS_INLINE const HashTableValue* entry(VM& vm, PropertyName identifier) const
         {
             initializeIfNeeded(vm);
             return entry(identifier);
         }
 
-        ALWAYS_INLINE const HashEntry* entry(ExecState* exec, PropertyName identifier) const
+        ALWAYS_INLINE const HashTableValue* entry(ExecState* exec, PropertyName identifier) const
         {
             initializeIfNeeded(exec);
             return entry(identifier);
@@ -157,14 +119,19 @@ namespace JSC {
                 skipInvalidKeys();
             }
 
-            const HashEntry* operator->()
+            const HashTableValue* value()
             {
-                return &m_table->table[m_position];
+                return &m_table->values[m_position];
             }
 
-            const HashEntry* operator*()
+            const char* key()
             {
-                return &m_table->table[m_position];
+                return m_table->keys[m_position];
+            }
+
+            const HashTableValue* operator->()
+            {
+                return value();
             }
 
             bool operator!=(const ConstIterator& other)
@@ -175,7 +142,7 @@ namespace JSC {
             
             ConstIterator& operator++()
             {
-                ASSERT(m_position < m_table->compactSize);
+                ASSERT(m_position < m_table->numberOfValues);
                 ++m_position;
                 skipInvalidKeys();
                 return *this;
@@ -184,10 +151,10 @@ namespace JSC {
         private:
             void skipInvalidKeys()
             {
-                ASSERT(m_position <= m_table->compactSize);
-                while (m_position < m_table->compactSize && !m_table->table[m_position].key())
+                ASSERT(m_position <= m_table->numberOfValues);
+                while (m_position < m_table->numberOfValues && !m_table->keys[m_position])
                     ++m_position;
-                ASSERT(m_position <= m_table->compactSize);
+                ASSERT(m_position <= m_table->numberOfValues);
             }
             
             const HashTable* m_table;
@@ -196,43 +163,46 @@ namespace JSC {
 
         ConstIterator begin(VM& vm) const
         {
-            initializeIfNeeded(&vm);
+            initializeIfNeeded(vm);
             return ConstIterator(this, 0);
         }
         ConstIterator end(VM& vm) const
         {
-            initializeIfNeeded(&vm);
-            return ConstIterator(this, compactSize);
+            initializeIfNeeded(vm);
+            return ConstIterator(this, numberOfValues);
         }
 
     private:
-        ALWAYS_INLINE const HashEntry* entry(PropertyName propertyName) const
+        ALWAYS_INLINE const HashTableValue* entry(PropertyName propertyName) const
         {
-            StringImpl* impl = propertyName.publicName();
+            StringImpl* impl = propertyName.uid();
             if (!impl)
                 return 0;
         
-            ASSERT(table);
-
-            const HashEntry* entry = &table[impl->existingHash() & compactHashSizeMask];
+            ASSERT(keys);
 
-            if (!entry->key())
+            int indexEntry = impl->existingHash() & indexMask;
+            int valueIndex = index[indexEntry].value;
+            if (valueIndex == -1)
                 return 0;
 
-            do {
-                if (entry->key() == impl)
-                    return entry;
-                entry = entry->next();
-            } while (entry);
+            while (true) {
+                if (WTF::equal(impl, keys[valueIndex]))
+                    return &values[valueIndex];
 
-            return 0;
+                indexEntry = index[indexEntry].next;
+                if (indexEntry == -1)
+                    return nullptr;
+                valueIndex = index[indexEntry].value;
+                ASSERT(valueIndex != -1);
+            };
         }
 
         // Convert the hash table keys to identifiers.
-        JS_EXPORT_PRIVATE void createTable(VM*) const;
+        JS_EXPORT_PRIVATE void createTable(VM&) const;
     };
 
-    JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, PropertyName, PropertySlot&);
+    JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashTableValue*, JSObject* thisObject, PropertyName, PropertySlot&);
 
     /**
      * This method does it all (looking in the hashtable, checking for function
@@ -241,38 +211,22 @@ namespace JSC {
      * unknown property).
      */
     template <class ThisImp, class ParentImp>
-    inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
+    inline bool getStaticPropertySlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
     {
-        const HashEntry* entry = table->entry(exec, propertyName);
+        const HashTableValue* entry = table.entry(exec, propertyName);
 
         if (!entry) // not found, forward to parent
             return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
 
-        if (entry->attributes() & Function)
+        if (entry->attributes() & BuiltinOrFunction)
             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;
+        if (entry->attributes() & ConstantInteger) {
+            slot.setValue(thisObj, entry->attributes(), jsNumber(entry->constantInteger()));
+            return true;
         }
-
-        slot.setCustom(thisObj, entry->propertyGetter());
-        descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
+    
+        slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
         return true;
     }
 
@@ -282,86 +236,51 @@ namespace JSC {
      * a dummy getValueProperty.
      */
     template <class ParentImp>
-    inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
+    inline bool getStaticFunctionSlot(ExecState* exec, const HashTable& table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
     {
         if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
             return true;
 
-        const HashEntry* entry = table->entry(exec, propertyName);
+        const HashTableValue* entry = table.entry(exec, propertyName);
         if (!entry)
             return false;
 
         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;
-    }
 
     /**
      * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
      * 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, PropertyName propertyName, PropertySlot& slot)
+    inline bool getStaticValueSlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
     {
-        const HashEntry* entry = table->entry(exec, propertyName);
+        const HashTableValue* entry = table.entry(exec, propertyName);
 
         if (!entry) // not found, forward to parent
             return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
 
-        ASSERT(!(entry->attributes() & Function));
+        ASSERT(!(entry->attributes() & BuiltinOrFunction));
 
-        slot.setCacheableCustom(thisObj, entry->propertyGetter());
-        return true;
-    }
+        if (entry->attributes() & ConstantInteger) {
+            slot.setValue(thisObj, entry->attributes(), jsNumber(entry->constantInteger()));
+            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());
+        slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
         return true;
     }
 
-    template <class ThisImp>
-    inline void putEntry(ExecState* exec, const HashEntry* entry, PropertyName propertyName, JSValue value, ThisImp* thisObj, bool shouldThrow = false)
+    inline void putEntry(ExecState* exec, const HashTableValue* entry, JSObject* base, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
     {
         // 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)
+        if (entry->attributes() & BuiltinOrFunction) {
+            if (JSObject* thisObject = jsDynamicCast<JSObject*>(slot.thisValue()))
+                thisObject->putDirect(exec->vm(), propertyName, value);
+        } else if (!(entry->attributes() & ReadOnly)) {
+            entry->propertyPutter()(exec, base, JSValue::encode(slot.thisValue()), JSValue::encode(value));
+            slot.setCustomProperty(base, entry->propertyPutter());
+        } else if (slot.isStrictMode())
             throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
     }
 
@@ -370,29 +289,50 @@ namespace JSC {
      * 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, PropertyName propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, bool shouldThrow = false)
+    inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSObject* base, JSValue value, const HashTable& table, PutPropertySlot& slot)
     {
-        const HashEntry* entry = table->entry(exec, propertyName);
-        
+        const HashTableValue* entry = table.entry(exec, propertyName);
+
         if (!entry)
             return false;
 
-        putEntry<ThisImp>(exec, entry, propertyName, value, thisObj, shouldThrow);
+        putEntry(exec, entry, base, propertyName, value, slot);
         return true;
     }
 
-    /**
-     * This one is for "put".
-     * It calls lookupPut<ThisImp>() to set the value.  If that call
-     * returns false (meaning no entry in the hash table was found),
-     * then it calls put() on the ParentImp class.
-     */
-    template <class ThisImp, class ParentImp>
-    inline void lookupPut(ExecState* exec, PropertyName propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
+    template<unsigned numberOfValues>
+    inline void reifyStaticProperties(VM& vm, const HashTableValue (&values)[numberOfValues], JSObject& thisObj)
     {
-        if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj, slot.isStrictMode()))
-            ParentImp::put(thisObj, exec, propertyName, value, slot); // not found: forward to parent
+        BatchedTransitionOptimizer transitionOptimizer(vm, &thisObj);
+        for (auto& value : values) {
+            if (!value.m_key)
+                continue;                
+        
+            Identifier propertyName(&vm, reinterpret_cast<const LChar*>(value.m_key), strlen(value.m_key));
+            if (value.attributes() & Builtin) {
+                thisObj.putDirectBuiltinFunction(vm, thisObj.globalObject(), propertyName, value.builtinGenerator()(vm), value.attributes());
+                continue;
+            }
+
+            if (value.attributes() & Function) {
+                thisObj.putDirectNativeFunction(vm, thisObj.globalObject(), propertyName, value.functionLength(),
+                    value.function(), value.intrinsic(), value.attributes());
+                continue;
+            }
+
+            if (value.attributes() & ConstantInteger) {
+                thisObj.putDirect(vm, propertyName, jsNumber(value.constantInteger()), value.attributes());
+                continue;
+            }
+
+            if (value.attributes() & Accessor) {
+                RELEASE_ASSERT_NOT_REACHED();
+                continue;
+            }
+
+            CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, value.propertyGetter(), value.propertyPutter());
+            thisObj.putDirectCustomAccessor(vm, propertyName, customGetterSetter, value.attributes());
+        }
     }
 
 } // namespace JSC