]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Structure.h
JavaScriptCore-584.tar.gz
[apple/javascriptcore.git] / runtime / Structure.h
index ea17c246167a2e171afe00be964a8e023daa404a..451ba3cefe3f5c030ed4e6a01a6e0838d699966e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "JSType.h"
 #include "JSValue.h"
 #include "PropertyMapHashTable.h"
+#include "PropertyNameArray.h"
+#include "Protect.h"
 #include "StructureChain.h"
 #include "StructureTransitionTable.h"
-#include "TypeInfo.h"
+#include "JSTypeInfo.h"
 #include "UString.h"
+#include "WeakGCPtr.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 
 
 namespace JSC {
 
+    class MarkStack;
     class PropertyNameArray;
     class PropertyNameArrayData;
 
+    enum EnumerationMode {
+        ExcludeDontEnumProperties,
+        IncludeDontEnumProperties
+    };
+
     class Structure : public RefCounted<Structure> {
     public:
         friend class JIT;
-        static PassRefPtr<Structure> create(JSValuePtr prototype, const TypeInfo& typeInfo)
+        friend class StructureTransitionTable;
+        static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo, unsigned anonymousSlotCount)
         {
-            return adoptRef(new Structure(prototype, typeInfo));
+            return adoptRef(new Structure(prototype, typeInfo, anonymousSlotCount));
         }
 
         static void startIgnoringLeaks();
@@ -61,57 +71,88 @@ namespace JSC {
 
         static void dumpStatistics();
 
-        static PassRefPtr<Structure> addPropertyTransition(Structure*, const Identifier& propertyName, unsigned attributes, size_t& offset);
-        static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, size_t& offset);
+        static PassRefPtr<Structure> addPropertyTransition(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
+        static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
         static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset);
-        static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValuePtr prototype);
+        static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype);
+        static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&);
         static PassRefPtr<Structure> getterSetterTransition(Structure*);
-        static PassRefPtr<Structure> toDictionaryTransition(Structure*);
-        static PassRefPtr<Structure> fromDictionaryTransition(Structure*);
+        static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*);
+        static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*);
 
-        ~Structure();
+        PassRefPtr<Structure> flattenDictionaryStructure(JSObject*);
 
-        void mark()
-        {
-            if (!m_prototype.marked())
-                m_prototype.mark();
-        }
+        ~Structure();
 
         // These should be used with caution.  
-        size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes);
+        size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
         size_t removePropertyWithoutTransition(const Identifier& propertyName);
-        void setPrototypeWithoutTransition(JSValuePtr prototype) { m_prototype = prototype; }
-
-        bool isDictionary() const { return m_isDictionary; }
+        void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; }
+        
+        bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
+        bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
 
         const TypeInfo& typeInfo() const { return m_typeInfo; }
 
-        JSValuePtr storedPrototype() const { return m_prototype; }
-        JSValuePtr prototypeForLookup(ExecState*) const;
+        JSValue storedPrototype() const { return m_prototype; }
+        JSValue prototypeForLookup(ExecState*) const;
         StructureChain* prototypeChain(ExecState*) const;
 
         Structure* previousID() const { return m_previous.get(); }
 
         void growPropertyStorageCapacity();
-        size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; }
-        size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; }
+        unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; }
+        unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1); }
+        bool isUsingInlineStorage() const;
 
         size_t get(const Identifier& propertyName);
-        size_t get(const Identifier& propertyName, unsigned& attributes);
-        void getEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*);
+        size_t get(const UString::Rep* rep, unsigned& attributes, JSCell*& specificValue);
+        size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
+        {
+            ASSERT(!propertyName.isNull());
+            return get(propertyName.ustring().rep(), attributes, specificValue);
+        }
+        bool transitionedFor(const JSCell* specificValue)
+        {
+            return m_specificValueInPrevious == specificValue;
+        }
+        bool hasTransition(UString::Rep*, unsigned attributes);
+        bool hasTransition(const Identifier& propertyName, unsigned attributes)
+        {
+            return hasTransition(propertyName._ustring.rep(), attributes);
+        }
 
         bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
         void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
 
+        bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
+
+        bool hasAnonymousSlots() const { return !!m_anonymousSlotCount; }
+        unsigned anonymousSlotCount() const { return m_anonymousSlotCount; }
+        
         bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; }
 
+        void despecifyDictionaryFunction(const Identifier& propertyName);
+        void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
+
+        void setEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
+        void clearEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
+        JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
+        void getPropertyNames(PropertyNameArray&, EnumerationMode mode);
+        
     private:
-        Structure(JSValuePtr prototype, const TypeInfo&);
 
-        size_t put(const Identifier& propertyName, unsigned attributes);
+        Structure(JSValue prototype, const TypeInfo&, unsigned anonymousSlotCount);
+        
+        typedef enum { 
+            NoneDictionaryKind = 0,
+            CachedDictionaryKind = 1,
+            UncachedDictionaryKind = 2
+        } DictionaryKind;
+        static PassRefPtr<Structure> toDictionaryTransition(Structure*, DictionaryKind);
+
+        size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
         size_t remove(const Identifier& propertyName);
-        void getEnumerableNamesFromPropertyTable(PropertyNameArray&);
-        void getEnumerableNamesFromClassInfoTable(ExecState*, const ClassInfo*, PropertyNameArray&);
 
         void expandPropertyMapHashTable();
         void rehashPropertyMapHashTable();
@@ -121,6 +162,9 @@ namespace JSC {
         void insertIntoPropertyMapHashTable(const PropertyMapEntry&);
         void checkConsistency();
 
+        bool despecifyFunction(const Identifier&);
+        void despecifyAllFunctions();
+
         PropertyMapHashTable* copyPropertyTable();
         void materializePropertyMap();
         void materializePropertyMapIfNecessary()
@@ -130,13 +174,6 @@ namespace JSC {
             materializePropertyMap();
         }
 
-        void clearEnumerationCache();
-
-        void* addressOfCount()
-        {
-            return &m_refCount;
-        }
-
         signed char transitionCount() const
         {
             // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
@@ -151,31 +188,43 @@ namespace JSC {
 
         static const signed char noOffset = -1;
 
+        static const unsigned maxSpecificFunctionThrashCount = 3;
+
         TypeInfo m_typeInfo;
 
-        JSValuePtr m_prototype;
+        JSValue m_prototype;
         mutable RefPtr<StructureChain> m_cachedPrototypeChain;
 
         RefPtr<Structure> m_previous;
         RefPtr<UString::Rep> m_nameInPrevious;
+        JSCell* m_specificValueInPrevious;
 
-        union {
-            Structure* singleTransition;
-            StructureTransitionTable* table;
-        } m_transitions;
+        StructureTransitionTable table;
 
-        RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData;
+        WeakGCPtr<JSPropertyNameIterator> m_enumerationCache;
 
         PropertyMapHashTable* m_propertyTable;
 
-        size_t m_propertyStorageCapacity;
+        uint32_t m_propertyStorageCapacity;
+
+        // m_offset does not account for anonymous slots
         signed char m_offset;
 
-        bool m_isDictionary : 1;
+        unsigned m_dictionaryKind : 2;
         bool m_isPinnedPropertyTable : 1;
         bool m_hasGetterSetterProperties : 1;
-        bool m_usingSingleTransitionSlot : 1;
-        unsigned m_attributesInPrevious : 5;
+        bool m_hasNonEnumerableProperties : 1;
+#if COMPILER(WINSCW)
+        // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared 
+        // bitfield, when used as argument in make_pair() function calls in structure.ccp.
+        // This bitfield optimization is insignificant for the Symbian emulator target.
+        unsigned m_attributesInPrevious;
+#else
+        unsigned m_attributesInPrevious : 7;
+#endif
+        unsigned m_specificFunctionThrashCount : 2;
+        unsigned m_anonymousSlotCount : 5;
+        // 5 free bits
     };
 
     inline size_t Structure::get(const Identifier& propertyName)
@@ -188,7 +237,7 @@ namespace JSC {
 
         UString::Rep* rep = propertyName._ustring.rep();
 
-        unsigned i = rep->computedHash();
+        unsigned i = rep->existingHash();
 
 #if DUMP_PROPERTYMAP_STATS
         ++numProbes;
@@ -205,7 +254,7 @@ namespace JSC {
         ++numCollisions;
 #endif
 
-        unsigned k = 1 | WTF::doubleHash(rep->computedHash());
+        unsigned k = 1 | WTF::doubleHash(rep->existingHash());
 
         while (1) {
             i += k;
@@ -222,7 +271,58 @@ namespace JSC {
                 return m_propertyTable->entries()[entryIndex - 1].offset;
         }
     }
+    
+    bool StructureTransitionTable::contains(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
+    {
+        if (usingSingleTransitionSlot()) {
+            Structure* existingTransition = singleTransition();
+            return existingTransition && existingTransition->m_nameInPrevious.get() == key.first
+                   && existingTransition->m_attributesInPrevious == key.second
+                   && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0);
+        }
+        TransitionTable::iterator find = table()->find(key);
+        if (find == table()->end())
+            return false;
+
+        return find->second.first || find->second.second->transitionedFor(specificValue);
+    }
+
+    Structure* StructureTransitionTable::get(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const
+    {
+        if (usingSingleTransitionSlot()) {
+            Structure* existingTransition = singleTransition();
+            if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first
+                && existingTransition->m_attributesInPrevious == key.second
+                && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0))
+                return existingTransition;
+            return 0;
+        }
+
+        Transition transition = table()->get(key);
+        if (transition.second && transition.second->transitionedFor(specificValue))
+            return transition.second;
+        return transition.first;
+    }
 
+    bool StructureTransitionTable::hasTransition(const StructureTransitionTableHash::Key& key) const
+    {
+        if (usingSingleTransitionSlot()) {
+            Structure* transition = singleTransition();
+            return transition && transition->m_nameInPrevious == key.first
+            && transition->m_attributesInPrevious == key.second;
+        }
+        return table()->contains(key);
+    }
+    
+    void StructureTransitionTable::reifySingleTransition()
+    {
+        ASSERT(usingSingleTransitionSlot());
+        Structure* existingTransition = singleTransition();
+        TransitionTable* transitionTable = new TransitionTable;
+        setTransitionTable(transitionTable);
+        if (existingTransition)
+            add(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious);
+    }
 } // namespace JSC
 
 #endif // Structure_h