]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Lookup.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / Lookup.h
index 909734b4448f7e749392888ddf741303d53308c6..4c86ccdcc1dbba40a60934871d2127dca1a0ad94 100644 (file)
 #include <wtf/Assertions.h>
 
 namespace JSC {
-    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 PutPropertySlot::PutValueFunc PutFunction;
-    typedef FunctionExecutable* (*BuiltinGenerator)(VM&);
+struct CompactHashIndex {
+    const int16_t value;
+    const int16_t next;
+};
 
-    // 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;
+// FIXME: There is no reason this get function can't be simpler.
+// ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
+typedef PropertySlot::GetValueFunc GetFunction;
+typedef PutPropertySlot::PutValueFunc PutFunction;
+typedef FunctionExecutable* (*BuiltinGenerator)(VM&);
 
-        unsigned attributes() const { return m_attributes; }
+// 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;
 
-        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); }
+    unsigned attributes() const { return m_attributes; }
 
-        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); }
+    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 constantInteger() const { ASSERT(m_attributes & ConstantInteger); return m_value1; }
+    GetFunction propertyGetter() const { ASSERT(!(m_attributes & BuiltinOrFunctionOrAccessorOrConstant)); return reinterpret_cast<GetFunction>(m_value1); }
+    PutFunction propertyPutter() const { ASSERT(!(m_attributes & BuiltinOrFunctionOrAccessorOrConstant)); return reinterpret_cast<PutFunction>(m_value2); }
 
-        intptr_t lexerValue() const { ASSERT(!m_attributes); return m_value1; }
-    };
+    NativeFunction accessorGetter() const { ASSERT(m_attributes & Accessor); return reinterpret_cast<NativeFunction>(m_value1); }
+    NativeFunction accessorSetter() const { ASSERT(m_attributes & Accessor); return reinterpret_cast<NativeFunction>(m_value2); }
 
-    struct HashTable {
-        mutable int numberOfValues;
-        int indexMask;
-        bool hasSetterOrReadonlyProperties;
+    intptr_t constantInteger() const { ASSERT(m_attributes & ConstantInteger); return m_value1; }
 
-        const HashTableValue* values; // Fixed values generated by script.
-        mutable const char** keys; // Table allocated at runtime.
-        const CompactHashIndex* index;
+    intptr_t lexerValue() const { ASSERT(!m_attributes); return m_value1; }
+};
 
-        ALWAYS_INLINE HashTable copy() const
-        {
-            // Don't copy dynamic table since it's thread specific.
-            HashTable result = { numberOfValues, indexMask, hasSetterOrReadonlyProperties, values, 0, index };
-            return result;
-        }
+struct HashTable {
+    mutable int numberOfValues;
+    int indexMask;
+    bool hasSetterOrReadonlyProperties;
+
+    const HashTableValue* values; // Fixed values generated by script.
+    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 = { numberOfValues, indexMask, hasSetterOrReadonlyProperties, values, 0, index };
+        return result;
+    }
+
+    ALWAYS_INLINE void initializeIfNeeded() const
+    {
+        if (!keys)
+            createTable();
+    }
+
+    JS_EXPORT_PRIVATE void deleteTable() const;
+
+    // Find an entry in the table, and return the entry.
+    ALWAYS_INLINE const HashTableValue* entry(PropertyName propertyName) const
+    {
+        initializeIfNeeded();
+
+        if (propertyName.isSymbol())
+            return nullptr;
 
-        ALWAYS_INLINE void initializeIfNeeded(VM& vm) const
+        auto uid = propertyName.uid();
+        if (!uid)
+            return nullptr;
+
+        ASSERT(keys);
+
+        int indexEntry = IdentifierRepHash::hash(uid) & indexMask;
+        int valueIndex = index[indexEntry].value;
+        if (valueIndex == -1)
+            return nullptr;
+
+        while (true) {
+            if (WTF::equal(uid, keys[valueIndex]))
+                return &values[valueIndex];
+
+            indexEntry = index[indexEntry].next;
+            if (indexEntry == -1)
+                return nullptr;
+            valueIndex = index[indexEntry].value;
+            ASSERT(valueIndex != -1);
+        };
+    }
+
+    class ConstIterator {
+    public:
+        ConstIterator(const HashTable* table, int position)
+            : m_table(table)
+            , m_position(position)
         {
-            if (!keys)
-                createTable(vm);
+            skipInvalidKeys();
         }
 
-        ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
+        const HashTableValue* value()
         {
-            if (!keys)
-                createTable(exec->vm());
+            return &m_table->values[m_position];
         }
 
-        JS_EXPORT_PRIVATE void deleteTable() const;
-
-        // Find an entry in the table, and return the entry.
-        ALWAYS_INLINE const HashTableValue* entry(VM& vm, PropertyName identifier) const
+        const char* key()
         {
-            initializeIfNeeded(vm);
-            return entry(identifier);
+            return m_table->keys[m_position];
         }
 
-        ALWAYS_INLINE const HashTableValue* entry(ExecState* exec, PropertyName identifier) const
+        const HashTableValue* operator->()
         {
-            initializeIfNeeded(exec);
-            return entry(identifier);
+            return value();
         }
 
-        class ConstIterator {
-        public:
-            ConstIterator(const HashTable* table, int position)
-                : m_table(table)
-                , m_position(position)
-            {
-                skipInvalidKeys();
-            }
-
-            const HashTableValue* value()
-            {
-                return &m_table->values[m_position];
-            }
-
-            const char* key()
-            {
-                return m_table->keys[m_position];
-            }
-
-            const HashTableValue* operator->()
-            {
-                return value();
-            }
-
-            bool operator!=(const ConstIterator& other)
-            {
-                ASSERT(m_table == other.m_table);
-                return m_position != other.m_position;
-            }
-            
-            ConstIterator& operator++()
-            {
-                ASSERT(m_position < m_table->numberOfValues);
-                ++m_position;
-                skipInvalidKeys();
-                return *this;
-            }
-
-        private:
-            void skipInvalidKeys()
-            {
-                ASSERT(m_position <= m_table->numberOfValues);
-                while (m_position < m_table->numberOfValues && !m_table->keys[m_position])
-                    ++m_position;
-                ASSERT(m_position <= m_table->numberOfValues);
-            }
-            
-            const HashTable* m_table;
-            int m_position;
-        };
-
-        ConstIterator begin(VM& vm) const
+        bool operator!=(const ConstIterator& other)
         {
-            initializeIfNeeded(vm);
-            return ConstIterator(this, 0);
+            ASSERT(m_table == other.m_table);
+            return m_position != other.m_position;
         }
-        ConstIterator end(VM& vm) const
+
+        ConstIterator& operator++()
         {
-            initializeIfNeeded(vm);
-            return ConstIterator(this, numberOfValues);
+            ASSERT(m_position < m_table->numberOfValues);
+            ++m_position;
+            skipInvalidKeys();
+            return *this;
         }
 
     private:
-        ALWAYS_INLINE const HashTableValue* entry(PropertyName propertyName) const
+        void skipInvalidKeys()
         {
-            StringImpl* impl = propertyName.uid();
-            if (!impl)
-                return 0;
-        
-            ASSERT(keys);
-
-            int indexEntry = impl->existingHash() & indexMask;
-            int valueIndex = index[indexEntry].value;
-            if (valueIndex == -1)
-                return 0;
-
-            while (true) {
-                if (WTF::equal(impl, keys[valueIndex]))
-                    return &values[valueIndex];
-
-                indexEntry = index[indexEntry].next;
-                if (indexEntry == -1)
-                    return nullptr;
-                valueIndex = index[indexEntry].value;
-                ASSERT(valueIndex != -1);
-            };
+            ASSERT(m_position <= m_table->numberOfValues);
+            while (m_position < m_table->numberOfValues && !m_table->keys[m_position])
+                ++m_position;
+            ASSERT(m_position <= m_table->numberOfValues);
         }
 
-        // Convert the hash table keys to identifiers.
-        JS_EXPORT_PRIVATE void createTable(VM&) const;
+        const HashTable* m_table;
+        int m_position;
     };
 
-    JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashTableValue*, JSObject* thisObject, PropertyName, PropertySlot&);
-
-    /**
-     * This method does it all (looking in the hashtable, checking for function
-     * overrides, creating the function or retrieving from cache, calling
-     * getValueProperty in case of a non-function property, forwarding to parent if
-     * unknown property).
-     */
-    template <class ThisImp, class ParentImp>
-    inline bool getStaticPropertySlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
+    ConstIterator begin() const
     {
-        const HashTableValue* entry = table.entry(exec, propertyName);
+        initializeIfNeeded();
+        return ConstIterator(this, 0);
+    }
+    ConstIterator end() const
+    {
+        initializeIfNeeded();
+        return ConstIterator(this, numberOfValues);
+    }
 
-        if (!entry) // not found, forward to parent
-            return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
+private:
+    // Convert the hash table keys to identifiers.
+    JS_EXPORT_PRIVATE void createTable() const;
+};
 
-        if (entry->attributes() & BuiltinOrFunction)
-            return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashTableValue*, JSObject* thisObject, PropertyName, PropertySlot&);
+JS_EXPORT_PRIVATE void reifyStaticAccessor(VM&, const HashTableValue&, JSObject& thisObject, PropertyName);
 
-        if (entry->attributes() & ConstantInteger) {
-            slot.setValue(thisObj, entry->attributes(), jsNumber(entry->constantInteger()));
-            return true;
-        }
-    
-        slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
+/**
+ * This method does it all (looking in the hashtable, checking for function
+ * overrides, creating the function or retrieving from cache, calling
+ * getValueProperty in case of a non-function property, forwarding to parent if
+ * unknown property).
+ */
+template <class ThisImp, class ParentImp>
+inline bool getStaticPropertySlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
+{
+    const HashTableValue* entry = table.entry(propertyName);
+
+    if (!entry) // not found, forward to parent
+        return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
+
+    if (entry->attributes() & BuiltinOrFunctionOrAccessor)
+        return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+
+    if (entry->attributes() & ConstantInteger) {
+        slot.setValue(thisObj, entry->attributes(), jsNumber(entry->constantInteger()));
         return true;
     }
 
-    /**
-     * Simplified version of getStaticPropertySlot in case there are only functions.
-     * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
-     * a dummy getValueProperty.
-     */
-    template <class ParentImp>
-    inline bool getStaticFunctionSlot(ExecState* exec, const HashTable& table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
-    {
-        if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
-            return true;
+    slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
+    return true;
+}
 
-        const HashTableValue* entry = table.entry(exec, propertyName);
-        if (!entry)
-            return false;
+/**
+ * Simplified version of getStaticPropertySlot in case there are only functions.
+ * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
+ * a dummy getValueProperty.
+ */
+template <class ParentImp>
+inline bool getStaticFunctionSlot(ExecState* exec, const HashTable& table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
+{
+    if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
+        return true;
 
-        return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
-    }
+    const HashTableValue* entry = table.entry(propertyName);
+    if (!entry)
+        return false;
 
-    /**
-     * 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)
-    {
-        const HashTableValue* entry = table.entry(exec, propertyName);
+    return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+}
 
-        if (!entry) // not found, forward to parent
-            return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
+/**
+ * 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)
+{
+    const HashTableValue* entry = table.entry(propertyName);
 
-        ASSERT(!(entry->attributes() & BuiltinOrFunction));
+    if (!entry) // not found, forward to parent
+        return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
 
-        if (entry->attributes() & ConstantInteger) {
-            slot.setValue(thisObj, entry->attributes(), jsNumber(entry->constantInteger()));
-            return true;
-        }
+    ASSERT(!(entry->attributes() & BuiltinOrFunctionOrAccessor));
 
-        slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
+    if (entry->attributes() & ConstantInteger) {
+        slot.setValue(thisObj, entry->attributes(), jsNumber(entry->constantInteger()));
         return true;
     }
 
-    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() & 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())
+    slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
+    return true;
+}
+
+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() & BuiltinOrFunction) {
+        if (JSObject* thisObject = jsDynamicCast<JSObject*>(slot.thisValue()))
+            thisObject->putDirect(exec->vm(), propertyName, value);
+    } else if (entry->attributes() & Accessor) {
+        if (slot.isStrictMode())
             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.
-     */
-    inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSObject* base, JSValue value, const HashTable& table, PutPropertySlot& slot)
-    {
-        const HashTableValue* entry = table.entry(exec, propertyName);
+    } 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);
+}
+
+/**
+ * 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.
+ */
+inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSObject* base, JSValue value, const HashTable& table, PutPropertySlot& slot)
+{
+    const HashTableValue* entry = table.entry(propertyName);
+
+    if (!entry)
+        return false;
+
+    putEntry(exec, entry, base, propertyName, value, slot);
+    return true;
+}
+
+template<unsigned numberOfValues>
+inline void reifyStaticProperties(VM& vm, const HashTableValue (&values)[numberOfValues], JSObject& thisObj)
+{
+    BatchedTransitionOptimizer transitionOptimizer(vm, &thisObj);
+    for (auto& value : values) {
+        if (!value.m_key)
+            continue;
+
+        Identifier propertyName = Identifier::fromString(&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 (!entry)
-            return false;
+        if (value.attributes() & Function) {
+            thisObj.putDirectNativeFunction(vm, thisObj.globalObject(), propertyName, value.functionLength(),
+                value.function(), value.intrinsic(), value.attributes());
+            continue;
+        }
 
-        putEntry(exec, entry, base, propertyName, value, slot);
-        return true;
-    }
+        if (value.attributes() & ConstantInteger) {
+            thisObj.putDirect(vm, propertyName, jsNumber(value.constantInteger()), value.attributes());
+            continue;
+        }
 
-    template<unsigned numberOfValues>
-    inline void reifyStaticProperties(VM& vm, const HashTableValue (&values)[numberOfValues], JSObject& thisObj)
-    {
-        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());
+        if (value.attributes() & Accessor) {
+            reifyStaticAccessor(vm, value, thisObj, propertyName);
+            continue;
         }
+
+        CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, value.propertyGetter(), value.propertyPutter());
+        thisObj.putDirectCustomAccessor(vm, propertyName, customGetterSetter, value.attributes());
     }
+}
 
 } // namespace JSC