Unused Structure property tables waste 14MB on Membuster.
authorakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Feb 2013 15:32:30 +0000 (15:32 +0000)
committerakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Feb 2013 15:32:30 +0000 (15:32 +0000)
<http://webkit.org/b/110854>
<rdar://problem/13292104>

Reviewed by Filip Pizlo.

Turn PropertyTable into a GC object and have Structure drop unpinned tables when marking.
14 MB progression on Membuster3.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.gypi:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:

    Added PropertyTable.cpp.

* runtime/PropertyTable.cpp: Added.
(JSC::PropertyTable::create):
(JSC::PropertyTable::clone):
(JSC::PropertyTable::PropertyTable):
(JSC::PropertyTable::destroy):
(JSC::PropertyTable::~PropertyTable):
(JSC::PropertyTable::visitChildren):

    Moved marking of property table values here from Structure::visitChildren().

* runtime/StructureInlines.h:
(JSC::Structure::putWillGrowOutOfLineStorage):
(JSC::Structure::checkOffsetConsistency):

    Moved these to StructureInlines.h to break header dependency cycle between Structure/PropertyTable.

* runtime/Structure.cpp:
(JSC::Structure::visitChildren):

    Null out m_propertyTable if the table is unpinned. This'll cause the table to get GC'd.

(JSC::Structure::materializePropertyMap):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::changePrototypeTransition):
(JSC::Structure::despecifyFunctionTransition):
(JSC::Structure::attributeChangeTransition):
(JSC::Structure::toDictionaryTransition):
(JSC::Structure::preventExtensionsTransition):
(JSC::Structure::nonPropertyTransition):
(JSC::Structure::copyPropertyTable):
(JSC::Structure::copyPropertyTableForPinning):
(JSC::Structure::putSpecificValue):
(JSC::Structure::createPropertyMap):
* runtime/Structure.h:
(Structure):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
* runtime/JSGlobalData.h:
(JSGlobalData):
* runtime/PropertyMapHashTable.h:
(PropertyTable):
(JSC::PropertyTable::createStructure):
(JSC::PropertyTable::copy):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@144054 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.gypi
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/runtime/JSGlobalData.cpp
Source/JavaScriptCore/runtime/JSGlobalData.h
Source/JavaScriptCore/runtime/PropertyMapHashTable.h
Source/JavaScriptCore/runtime/PropertyTable.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/runtime/StructureInlines.h

index 3bd6823..3bb3912 100644 (file)
@@ -280,6 +280,7 @@ set(JavaScriptCore_SOURCES
     runtime/PropertyDescriptor.cpp
     runtime/PropertyNameArray.cpp
     runtime/PropertySlot.cpp
+    runtime/PropertyTable.cpp
     runtime/PrototypeMap.cpp
     runtime/RegExp.cpp
     runtime/RegExpCache.cpp
index 6a3948b..e856f85 100644 (file)
@@ -1,3 +1,68 @@
+2013-02-26  Andreas Kling  <akling@apple.com>
+
+        Unused Structure property tables waste 14MB on Membuster.
+        <http://webkit.org/b/110854>
+        <rdar://problem/13292104>
+
+        Reviewed by Filip Pizlo.
+
+        Turn PropertyTable into a GC object and have Structure drop unpinned tables when marking.
+        14 MB progression on Membuster3.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.gypi:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+
+            Added PropertyTable.cpp.
+
+        * runtime/PropertyTable.cpp: Added.
+        (JSC::PropertyTable::create):
+        (JSC::PropertyTable::clone):
+        (JSC::PropertyTable::PropertyTable):
+        (JSC::PropertyTable::destroy):
+        (JSC::PropertyTable::~PropertyTable):
+        (JSC::PropertyTable::visitChildren):
+
+            Moved marking of property table values here from Structure::visitChildren().
+
+        * runtime/StructureInlines.h:
+        (JSC::Structure::putWillGrowOutOfLineStorage):
+        (JSC::Structure::checkOffsetConsistency):
+
+            Moved these to StructureInlines.h to break header dependency cycle between Structure/PropertyTable.
+
+        * runtime/Structure.cpp:
+        (JSC::Structure::visitChildren):
+
+            Null out m_propertyTable if the table is unpinned. This'll cause the table to get GC'd.
+
+        (JSC::Structure::materializePropertyMap):
+        (JSC::Structure::addPropertyTransition):
+        (JSC::Structure::changePrototypeTransition):
+        (JSC::Structure::despecifyFunctionTransition):
+        (JSC::Structure::attributeChangeTransition):
+        (JSC::Structure::toDictionaryTransition):
+        (JSC::Structure::preventExtensionsTransition):
+        (JSC::Structure::nonPropertyTransition):
+        (JSC::Structure::copyPropertyTable):
+        (JSC::Structure::copyPropertyTableForPinning):
+        (JSC::Structure::putSpecificValue):
+        (JSC::Structure::createPropertyMap):
+        * runtime/Structure.h:
+        (Structure):
+        * runtime/JSGlobalData.cpp:
+        (JSC::JSGlobalData::JSGlobalData):
+        * runtime/JSGlobalData.h:
+        (JSGlobalData):
+        * runtime/PropertyMapHashTable.h:
+        (PropertyTable):
+        (JSC::PropertyTable::createStructure):
+        (JSC::PropertyTable::copy):
+
 2013-02-26  Jocelyn Turcotte  <jocelyn.turcotte@digia.com>
 
         Implement JIT on Windows 64 bits
index e8a1f2b..51d5a41 100644 (file)
@@ -722,6 +722,7 @@ javascriptcore_sources += \
        Source/JavaScriptCore/runtime/PropertyOffset.h \
        Source/JavaScriptCore/runtime/PropertySlot.cpp \
        Source/JavaScriptCore/runtime/PropertySlot.h \
+       Source/JavaScriptCore/runtime/PropertyTable.cpp \
        Source/JavaScriptCore/runtime/PrototypeMap.cpp \
        Source/JavaScriptCore/runtime/PrototypeMap.h \
        Source/JavaScriptCore/runtime/PropertyStorage.h \
index 85f6446..c901cbc 100644 (file)
             'runtime/PropertyOffset.h',
             'runtime/PropertySlot.cpp',
             'runtime/PropertySlot.h',
+            'runtime/PropertyTable.cpp',
             'runtime/PropertyStorage.h',
             'runtime/Protect.h',
             'runtime/PrototypeMap.cpp',
index 7517a4a..560fb28 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\runtime\PropertyTable.cpp"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\runtime\PrototypeMap.cpp"
                                >
                        </File>
index 325e725..f05505e 100644 (file)
     <ClCompile Include="..\runtime\PropertyDescriptor.cpp" />\r
     <ClCompile Include="..\runtime\PropertyNameArray.cpp" />\r
     <ClCompile Include="..\runtime\PropertySlot.cpp" />\r
+    <ClCompile Include="..\runtime\PropertyTable.cpp" />\r
     <ClCompile Include="..\runtime\PrototypeMap.cpp" />\r
     <ClCompile Include="..\runtime\RegExp.cpp" />\r
     <ClCompile Include="..\runtime\RegExpCache.cpp" />\r
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
   <ImportGroup Label="ExtensionTargets">\r
   </ImportGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r
index bfe00b4..d78954e 100644 (file)
                A7FB60A4103F7DC20017A286 /* PropertyDescriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7FB60A3103F7DC20017A286 /* PropertyDescriptor.cpp */; };
                A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A8A4748E151A8306004123FF /* libWTF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A8A4748D151A8306004123FF /* libWTF.a */; };
+               AD1CF06A16DCAD5B00B97123 /* PropertyTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */; };
                BC02E90D0E1839DB000F9297 /* ErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9050E1839DB000F9297 /* ErrorConstructor.h */; };
                BC02E90F0E1839DB000F9297 /* ErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9070E1839DB000F9297 /* ErrorPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BC02E9110E1839DB000F9297 /* NativeErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9090E1839DB000F9297 /* NativeErrorConstructor.h */; };
                A8A4748D151A8306004123FF /* libWTF.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libWTF.a; sourceTree = BUILT_PRODUCTS_DIR; };
                A8E894310CD0602400367179 /* JSCallbackObjectFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallbackObjectFunctions.h; sourceTree = "<group>"; };
                A8E894330CD0603F00367179 /* JSGlobalObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObject.h; sourceTree = "<group>"; };
+               AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyTable.cpp; sourceTree = "<group>"; };
                BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ToolExecutable.xcconfig; sourceTree = "<group>"; };
                BC02E9040E1839DB000F9297 /* ErrorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorConstructor.cpp; sourceTree = "<group>"; };
                BC02E9050E1839DB000F9297 /* ErrorConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ErrorConstructor.h; sourceTree = "<group>"; };
                                65621E6B089E859700760F35 /* PropertySlot.cpp */,
                                65621E6C089E859700760F35 /* PropertySlot.h */,
                                0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */,
+                               AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */,
                                65C02FBB0637462A003E7EE6 /* Protect.h */,
                                14D844A216AA2C7000A65AF0 /* PrototypeMap.cpp */,
                                14D844A316AA2C7000A65AF0 /* PrototypeMap.h */,
                                0FBE0F7416C1DB090082C5E8 /* DFGPredictionInjectionPhase.cpp in Sources */,
                                0FBE0F7616C1DB0F0082C5E8 /* DFGUnificationPhase.cpp in Sources */,
                                0F493AFA16D0CAD30084508B /* SourceProvider.cpp in Sources */,
+                               AD1CF06A16DCAD5B00B97123 /* PropertyTable.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 58140f6..6608a07 100644 (file)
@@ -298,6 +298,7 @@ SOURCES += \
     runtime/PropertyDescriptor.cpp \
     runtime/PropertyNameArray.cpp \
     runtime/PropertySlot.cpp \
+    runtime/PropertyTable.cpp \
     runtime/PrototypeMap.cpp \
     runtime/RegExpConstructor.cpp \
     runtime/RegExpCachedResult.cpp \
index c06cf5c..508a876 100644 (file)
@@ -232,6 +232,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType)
     unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull()));
     unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull()));
     unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull()));
+    propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull()));
     smallStrings.initializeCommonStrings(*this);
 
     wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
index dc9881f..1895a06 100644 (file)
@@ -256,6 +256,7 @@ namespace JSC {
         Strong<Structure> unlinkedProgramCodeBlockStructure;
         Strong<Structure> unlinkedEvalCodeBlockStructure;
         Strong<Structure> unlinkedFunctionCodeBlockStructure;
+        Strong<Structure> propertyTableStructure;
 
         IdentifierTable* identifierTable;
         CommonIdentifiers* propertyNames;
index 2422c5b..54e2973 100644 (file)
@@ -22,6 +22,7 @@
 #define PropertyMapHashTable_h
 
 #include "PropertyOffset.h"
+#include "Structure.h"
 #include "WriteBarrier.h"
 #include <wtf/HashTable.h>
 #include <wtf/MathExtras.h>
@@ -85,8 +86,7 @@ struct PropertyMapEntry {
     }
 };
 
-class PropertyTable {
-    WTF_MAKE_FAST_ALLOCATED;
+class PropertyTable : public JSCell {
 
     // This is the implementation for 'iterator' and 'const_iterator',
     // used for iterating over the table in insertion order.
@@ -129,6 +129,19 @@ class PropertyTable {
     };
 
 public:
+    static const bool needsDestruction = true;
+    static const bool hasImmortalStructure = true;
+    static void destroy(JSCell*);
+
+    static JS_EXPORTDATA const ClassInfo s_info;
+
+    static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(globalData, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), &s_info);
+    }
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
     typedef StringImpl* KeyType;
     typedef PropertyMapEntry ValueType;
 
@@ -142,9 +155,9 @@ public:
     typedef std::pair<ValueType*, unsigned> find_iterator;
 
     // Constructor is passed an initial capacity, a PropertyTable to copy, or both.
-    explicit PropertyTable(unsigned initialCapacity);
-    PropertyTable(JSGlobalData&, JSCell*, const PropertyTable&);
-    PropertyTable(JSGlobalData&, JSCell*, unsigned initialCapacity, const PropertyTable&);
+    static PropertyTable* create(JSGlobalData&, unsigned initialCapacity);
+    static PropertyTable* clone(JSGlobalData&, JSCell* owner, const PropertyTable&);
+    static PropertyTable* clone(JSGlobalData&, JSCell* owner, unsigned initialCapacity, const PropertyTable&);
     ~PropertyTable();
 
     // Ordered iteration methods.
@@ -181,7 +194,7 @@ public:
     PropertyOffset nextOffset(PropertyOffset inlineCapacity);
 
     // Copy this PropertyTable, ensuring the copy has at least the capacity provided.
-    PassOwnPtr<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity);
+    PropertyTable* copy(JSGlobalData&, JSCell* owner, unsigned newCapacity);
 
 #ifndef NDEBUG
     size_t sizeInMemory();
@@ -189,6 +202,10 @@ public:
 #endif
 
 private:
+    PropertyTable(JSGlobalData&, unsigned initialCapacity);
+    PropertyTable(JSGlobalData&, JSCell*, const PropertyTable&);
+    PropertyTable(JSGlobalData&, JSCell*, 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.
     void reinsert(const ValueType& entry);
@@ -239,72 +256,6 @@ private:
     static const unsigned EmptyEntryIndex = 0;
 };
 
-inline PropertyTable::PropertyTable(unsigned initialCapacity)
-    : m_indexSize(sizeForCapacity(initialCapacity))
-    , m_indexMask(m_indexSize - 1)
-    , m_index(static_cast<unsigned*>(fastZeroedMalloc(dataSize())))
-    , m_keyCount(0)
-    , m_deletedCount(0)
-{
-    ASSERT(isPowerOf2(m_indexSize));
-}
-
-inline PropertyTable::PropertyTable(JSGlobalData&, JSCell* owner, const PropertyTable& other)
-    : m_indexSize(other.m_indexSize)
-    , m_indexMask(other.m_indexMask)
-    , m_index(static_cast<unsigned*>(fastMalloc(dataSize())))
-    , m_keyCount(other.m_keyCount)
-    , m_deletedCount(other.m_deletedCount)
-{
-    ASSERT(isPowerOf2(m_indexSize));
-
-    memcpy(m_index, other.m_index, dataSize());
-
-    iterator end = this->end();
-    for (iterator iter = begin(); iter != end; ++iter) {
-        iter->key->ref();
-        Heap::writeBarrier(owner, iter->specificValue.get());
-    }
-
-    // Copy the m_deletedOffsets vector.
-    Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get();
-    if (otherDeletedOffsets)
-        m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets));
-}
-
-inline PropertyTable::PropertyTable(JSGlobalData&, JSCell* owner, unsigned initialCapacity, const PropertyTable& other)
-    : m_indexSize(sizeForCapacity(initialCapacity))
-    , m_indexMask(m_indexSize - 1)
-    , m_index(static_cast<unsigned*>(fastZeroedMalloc(dataSize())))
-    , m_keyCount(0)
-    , m_deletedCount(0)
-{
-    ASSERT(isPowerOf2(m_indexSize));
-    ASSERT(initialCapacity >= other.m_keyCount);
-
-    const_iterator end = other.end();
-    for (const_iterator iter = other.begin(); iter != end; ++iter) {
-        ASSERT(canInsert());
-        reinsert(*iter);
-        iter->key->ref();
-        Heap::writeBarrier(owner, iter->specificValue.get());
-    }
-
-    // Copy the m_deletedOffsets vector.
-    Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get();
-    if (otherDeletedOffsets)
-        m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets));
-}
-
-inline PropertyTable::~PropertyTable()
-{
-    iterator end = this->end();
-    for (iterator iter = begin(); iter != end; ++iter)
-        iter->key->deref();
-
-    fastFree(m_index);
-}
-
 inline PropertyTable::iterator PropertyTable::begin()
 {
     return iterator(skipDeletedEntries(table()));
@@ -502,15 +453,15 @@ inline PropertyOffset PropertyTable::nextOffset(PropertyOffset inlineCapacity)
     return offsetForPropertyNumber(size(), inlineCapacity);
 }
 
-inline PassOwnPtr<PropertyTable> PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, unsigned newCapacity)
+inline PropertyTable* PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, 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)
-        return adoptPtr(new PropertyTable(globalData, owner, *this));
-    return adoptPtr(new PropertyTable(globalData, owner, newCapacity, *this));
+        return PropertyTable::clone(globalData, owner, *this);
+    return PropertyTable::clone(globalData, owner, newCapacity, *this);
 }
 
 #ifndef NDEBUG
diff --git a/Source/JavaScriptCore/runtime/PropertyTable.cpp b/Source/JavaScriptCore/runtime/PropertyTable.cpp
new file mode 100644 (file)
index 0000000..d24c489
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    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
+ * 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
+ * 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
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "PropertyMapHashTable.h"
+
+#include "JSCellInlines.h"
+
+namespace JSC {
+
+const ClassInfo PropertyTable::s_info = { "PropertyTable", 0, 0, 0, CREATE_METHOD_TABLE(PropertyTable) };
+
+PropertyTable* PropertyTable::create(JSGlobalData& globalData, unsigned initialCapacity)
+{
+    PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(globalData.heap)) PropertyTable(globalData, initialCapacity);
+    table->finishCreation(globalData);
+    return table;
+}
+
+PropertyTable* PropertyTable::clone(JSGlobalData& globalData, JSCell* owner, const PropertyTable& other)
+{
+    PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(globalData.heap)) PropertyTable(globalData, owner, other);
+    table->finishCreation(globalData);
+    return table;
+}
+
+PropertyTable* PropertyTable::clone(JSGlobalData& globalData, JSCell* owner, unsigned initialCapacity, const PropertyTable& other)
+{
+    PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(globalData.heap)) PropertyTable(globalData, owner, initialCapacity, other);
+    table->finishCreation(globalData);
+    return table;
+}
+
+PropertyTable::PropertyTable(JSGlobalData& globalData, unsigned initialCapacity)
+    : JSCell(globalData, globalData.propertyTableStructure.get())
+    , m_indexSize(sizeForCapacity(initialCapacity))
+    , m_indexMask(m_indexSize - 1)
+    , m_index(static_cast<unsigned*>(fastZeroedMalloc(dataSize())))
+    , m_keyCount(0)
+    , m_deletedCount(0)
+{
+    ASSERT(isPowerOf2(m_indexSize));
+}
+
+PropertyTable::PropertyTable(JSGlobalData& globalData, JSCell* owner, const PropertyTable& other)
+    : JSCell(globalData, globalData.propertyTableStructure.get())
+    , m_indexSize(other.m_indexSize)
+    , m_indexMask(other.m_indexMask)
+    , m_index(static_cast<unsigned*>(fastMalloc(dataSize())))
+    , m_keyCount(other.m_keyCount)
+    , m_deletedCount(other.m_deletedCount)
+{
+    ASSERT(isPowerOf2(m_indexSize));
+
+    memcpy(m_index, other.m_index, dataSize());
+
+    iterator end = this->end();
+    for (iterator iter = begin(); iter != end; ++iter) {
+        iter->key->ref();
+        Heap::writeBarrier(owner, iter->specificValue.get());
+    }
+
+    // Copy the m_deletedOffsets vector.
+    Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get();
+    if (otherDeletedOffsets)
+        m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets));
+}
+
+PropertyTable::PropertyTable(JSGlobalData& globalData, JSCell* owner, unsigned initialCapacity, const PropertyTable& other)
+    : JSCell(globalData, globalData.propertyTableStructure.get())
+    , m_indexSize(sizeForCapacity(initialCapacity))
+    , m_indexMask(m_indexSize - 1)
+    , m_index(static_cast<unsigned*>(fastZeroedMalloc(dataSize())))
+    , m_keyCount(0)
+    , m_deletedCount(0)
+{
+    ASSERT(isPowerOf2(m_indexSize));
+    ASSERT(initialCapacity >= other.m_keyCount);
+
+    const_iterator end = other.end();
+    for (const_iterator iter = other.begin(); iter != end; ++iter) {
+        ASSERT(canInsert());
+        reinsert(*iter);
+        iter->key->ref();
+        Heap::writeBarrier(owner, iter->specificValue.get());
+    }
+
+    // Copy the m_deletedOffsets vector.
+    Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get();
+    if (otherDeletedOffsets)
+        m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets));
+}
+
+void PropertyTable::destroy(JSCell* cell)
+{
+    static_cast<PropertyTable*>(cell)->PropertyTable::~PropertyTable();
+}
+
+PropertyTable::~PropertyTable()
+{
+    iterator end = this->end();
+    for (iterator iter = begin(); iter != end; ++iter)
+        iter->key->deref();
+
+    fastFree(m_index);
+}
+
+void PropertyTable::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    PropertyTable* thisObject = jsCast<PropertyTable*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+
+    JSCell::visitChildren(thisObject, visitor);
+
+    PropertyTable::iterator end = thisObject->end();
+    for (PropertyTable::iterator ptr = thisObject->begin(); ptr != end; ++ptr)
+        visitor.append(&ptr->specificValue);
+}
+
+}
index b79c106..fc69a01 100644 (file)
@@ -247,7 +247,7 @@ void Structure::materializePropertyMap(JSGlobalData& globalData)
             ASSERT(structure->m_propertyTable);
             ASSERT(!structure->previousID());
 
-            m_propertyTable = structure->m_propertyTable->copy(globalData, 0, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
+            m_propertyTable.set(globalData, this, structure->m_propertyTable->copy(globalData, 0, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)));
             break;
         }
 
@@ -255,7 +255,7 @@ void Structure::materializePropertyMap(JSGlobalData& globalData)
     }
 
     if (!m_propertyTable)
-        createPropertyMap(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
+        createPropertyMap(globalData, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
 
     for (ptrdiff_t i = structures.size() - 1; i >= 0; --i) {
         structure = structures[i];
@@ -376,14 +376,16 @@ Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure*
     if (structure->m_propertyTable) {
         structure->checkOffsetConsistency();
         if (structure->m_isPinnedPropertyTable)
-            transition->m_propertyTable = structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1);
-        else
-            transition->m_propertyTable = structure->m_propertyTable.release();
+            transition->m_propertyTable.set(globalData, transition, structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1));
+        else {
+            transition->m_propertyTable.set(globalData, transition, structure->m_propertyTable.get());
+            structure->m_propertyTable.clear();
+        }
     } else {
         if (structure->previousID())
             transition->materializePropertyMap(globalData);
         else
-            transition->createPropertyMap();
+            transition->createPropertyMap(globalData);
     }
     transition->m_offset = structure->m_offset;
 
@@ -415,7 +417,7 @@ Structure* Structure::changePrototypeTransition(JSGlobalData& globalData, Struct
     transition->m_prototype.set(globalData, transition, prototype);
 
     structure->materializePropertyMapIfNecessary(globalData);
-    transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+    transition->m_propertyTable.set(globalData, transition, structure->copyPropertyTableForPinning(globalData, transition));
     transition->m_offset = structure->m_offset;
     transition->pin();
 
@@ -431,7 +433,7 @@ Structure* Structure::despecifyFunctionTransition(JSGlobalData& globalData, Stru
     ++transition->m_specificFunctionThrashCount;
 
     structure->materializePropertyMapIfNecessary(globalData);
-    transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+    transition->m_propertyTable.set(globalData, transition, structure->copyPropertyTableForPinning(globalData, transition));
     transition->m_offset = structure->m_offset;
     transition->pin();
 
@@ -452,7 +454,7 @@ Structure* Structure::attributeChangeTransition(JSGlobalData& globalData, Struct
         Structure* transition = create(globalData, structure);
 
         structure->materializePropertyMapIfNecessary(globalData);
-        transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+        transition->m_propertyTable.set(globalData, transition, structure->copyPropertyTableForPinning(globalData, transition));
         transition->m_offset = structure->m_offset;
         transition->pin();
         
@@ -475,7 +477,7 @@ Structure* Structure::toDictionaryTransition(JSGlobalData& globalData, Structure
     Structure* transition = create(globalData, structure);
 
     structure->materializePropertyMapIfNecessary(globalData);
-    transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+    transition->m_propertyTable.set(globalData, transition, structure->copyPropertyTableForPinning(globalData, transition));
     transition->m_offset = structure->m_offset;
     transition->m_dictionaryKind = kind;
     transition->pin();
@@ -535,7 +537,7 @@ Structure* Structure::preventExtensionsTransition(JSGlobalData& globalData, Stru
     // Don't set m_offset, as one can not transition to this.
 
     structure->materializePropertyMapIfNecessary(globalData);
-    transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+    transition->m_propertyTable.set(globalData, transition, structure->copyPropertyTableForPinning(globalData, transition));
     transition->m_offset = structure->m_offset;
     transition->m_preventExtensions = true;
     transition->pin();
@@ -575,14 +577,16 @@ Structure* Structure::nonPropertyTransition(JSGlobalData& globalData, Structure*
     if (structure->m_propertyTable) {
         structure->checkOffsetConsistency();
         if (structure->m_isPinnedPropertyTable)
-            transition->m_propertyTable = structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1);
-        else
-            transition->m_propertyTable = structure->m_propertyTable.release();
+            transition->m_propertyTable.set(globalData, transition, structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1));
+        else {
+            transition->m_propertyTable.set(globalData, transition, structure->m_propertyTable.get());
+            structure->m_propertyTable.clear();
+        }
     } else {
         if (structure->previousID())
             transition->materializePropertyMap(globalData);
         else
-            transition->createPropertyMap();
+            transition->createPropertyMap(globalData);
     }
     
     structure->m_transitionTable.add(globalData, transition);
@@ -737,14 +741,18 @@ inline void Structure::checkConsistency()
 
 #endif
 
-PassOwnPtr<PropertyTable> Structure::copyPropertyTable(JSGlobalData& globalData, Structure* owner)
+PropertyTable* Structure::copyPropertyTable(JSGlobalData& globalData, Structure* owner)
 {
-    return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : 0);
+    if (!m_propertyTable)
+        return 0;
+    return PropertyTable::clone(globalData, owner, *m_propertyTable.get());
 }
 
-PassOwnPtr<PropertyTable> Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner)
+PropertyTable* Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner)
 {
-    return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)));
+    if (m_propertyTable)
+        return PropertyTable::clone(globalData, owner, *m_propertyTable.get());
+    return PropertyTable::create(globalData, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
 }
 
 PropertyOffset Structure::get(JSGlobalData& globalData, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue)
@@ -801,7 +809,7 @@ PropertyOffset Structure::putSpecificValue(JSGlobalData& globalData, PropertyNam
     StringImpl* rep = propertyName.uid();
 
     if (!m_propertyTable)
-        createPropertyMap();
+        createPropertyMap(globalData);
 
     PropertyOffset newOffset = m_propertyTable->nextOffset(m_inlineCapacity);
 
@@ -833,12 +841,12 @@ PropertyOffset Structure::remove(PropertyName propertyName)
     return offset;
 }
 
-void Structure::createPropertyMap(unsigned capacity)
+void Structure::createPropertyMap(JSGlobalData& globalData, unsigned capacity)
 {
     ASSERT(!m_propertyTable);
 
     checkConsistency();
-    m_propertyTable = adoptPtr(new PropertyTable(capacity));
+    m_propertyTable.set(globalData, this, PropertyTable::create(globalData, capacity));
 }
 
 void Structure::getPropertyNamesFromStructure(JSGlobalData& globalData, PropertyNameArray& propertyNames, EnumerationMode mode)
@@ -882,11 +890,12 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
     }
     visitor.append(&thisObject->m_previousOrRareData);
     visitor.append(&thisObject->m_specificValueInPrevious);
-    if (thisObject->m_propertyTable) {
-        PropertyTable::iterator end = thisObject->m_propertyTable->end();
-        for (PropertyTable::iterator ptr = thisObject->m_propertyTable->begin(); ptr != end; ++ptr)
-            visitor.append(&ptr->specificValue);
-    }
+
+    if (thisObject->m_isPinnedPropertyTable) {
+        ASSERT(thisObject->m_propertyTable);
+        visitor.append(&thisObject->m_propertyTable);
+    } else if (thisObject->m_propertyTable)
+        thisObject->m_propertyTable.clear();
 }
 
 bool Structure::prototypeChainMayInterceptStoreTo(JSGlobalData& globalData, PropertyName propertyName)
index 2359c6c..6b1d08e 100644 (file)
 #include "JSCJSValue.h"
 #include "JSCell.h"
 #include "JSType.h"
-#include "PropertyMapHashTable.h"
 #include "PropertyName.h"
 #include "PropertyNameArray.h"
+#include "PropertyOffset.h"
 #include "Protect.h"
 #include "StructureRareData.h"
 #include "StructureTransitionTable.h"
 #include "JSTypeInfo.h"
 #include "Watchpoint.h"
 #include "Weak.h"
-#include <wtf/PassOwnPtr.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 #include <wtf/text/StringImpl.h>
@@ -51,6 +50,7 @@ namespace JSC {
 class LLIntOffsetsExtractor;
 class PropertyNameArray;
 class PropertyNameArrayData;
+class PropertyTable;
 class StructureChain;
 class SlotVisitor;
 class JSString;
@@ -108,25 +108,7 @@ public:
     bool isFrozen(JSGlobalData&);
     bool isExtensible() const { return !m_preventExtensions; }
     bool didTransition() const { return m_didTransition; }
-    bool putWillGrowOutOfLineStorage()
-    {
-        checkOffsetConsistency();
-            
-        ASSERT(outOfLineCapacity() >= outOfLineSize());
-            
-        if (!m_propertyTable) {
-            unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset);
-            ASSERT(outOfLineCapacity() >= currentSize);
-            return currentSize == outOfLineCapacity();
-        }
-            
-        ASSERT(totalStorageCapacity() >= m_propertyTable->propertyStorageSize());
-        if (m_propertyTable->hasDeletedOffset())
-            return false;
-            
-        ASSERT(totalStorageCapacity() >= m_propertyTable->size());
-        return m_propertyTable->size() == totalStorageCapacity();
-    }
+    bool putWillGrowOutOfLineStorage();
     JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity(); 
 
     Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
@@ -382,14 +364,14 @@ private:
     PropertyOffset putSpecificValue(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue);
     PropertyOffset remove(PropertyName);
 
-    void createPropertyMap(unsigned keyCount = 0);
+    void createPropertyMap(JSGlobalData&, unsigned keyCount = 0);
     void checkConsistency();
 
     bool despecifyFunction(JSGlobalData&, PropertyName);
     void despecifyAllFunctions(JSGlobalData&);
 
-    PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
-    PassOwnPtr<PropertyTable> copyPropertyTableForPinning(JSGlobalData&, Structure* owner);
+    PropertyTable* copyPropertyTable(JSGlobalData&, Structure* owner);
+    PropertyTable* copyPropertyTableForPinning(JSGlobalData&, Structure* owner);
     JS_EXPORT_PRIVATE void materializePropertyMap(JSGlobalData&);
     void materializePropertyMapIfNecessary(JSGlobalData& globalData)
     {
@@ -445,19 +427,7 @@ private:
         return static_cast<StructureRareData*>(m_previousOrRareData.get());
     }
         
-    ALWAYS_INLINE bool checkOffsetConsistency() const
-    {
-        if (!m_propertyTable) {
-            ASSERT(!m_isPinnedPropertyTable);
-            return true;
-        }
-            
-        RELEASE_ASSERT(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity) == m_propertyTable->propertyStorageSize());
-        unsigned totalSize = m_propertyTable->propertyStorageSize();
-        RELEASE_ASSERT((totalSize < inlineCapacity() ? 0 : totalSize - inlineCapacity()) == numberOfOutOfLineSlotsForLastOffset(m_offset));
-            
-        return true;
-    }
+    ALWAYS_INLINE bool checkOffsetConsistency() const;
 
     void allocateRareData(JSGlobalData&);
     void cloneRareDataFrom(JSGlobalData&, const Structure*);
@@ -482,7 +452,7 @@ private:
 
     StructureTransitionTable m_transitionTable;
 
-    OwnPtr<PropertyTable> m_propertyTable;
+    WriteBarrier<PropertyTable> m_propertyTable;
 
     mutable InlineWatchpointSet m_transitionWatchpointSet;
 
index 5bfd2d5..aac8064 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef StructureInlines_h
 #define StructureInlines_h
 
+#include "PropertyMapHashTable.h"
 #include "Structure.h"
 
 namespace JSC {
@@ -179,6 +180,40 @@ inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeC
     return isValid(exec->lexicalGlobalObject(), cachedPrototypeChain);
 }
 
+inline bool Structure::putWillGrowOutOfLineStorage()
+{
+    checkOffsetConsistency();
+
+    ASSERT(outOfLineCapacity() >= outOfLineSize());
+
+    if (!m_propertyTable) {
+        unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset);
+        ASSERT(outOfLineCapacity() >= currentSize);
+        return currentSize == outOfLineCapacity();
+    }
+
+    ASSERT(totalStorageCapacity() >= m_propertyTable->propertyStorageSize());
+    if (m_propertyTable->hasDeletedOffset())
+        return false;
+
+    ASSERT(totalStorageCapacity() >= m_propertyTable->size());
+    return m_propertyTable->size() == totalStorageCapacity();
+}
+
+inline bool Structure::checkOffsetConsistency() const
+{
+    if (!m_propertyTable) {
+        ASSERT(!m_isPinnedPropertyTable);
+        return true;
+    }
+
+    RELEASE_ASSERT(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity) == m_propertyTable->propertyStorageSize());
+    unsigned totalSize = m_propertyTable->propertyStorageSize();
+    RELEASE_ASSERT((totalSize < inlineCapacity() ? 0 : totalSize - inlineCapacity()) == numberOfOutOfLineSlotsForLastOffset(m_offset));
+
+    return true;
+}
+
 } // namespace JSC
 
 #endif // StructureInlines_h