]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/StructureTransitionTable.h
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / runtime / StructureTransitionTable.h
index 5b4f4e63221b83043fd78e7cd167e723cdced22a..27c0a79adca5c46c81b4d0556d1403db6c9ecdbf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 #ifndef StructureTransitionTable_h
 #define StructureTransitionTable_h
 
-#include "UString.h"
+#include "IndexingType.h"
+#include "WeakGCMap.h"
 #include <wtf/HashFunctions.h>
-#include <wtf/HashMap.h>
-#include <wtf/HashTraits.h>
-#include <wtf/RefPtr.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/text/StringImpl.h>
 
 namespace JSC {
 
-    class Structure;
+class JSCell;
+class Structure;
 
-    struct StructureTransitionTableHash {
-        typedef std::pair<RefPtr<UString::Rep>, unsigned> Key;
+static const unsigned FirstInternalAttribute = 1 << 6; // Use for transitions that don't have to do with property additions.
+
+// Support for attributes used to indicate transitions not related to properties.
+// If any of these are used, the string portion of the key should be 0.
+enum NonPropertyTransition {
+    AllocateUndecided,
+    AllocateInt32,
+    AllocateDouble,
+    AllocateContiguous,
+    AllocateArrayStorage,
+    AllocateSlowPutArrayStorage,
+    SwitchToSlowPutArrayStorage,
+    AddIndexedAccessors
+};
+
+inline unsigned toAttributes(NonPropertyTransition transition)
+{
+    return transition + FirstInternalAttribute;
+}
+
+inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition)
+{
+    switch (transition) {
+    case AllocateUndecided:
+        ASSERT(!hasIndexedProperties(oldType));
+        return oldType | UndecidedShape;
+    case AllocateInt32:
+        ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType));
+        return (oldType & ~IndexingShapeMask) | Int32Shape;
+    case AllocateDouble:
+        ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType));
+        return (oldType & ~IndexingShapeMask) | DoubleShape;
+    case AllocateContiguous:
+        ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType));
+        return (oldType & ~IndexingShapeMask) | ContiguousShape;
+    case AllocateArrayStorage:
+        ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType));
+        return (oldType & ~IndexingShapeMask) | ArrayStorageShape;
+    case AllocateSlowPutArrayStorage:
+        ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType) || hasContiguous(oldType));
+        return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape;
+    case SwitchToSlowPutArrayStorage:
+        ASSERT(hasArrayStorage(oldType));
+        return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape;
+    case AddIndexedAccessors:
+        return oldType | MayHaveIndexedAccessors;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return oldType;
+    }
+}
+
+class StructureTransitionTable {
+    static const intptr_t UsingSingleSlotFlag = 1;
+
+    
+    struct Hash {
+        typedef std::pair<StringImpl*, unsigned> Key;
+        
         static unsigned hash(const Key& p)
         {
-            return p.first->computedHash();
+            return PtrHash<StringImpl*>::hash(p.first) + p.second;
         }
 
         static bool equal(const Key& a, const Key& b)
@@ -51,62 +109,83 @@ namespace JSC {
         static const bool safeToCompareToEmptyOrDeleted = true;
     };
 
-    struct StructureTransitionTableHashTraits {
-        typedef WTF::HashTraits<RefPtr<UString::Rep> > FirstTraits;
-        typedef WTF::GenericHashTraits<unsigned> SecondTraits;
-        typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType;
+    typedef WeakGCMap<Hash::Key, Structure, Hash> TransitionMap;
 
-        static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero;
-        static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); }
+public:
+    StructureTransitionTable()
+        : m_data(UsingSingleSlotFlag)
+    {
+    }
 
-        static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction;
+    ~StructureTransitionTable()
+    {
+        if (!isUsingSingleSlot()) {
+            delete map();
+            return;
+        }
 
-        static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); }
-        static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
-    };
+        WeakImpl* impl = this->weakImpl();
+        if (!impl)
+            return;
+        WeakSet::deallocate(impl);
+    }
 
-    class StructureTransitionTable {
-        typedef std::pair<Structure*, Structure*> Transition;
-        typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable;
-    public:
-        // The contains and get methods accept imprecise matches, so if an unspecialised transition exists
-        // for the given key they will consider that transition to be a match.  If a specialised transition
-        // exists and it matches the provided specificValue, get will return the specific transition.
-        inline bool contains(const StructureTransitionTableHash::Key&, JSCell* specificValue);
-        inline Structure* get(const StructureTransitionTableHash::Key&, JSCell* specificValue) const;
-        bool hasTransition(const StructureTransitionTableHash::Key& key)
-        {
-            return m_table.contains(key);
-        }
-        void remove(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
-        {
-            TransitionTable::iterator find = m_table.find(key);
-            if (!specificValue)
-                find->second.first = 0;
-            else
-                find->second.second = 0;
-            if (!find->second.first && !find->second.second)
-                m_table.remove(find);
-        }
-        void add(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue)
-        {
-            if (!specificValue) {
-                TransitionTable::iterator find = m_table.find(key);
-                if (find == m_table.end())
-                    m_table.add(key, Transition(structure, 0));
-                else
-                    find->second.first = structure;
-            } else {
-                // If we're adding a transition to a specific value, then there cannot be
-                // an existing transition
-                ASSERT(!m_table.contains(key));
-                m_table.add(key, Transition(0, structure));
-            }
+    inline void add(VM&, Structure*);
+    inline bool contains(StringImpl* rep, unsigned attributes) const;
+    inline Structure* get(StringImpl* rep, unsigned attributes) const;
+
+private:
+    bool isUsingSingleSlot() const
+    {
+        return m_data & UsingSingleSlotFlag;
+    }
+
+    TransitionMap* map() const
+    {
+        ASSERT(!isUsingSingleSlot());
+        return reinterpret_cast<TransitionMap*>(m_data);
+    }
+
+    WeakImpl* weakImpl() const
+    {
+        ASSERT(isUsingSingleSlot());
+        return reinterpret_cast<WeakImpl*>(m_data & ~UsingSingleSlotFlag);
+    }
 
+    void setMap(TransitionMap* map)
+    {
+        ASSERT(isUsingSingleSlot());
+        
+        if (WeakImpl* impl = this->weakImpl())
+            WeakSet::deallocate(impl);
+
+        // This implicitly clears the flag that indicates we're using a single transition
+        m_data = reinterpret_cast<intptr_t>(map);
+
+        ASSERT(!isUsingSingleSlot());
+    }
+
+    Structure* singleTransition() const
+    {
+        ASSERT(isUsingSingleSlot());
+        if (WeakImpl* impl = this->weakImpl()) {
+            if (impl->state() == WeakImpl::Live)
+                return reinterpret_cast<Structure*>(impl->jsValue().asCell());
         }
-    private:
-        TransitionTable m_table;
-    };
+        return 0;
+    }
+    
+    void setSingleTransition(VM&, Structure* structure)
+    {
+        ASSERT(isUsingSingleSlot());
+        if (WeakImpl* impl = this->weakImpl())
+            WeakSet::deallocate(impl);
+        WeakImpl* impl = WeakSet::allocate(reinterpret_cast<JSCell*>(structure));
+        m_data = reinterpret_cast<intptr_t>(impl) | UsingSingleSlotFlag;
+    }
+
+    intptr_t m_data;
+};
 
 } // namespace JSC