]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/PropertyMapHashTable.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / PropertyMapHashTable.h
index 9ddb6997c4ba60203a227c977b6147fd679ea27d..b068b991dead55814c49d207428bcb6d1637edca 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- *  Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
 #ifndef PropertyMapHashTable_h
 #define PropertyMapHashTable_h
 
 #ifndef PropertyMapHashTable_h
 #define PropertyMapHashTable_h
 
+#include "JSExportMacros.h"
 #include "PropertyOffset.h"
 #include "Structure.h"
 #include "WriteBarrier.h"
 #include "PropertyOffset.h"
 #include "Structure.h"
 #include "WriteBarrier.h"
+#include <wtf/CryptographicallyRandomNumber.h>
 #include <wtf/HashTable.h>
 #include <wtf/MathExtras.h>
 #include <wtf/HashTable.h>
 #include <wtf/MathExtras.h>
-#include <wtf/PassOwnPtr.h>
 #include <wtf/Vector.h>
 #include <wtf/Vector.h>
-#include <wtf/text/StringImpl.h>
+#include <wtf/text/AtomicStringImpl.h>
 
 
 
 
-#ifndef NDEBUG
-#define DUMP_PROPERTYMAP_STATS 0
-#else
 #define DUMP_PROPERTYMAP_STATS 0
 #define DUMP_PROPERTYMAP_STATS 0
-#endif
+#define DUMP_PROPERTYMAP_COLLISIONS 0
 
 
-#if DUMP_PROPERTYMAP_STATS
+#define PROPERTY_MAP_DELETED_ENTRY_KEY ((UniquedStringImpl*)1)
 
 
-extern int numProbes;
-extern int numCollisions;
-extern int numRehashes;
-extern int numRemoves;
+namespace JSC {
 
 
-#endif
+#if DUMP_PROPERTYMAP_STATS
 
 
-#define PROPERTY_MAP_DELETED_ENTRY_KEY ((StringImpl*)1)
+struct PropertyMapHashTableStats {
+    std::atomic<unsigned> numFinds;
+    std::atomic<unsigned> numCollisions;
+    std::atomic<unsigned> numLookups;
+    std::atomic<unsigned> numLookupProbing;
+    std::atomic<unsigned> numAdds;
+    std::atomic<unsigned> numRemoves;
+    std::atomic<unsigned> numRehashes;
+    std::atomic<unsigned> numReinserts;
+};
 
 
-namespace JSC {
+JS_EXPORTDATA extern PropertyMapHashTableStats* propertyMapHashTableStats;
+
+#endif
 
 inline bool isPowerOf2(unsigned v)
 {
 
 inline bool isPowerOf2(unsigned v)
 {
@@ -71,22 +77,7 @@ inline unsigned nextPowerOf2(unsigned v)
     return v;
 }
 
     return v;
 }
 
-struct PropertyMapEntry {
-    StringImpl* key;
-    PropertyOffset offset;
-    unsigned attributes;
-    WriteBarrier<JSCell> specificValue;
-
-    PropertyMapEntry(VM& vm, JSCell* owner, StringImpl* key, PropertyOffset offset, unsigned attributes, JSCell* specificValue)
-        : key(key)
-        , offset(offset)
-        , attributes(attributes)
-        , specificValue(vm, owner, specificValue, WriteBarrier<JSCell>::MayBeNull)
-    {
-    }
-};
-
-class PropertyTable : public JSCell {
+class PropertyTable final : public JSCell {
 
     // This is the implementation for 'iterator' and 'const_iterator',
     // used for iterating over the table in insertion order.
 
     // This is the implementation for 'iterator' and 'const_iterator',
     // used for iterating over the table in insertion order.
@@ -129,20 +120,20 @@ class PropertyTable : public JSCell {
     };
 
 public:
     };
 
 public:
+    typedef JSCell Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
     static const bool needsDestruction = true;
     static const bool needsDestruction = true;
-    static const bool hasImmortalStructure = true;
     static void destroy(JSCell*);
 
     static void destroy(JSCell*);
 
-    static JS_EXPORTDATA const ClassInfo s_info;
+    DECLARE_EXPORT_INFO;
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
-        return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), &s_info);
+        return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
     }
 
     }
 
-    static void visitChildren(JSCell*, SlotVisitor&);
-
-    typedef StringImpl* KeyType;
+    typedef UniquedStringImpl* KeyType;
     typedef PropertyMapEntry ValueType;
 
     // The in order iterator provides overloaded * and -> to access the Value at the current position.
     typedef PropertyMapEntry ValueType;
 
     // The in order iterator provides overloaded * and -> to access the Value at the current position.
@@ -156,8 +147,8 @@ public:
 
     // Constructor is passed an initial capacity, a PropertyTable to copy, or both.
     static PropertyTable* create(VM&, unsigned initialCapacity);
 
     // Constructor is passed an initial capacity, a PropertyTable to copy, or both.
     static PropertyTable* create(VM&, unsigned initialCapacity);
-    static PropertyTable* clone(VM&, JSCell* owner, const PropertyTable&);
-    static PropertyTable* clone(VM&, JSCell* owner, unsigned initialCapacity, const PropertyTable&);
+    static PropertyTable* clone(VM&, const PropertyTable&);
+    static PropertyTable* clone(VM&, unsigned initialCapacity, const PropertyTable&);
     ~PropertyTable();
 
     // Ordered iteration methods.
     ~PropertyTable();
 
     // Ordered iteration methods.
@@ -168,7 +159,7 @@ public:
 
     // Find a value in the table.
     find_iterator find(const KeyType&);
 
     // Find a value in the table.
     find_iterator find(const KeyType&);
-    find_iterator findWithString(const KeyType&);
+    ValueType* get(const KeyType&);
     // Add a value to the table
     enum EffectOnPropertyOffset { PropertyOffsetMayChange, PropertyOffsetMustNotChange };
     std::pair<find_iterator, bool> add(const ValueType& entry, PropertyOffset&, EffectOnPropertyOffset);
     // Add a value to the table
     enum EffectOnPropertyOffset { PropertyOffsetMayChange, PropertyOffsetMustNotChange };
     std::pair<find_iterator, bool> add(const ValueType& entry, PropertyOffset&, EffectOnPropertyOffset);
@@ -194,7 +185,7 @@ public:
     PropertyOffset nextOffset(PropertyOffset inlineCapacity);
 
     // Copy this PropertyTable, ensuring the copy has at least the capacity provided.
     PropertyOffset nextOffset(PropertyOffset inlineCapacity);
 
     // Copy this PropertyTable, ensuring the copy has at least the capacity provided.
-    PropertyTable* copy(VM&, JSCell* owner, unsigned newCapacity);
+    PropertyTable* copy(VM&, unsigned newCapacity);
 
 #ifndef NDEBUG
     size_t sizeInMemory();
 
 #ifndef NDEBUG
     size_t sizeInMemory();
@@ -203,8 +194,8 @@ public:
 
 private:
     PropertyTable(VM&, unsigned initialCapacity);
 
 private:
     PropertyTable(VM&, unsigned initialCapacity);
-    PropertyTable(VM&, JSCell*, const PropertyTable&);
-    PropertyTable(VM&, JSCell*, unsigned initialCapacity, const PropertyTable&);
+    PropertyTable(VM&, const PropertyTable&);
+    PropertyTable(VM&, unsigned initialCapacity, const PropertyTable&);
 
     PropertyTable(const PropertyTable&);
     // Used to insert a value known not to be in the table, and where we know capacity to be available.
 
     PropertyTable(const PropertyTable&);
     // Used to insert a value known not to be in the table, and where we know capacity to be available.
@@ -250,9 +241,9 @@ private:
     unsigned* m_index;
     unsigned m_keyCount;
     unsigned m_deletedCount;
     unsigned* m_index;
     unsigned m_keyCount;
     unsigned m_deletedCount;
-    OwnPtr< Vector<PropertyOffset> > m_deletedOffsets;
+    std::unique_ptr<Vector<PropertyOffset>> m_deletedOffsets;
 
 
-    static const unsigned MinimumTableSize = 8;
+    static const unsigned MinimumTableSize = 16;
     static const unsigned EmptyEntryIndex = 0;
 };
 
     static const unsigned EmptyEntryIndex = 0;
 };
 
@@ -279,12 +270,12 @@ inline PropertyTable::const_iterator PropertyTable::end() const
 inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key)
 {
     ASSERT(key);
 inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key)
 {
     ASSERT(key);
-    ASSERT(key->isIdentifier() || key->isEmptyUnique());
-    unsigned hash = key->existingHash();
+    ASSERT(key->isAtomic() || key->isSymbol());
+    unsigned hash = IdentifierRepHash::hash(key);
     unsigned step = 0;
 
 #if DUMP_PROPERTYMAP_STATS
     unsigned step = 0;
 
 #if DUMP_PROPERTYMAP_STATS
-    ++numProbes;
+    ++propertyMapHashTableStats->numFinds;
 #endif
 
     while (true) {
 #endif
 
     while (true) {
@@ -294,50 +285,51 @@ inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key)
         if (key == table()[entryIndex - 1].key)
             return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask);
 
         if (key == table()[entryIndex - 1].key)
             return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask);
 
-#if DUMP_PROPERTYMAP_STATS
-        ++numCollisions;
-#endif
-
         if (!step)
         if (!step)
-            step = WTF::doubleHash(key->existingHash()) | 1;
-        hash += step;
+            step = WTF::doubleHash(IdentifierRepHash::hash(key)) | 1;
 
 #if DUMP_PROPERTYMAP_STATS
 
 #if DUMP_PROPERTYMAP_STATS
-        ++numRehashes;
+        ++propertyMapHashTableStats->numCollisions;
 #endif
 #endif
+
+#if DUMP_PROPERTYMAP_COLLISIONS
+        dataLog("PropertyTable collision for ", key, " (", hash, ") with step ", step, "\n");
+        dataLog("Collided with ", table()[entryIndex - 1].key, "(", IdentifierRepHash::hash(table()[entryIndex - 1].key), ")\n");
+#endif
+
+        hash += step;
     }
 }
 
     }
 }
 
-inline PropertyTable::find_iterator PropertyTable::findWithString(const KeyType& key)
+inline PropertyTable::ValueType* PropertyTable::get(const KeyType& key)
 {
     ASSERT(key);
 {
     ASSERT(key);
-    ASSERT(!key->isIdentifier() && !key->hasHash());
-    unsigned hash = key->hash();
+    ASSERT(key->isAtomic() || key->isSymbol());
+
+    if (!m_keyCount)
+        return nullptr;
+
+    unsigned hash = IdentifierRepHash::hash(key);
     unsigned step = 0;
 
 #if DUMP_PROPERTYMAP_STATS
     unsigned step = 0;
 
 #if DUMP_PROPERTYMAP_STATS
-    ++numProbes;
+    ++propertyMapHashTableStats->numLookups;
 #endif
 
     while (true) {
         unsigned entryIndex = m_index[hash & m_indexMask];
         if (entryIndex == EmptyEntryIndex)
 #endif
 
     while (true) {
         unsigned entryIndex = m_index[hash & m_indexMask];
         if (entryIndex == EmptyEntryIndex)
-            return std::make_pair((ValueType*)0, hash & m_indexMask);
-        const KeyType& keyInMap = table()[entryIndex - 1].key;
-        if (equal(key, keyInMap) && keyInMap->isIdentifier())
-            return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask);
+            return nullptr;
+        if (key == table()[entryIndex - 1].key)
+            return &table()[entryIndex - 1];
 
 #if DUMP_PROPERTYMAP_STATS
 
 #if DUMP_PROPERTYMAP_STATS
-        ++numCollisions;
+        ++propertyMapHashTableStats->numLookupProbing;
 #endif
 
         if (!step)
 #endif
 
         if (!step)
-            step = WTF::doubleHash(key->existingHash()) | 1;
+            step = WTF::doubleHash(IdentifierRepHash::hash(key)) | 1;
         hash += step;
         hash += step;
-
-#if DUMP_PROPERTYMAP_STATS
-        ++numRehashes;
-#endif
     }
 }
 
     }
 }
 
@@ -350,6 +342,10 @@ inline std::pair<PropertyTable::find_iterator, bool> PropertyTable::add(const Va
         return std::make_pair(iter, false);
     }
 
         return std::make_pair(iter, false);
     }
 
+#if DUMP_PROPERTYMAP_STATS
+    ++propertyMapHashTableStats->numAdds;
+#endif
+
     // Ref the key
     entry.key->ref();
 
     // Ref the key
     entry.key->ref();
 
@@ -383,7 +379,7 @@ inline void PropertyTable::remove(const find_iterator& iter)
         return;
 
 #if DUMP_PROPERTYMAP_STATS
         return;
 
 #if DUMP_PROPERTYMAP_STATS
-    ++numRemoves;
+    ++propertyMapHashTableStats->numRemoves;
 #endif
 
     // Replace this one element with the deleted sentinel. Also clear out
 #endif
 
     // Replace this one element with the deleted sentinel. Also clear out
@@ -423,7 +419,7 @@ inline unsigned PropertyTable::propertyStorageSize() const
 
 inline void PropertyTable::clearDeletedOffsets()
 {
 
 inline void PropertyTable::clearDeletedOffsets()
 {
-    m_deletedOffsets.clear();
+    m_deletedOffsets = nullptr;
 }
 
 inline bool PropertyTable::hasDeletedOffset()
 }
 
 inline bool PropertyTable::hasDeletedOffset()
@@ -441,7 +437,7 @@ inline PropertyOffset PropertyTable::getDeletedOffset()
 inline void PropertyTable::addDeletedOffset(PropertyOffset offset)
 {
     if (!m_deletedOffsets)
 inline void PropertyTable::addDeletedOffset(PropertyOffset offset)
 {
     if (!m_deletedOffsets)
-        m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>);
+        m_deletedOffsets = std::make_unique<Vector<PropertyOffset>>();
     m_deletedOffsets->append(offset);
 }
 
     m_deletedOffsets->append(offset);
 }
 
@@ -453,15 +449,15 @@ inline PropertyOffset PropertyTable::nextOffset(PropertyOffset inlineCapacity)
     return offsetForPropertyNumber(size(), inlineCapacity);
 }
 
     return offsetForPropertyNumber(size(), inlineCapacity);
 }
 
-inline PropertyTable* PropertyTable::copy(VM& vm, JSCell* owner, unsigned newCapacity)
+inline PropertyTable* PropertyTable::copy(VM& vm, unsigned newCapacity)
 {
     ASSERT(newCapacity >= m_keyCount);
 
     // Fast case; if the new table will be the same m_indexSize as this one, we can memcpy it,
     // save rehashing all keys.
     if (sizeForCapacity(newCapacity) == m_indexSize)
 {
     ASSERT(newCapacity >= m_keyCount);
 
     // Fast case; if the new table will be the same m_indexSize as this one, we can memcpy it,
     // save rehashing all keys.
     if (sizeForCapacity(newCapacity) == m_indexSize)
-        return PropertyTable::clone(vm, owner, *this);
-    return PropertyTable::clone(vm, owner, newCapacity, *this);
+        return PropertyTable::clone(vm, *this);
+    return PropertyTable::clone(vm, newCapacity, *this);
 }
 
 #ifndef NDEBUG
 }
 
 #ifndef NDEBUG
@@ -476,6 +472,10 @@ inline size_t PropertyTable::sizeInMemory()
 
 inline void PropertyTable::reinsert(const ValueType& entry)
 {
 
 inline void PropertyTable::reinsert(const ValueType& entry)
 {
+#if DUMP_PROPERTYMAP_STATS
+    ++propertyMapHashTableStats->numReinserts;
+#endif
+
     // Used to insert a value known not to be in the table, and where
     // we know capacity to be available.
     ASSERT(canInsert());
     // Used to insert a value known not to be in the table, and where
     // we know capacity to be available.
     ASSERT(canInsert());
@@ -491,6 +491,10 @@ inline void PropertyTable::reinsert(const ValueType& entry)
 
 inline void PropertyTable::rehash(unsigned newCapacity)
 {
 
 inline void PropertyTable::rehash(unsigned newCapacity)
 {
+#if DUMP_PROPERTYMAP_STATS
+    ++propertyMapHashTableStats->numRehashes;
+#endif
+
     unsigned* oldEntryIndices = m_index;
     iterator iter = this->begin();
     iterator end = this->end();
     unsigned* oldEntryIndices = m_index;
     iterator iter = this->begin();
     iterator end = this->end();