Changeset 144910 in webkit


Ignore:
Timestamp:
Mar 6, 2013 4:52:16 AM (11 years ago)
Author:
akling@apple.com
Message:

Unused Structure property tables waste 14MB on Membuster.
<http://webkit.org/b/110854>
<rdar://problem/13292104>

Reviewed by Geoffrey Garen.

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

This time it should stick; I've been through all the tests with COLLECT_ON_EVERY_ALLOCATION.
The issue with the last version was that Structure::m_offset could be used uninitialized
when re-materializing a previously GC'd property table, causing some sanity checks to fail.

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/WriteBarrier.h:

(JSC::WriteBarrierBase::get):

Move m_cell to a local before using it multiple times. This avoids a multiple-access race when
Structure::checkOffsetConsistency() is used in assertions on the main thread while a marking thread
zaps the property table.

  • runtime/Structure.h:

(JSC::Structure::materializePropertyMapIfNecessary):
(JSC::Structure::materializePropertyMapIfNecessaryForPinning):

  • runtime/StructureInlines.h:

(JSC::Structure::propertyTable):

Added a getter for the Structure's PropertyTable that ASSERTs GC currently isn't active.
Because GC can zap an unpinned property table at any time, it's not entirely safe to access it.
Renamed the variable itself to m_propertyTableUnsafe to force call sites into explaining themselves.

(JSC::Structure::putWillGrowOutOfLineStorage):
(JSC::Structure::checkOffsetConsistency):

Moved these out of Structure.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::takePropertyTableOrCloneIfPinned):

Added for setting up the property table in a new transition, this code is now shared between
addPropertyTransition() and nonPropertyTransition().

  • runtime/JSGlobalData.h:
  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):

Add a global propertyTableStructure.

  • runtime/PropertyMapHashTable.h:

(PropertyTable):
(JSC::PropertyTable::createStructure):
(JSC::PropertyTable::copy):

Make PropertyTable a GC object.

  • runtime/Structure.cpp:

(JSC::Structure::dumpStatistics):
(JSC::Structure::materializePropertyMap):
(JSC::Structure::despecifyDictionaryFunction):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::changePrototypeTransition):
(JSC::Structure::despecifyFunctionTransition):
(JSC::Structure::attributeChangeTransition):
(JSC::Structure::toDictionaryTransition):
(JSC::Structure::sealTransition):
(JSC::Structure::freezeTransition):
(JSC::Structure::preventExtensionsTransition):
(JSC::Structure::nonPropertyTransition):
(JSC::Structure::isSealed):
(JSC::Structure::isFrozen):
(JSC::Structure::flattenDictionaryStructure):
(JSC::Structure::pin):
(JSC::Structure::copyPropertyTable):
(JSC::Structure::copyPropertyTableForPinning):
(JSC::Structure::get):
(JSC::Structure::despecifyFunction):
(JSC::Structure::despecifyAllFunctions):
(JSC::Structure::putSpecificValue):
(JSC::Structure::remove):
(JSC::Structure::createPropertyMap):
(JSC::Structure::getPropertyNamesFromStructure):
(JSC::Structure::checkConsistency):

Location:
trunk/Source/JavaScriptCore
Files:
1 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r144862 r144910  
    282282    runtime/PropertyNameArray.cpp
    283283    runtime/PropertySlot.cpp
     284    runtime/PropertyTable.cpp
    284285    runtime/PrototypeMap.cpp
    285286    runtime/RegExp.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r144886 r144910  
     12013-03-06  Andreas Kling  <akling@apple.com>
     2
     3        Unused Structure property tables waste 14MB on Membuster.
     4        <http://webkit.org/b/110854>
     5        <rdar://problem/13292104>
     6
     7        Reviewed by Geoffrey Garen.
     8
     9        Turn PropertyTable into a GC object and have Structure drop unpinned tables when marking.
     10        14 MB progression on Membuster3.
     11
     12        This time it should stick; I've been through all the tests with COLLECT_ON_EVERY_ALLOCATION.
     13        The issue with the last version was that Structure::m_offset could be used uninitialized
     14        when re-materializing a previously GC'd property table, causing some sanity checks to fail.
     15
     16        * CMakeLists.txt:
     17        * GNUmakefile.list.am:
     18        * JavaScriptCore.gypi:
     19        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
     20        * JavaScriptCore.xcodeproj/project.pbxproj:
     21        * Target.pri:
     22
     23            Added PropertyTable.cpp.
     24
     25        * runtime/PropertyTable.cpp: Added.
     26        (JSC::PropertyTable::create):
     27        (JSC::PropertyTable::clone):
     28        (JSC::PropertyTable::PropertyTable):
     29        (JSC::PropertyTable::destroy):
     30        (JSC::PropertyTable::~PropertyTable):
     31        (JSC::PropertyTable::visitChildren):
     32
     33            Moved marking of property table values here from Structure::visitChildren().
     34
     35        * runtime/WriteBarrier.h:
     36        (JSC::WriteBarrierBase::get):
     37
     38            Move m_cell to a local before using it multiple times. This avoids a multiple-access race when
     39            Structure::checkOffsetConsistency() is used in assertions on the main thread while a marking thread
     40            zaps the property table.
     41
     42        * runtime/Structure.h:
     43        (JSC::Structure::materializePropertyMapIfNecessary):
     44        (JSC::Structure::materializePropertyMapIfNecessaryForPinning):
     45        * runtime/StructureInlines.h:
     46        (JSC::Structure::propertyTable):
     47
     48            Added a getter for the Structure's PropertyTable that ASSERTs GC currently isn't active.
     49            Because GC can zap an unpinned property table at any time, it's not entirely safe to access it.
     50            Renamed the variable itself to m_propertyTableUnsafe to force call sites into explaining themselves.
     51
     52        (JSC::Structure::putWillGrowOutOfLineStorage):
     53        (JSC::Structure::checkOffsetConsistency):
     54
     55            Moved these out of Structure.h to break header dependency cycle between Structure/PropertyTable.
     56
     57        * runtime/Structure.cpp:
     58        (JSC::Structure::visitChildren):
     59
     60            Null out m_propertyTable if the table is unpinned. This'll cause the table to get GC'd.
     61
     62        (JSC::Structure::takePropertyTableOrCloneIfPinned):
     63
     64            Added for setting up the property table in a new transition, this code is now shared between
     65            addPropertyTransition() and nonPropertyTransition().
     66
     67        * runtime/JSGlobalData.h:
     68        * runtime/JSGlobalData.cpp:
     69        (JSC::JSGlobalData::JSGlobalData):
     70
     71            Add a global propertyTableStructure.
     72
     73        * runtime/PropertyMapHashTable.h:
     74        (PropertyTable):
     75        (JSC::PropertyTable::createStructure):
     76        (JSC::PropertyTable::copy):
     77
     78            Make PropertyTable a GC object.
     79
     80        * runtime/Structure.cpp:
     81        (JSC::Structure::dumpStatistics):
     82        (JSC::Structure::materializePropertyMap):
     83        (JSC::Structure::despecifyDictionaryFunction):
     84        (JSC::Structure::addPropertyTransition):
     85        (JSC::Structure::changePrototypeTransition):
     86        (JSC::Structure::despecifyFunctionTransition):
     87        (JSC::Structure::attributeChangeTransition):
     88        (JSC::Structure::toDictionaryTransition):
     89        (JSC::Structure::sealTransition):
     90        (JSC::Structure::freezeTransition):
     91        (JSC::Structure::preventExtensionsTransition):
     92        (JSC::Structure::nonPropertyTransition):
     93        (JSC::Structure::isSealed):
     94        (JSC::Structure::isFrozen):
     95        (JSC::Structure::flattenDictionaryStructure):
     96        (JSC::Structure::pin):
     97        (JSC::Structure::copyPropertyTable):
     98        (JSC::Structure::copyPropertyTableForPinning):
     99        (JSC::Structure::get):
     100        (JSC::Structure::despecifyFunction):
     101        (JSC::Structure::despecifyAllFunctions):
     102        (JSC::Structure::putSpecificValue):
     103        (JSC::Structure::remove):
     104        (JSC::Structure::createPropertyMap):
     105        (JSC::Structure::getPropertyNamesFromStructure):
     106        (JSC::Structure::checkConsistency):
     107
    11082013-03-05  Filip Pizlo  <fpizlo@apple.com>
    2109
  • trunk/Source/JavaScriptCore/GNUmakefile.list.am

    r144862 r144910  
    725725        Source/JavaScriptCore/runtime/PropertySlot.cpp \
    726726        Source/JavaScriptCore/runtime/PropertySlot.h \
     727        Source/JavaScriptCore/runtime/PropertyTable.cpp \
    727728        Source/JavaScriptCore/runtime/PrototypeMap.cpp \
    728729        Source/JavaScriptCore/runtime/PrototypeMap.h \
  • trunk/Source/JavaScriptCore/JavaScriptCore.gypi

    r144767 r144910  
    759759            'runtime/PropertySlot.cpp',
    760760            'runtime/PropertySlot.h',
     761            'runtime/PropertyTable.cpp',
    761762            'runtime/PropertyStorage.h',
    762763            'runtime/Protect.h',
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj

    r144767 r144910  
    306306    <ClCompile Include="..\runtime\PropertyNameArray.cpp" />
    307307    <ClCompile Include="..\runtime\PropertySlot.cpp" />
     308    <ClCompile Include="..\runtime\PropertyTable.cpp" />
    308309    <ClCompile Include="..\runtime\PrototypeMap.cpp" />
    309310    <ClCompile Include="..\runtime\RegExp.cpp" />
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r144862 r144910  
    706706                A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; };
    707707                A8A4748E151A8306004123FF /* libWTF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A8A4748D151A8306004123FF /* libWTF.a */; };
     708                ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */; };
    708709                BC02E90D0E1839DB000F9297 /* ErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9050E1839DB000F9297 /* ErrorConstructor.h */; };
    709710                BC02E90F0E1839DB000F9297 /* ErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9070E1839DB000F9297 /* ErrorPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    16231624                A8E894310CD0602400367179 /* JSCallbackObjectFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallbackObjectFunctions.h; sourceTree = "<group>"; };
    16241625                A8E894330CD0603F00367179 /* JSGlobalObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObject.h; sourceTree = "<group>"; };
     1626                AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyTable.cpp; sourceTree = "<group>"; };
    16251627                BC021BF2136900C300FC5467 /* ToolExecutable.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ToolExecutable.xcconfig; sourceTree = "<group>"; };
    16261628                BC02E9040E1839DB000F9297 /* ErrorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorConstructor.cpp; sourceTree = "<group>"; };
     
    25112513                                65621E6C089E859700760F35 /* PropertySlot.h */,
    25122514                                0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */,
     2515                                AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */,
    25132516                                65C02FBB0637462A003E7EE6 /* Protect.h */,
    25142517                                14D844A216AA2C7000A65AF0 /* PrototypeMap.cpp */,
     
    40324035                                0FBE0F7616C1DB0F0082C5E8 /* DFGUnificationPhase.cpp in Sources */,
    40334036                                0F493AFA16D0CAD30084508B /* SourceProvider.cpp in Sources */,
     4037                                ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */,
    40344038                        );
    40354039                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/Source/JavaScriptCore/Target.pri

    r144862 r144910  
    300300    runtime/PropertyNameArray.cpp \
    301301    runtime/PropertySlot.cpp \
     302    runtime/PropertyTable.cpp \
    302303    runtime/PrototypeMap.cpp \
    303304    runtime/RegExpConstructor.cpp \
  • trunk/Source/JavaScriptCore/runtime/JSGlobalData.cpp

    r144767 r144910  
    233233    unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull()));
    234234    unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull()));
     235    propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull()));
    235236    smallStrings.initializeCommonStrings(*this);
    236237
  • trunk/Source/JavaScriptCore/runtime/JSGlobalData.h

    r144767 r144910  
    257257        Strong<Structure> unlinkedEvalCodeBlockStructure;
    258258        Strong<Structure> unlinkedFunctionCodeBlockStructure;
     259        Strong<Structure> propertyTableStructure;
    259260
    260261        IdentifierTable* identifierTable;
  • trunk/Source/JavaScriptCore/runtime/PropertyMapHashTable.h

    r144767 r144910  
    2323
    2424#include "PropertyOffset.h"
     25#include "Structure.h"
    2526#include "WriteBarrier.h"
    2627#include <wtf/HashTable.h>
     
    8687};
    8788
    88 class PropertyTable {
    89     WTF_MAKE_FAST_ALLOCATED;
     89class PropertyTable : public JSCell {
    9090
    9191    // This is the implementation for 'iterator' and 'const_iterator',
     
    130130
    131131public:
     132    static const bool needsDestruction = true;
     133    static const bool hasImmortalStructure = true;
     134    static void destroy(JSCell*);
     135
     136    static JS_EXPORTDATA const ClassInfo s_info;
     137
     138    static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
     139    {
     140        return Structure::create(globalData, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), &s_info);
     141    }
     142
     143    static void visitChildren(JSCell*, SlotVisitor&);
     144
    132145    typedef StringImpl* KeyType;
    133146    typedef PropertyMapEntry ValueType;
     
    143156
    144157    // Constructor is passed an initial capacity, a PropertyTable to copy, or both.
    145     explicit PropertyTable(unsigned initialCapacity);
    146     PropertyTable(JSGlobalData&, JSCell*, const PropertyTable&);
    147     PropertyTable(JSGlobalData&, JSCell*, unsigned initialCapacity, const PropertyTable&);
     158    static PropertyTable* create(JSGlobalData&, unsigned initialCapacity);
     159    static PropertyTable* clone(JSGlobalData&, JSCell* owner, const PropertyTable&);
     160    static PropertyTable* clone(JSGlobalData&, JSCell* owner, unsigned initialCapacity, const PropertyTable&);
    148161    ~PropertyTable();
    149162
     
    182195
    183196    // Copy this PropertyTable, ensuring the copy has at least the capacity provided.
    184     PassOwnPtr<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity);
     197    PropertyTable* copy(JSGlobalData&, JSCell* owner, unsigned newCapacity);
    185198
    186199#ifndef NDEBUG
     
    190203
    191204private:
     205    PropertyTable(JSGlobalData&, unsigned initialCapacity);
     206    PropertyTable(JSGlobalData&, JSCell*, const PropertyTable&);
     207    PropertyTable(JSGlobalData&, JSCell*, unsigned initialCapacity, const PropertyTable&);
     208
    192209    PropertyTable(const PropertyTable&);
    193210    // Used to insert a value known not to be in the table, and where we know capacity to be available.
     
    240257};
    241258
    242 inline PropertyTable::PropertyTable(unsigned initialCapacity)
    243     : m_indexSize(sizeForCapacity(initialCapacity))
    244     , m_indexMask(m_indexSize - 1)
    245     , m_index(static_cast<unsigned*>(fastZeroedMalloc(dataSize())))
    246     , m_keyCount(0)
    247     , m_deletedCount(0)
    248 {
    249     ASSERT(isPowerOf2(m_indexSize));
    250 }
    251 
    252 inline PropertyTable::PropertyTable(JSGlobalData&, JSCell* owner, const PropertyTable& other)
    253     : m_indexSize(other.m_indexSize)
    254     , m_indexMask(other.m_indexMask)
    255     , m_index(static_cast<unsigned*>(fastMalloc(dataSize())))
    256     , m_keyCount(other.m_keyCount)
    257     , m_deletedCount(other.m_deletedCount)
    258 {
    259     ASSERT(isPowerOf2(m_indexSize));
    260 
    261     memcpy(m_index, other.m_index, dataSize());
    262 
    263     iterator end = this->end();
    264     for (iterator iter = begin(); iter != end; ++iter) {
    265         iter->key->ref();
    266         Heap::writeBarrier(owner, iter->specificValue.get());
    267     }
    268 
    269     // Copy the m_deletedOffsets vector.
    270     Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get();
    271     if (otherDeletedOffsets)
    272         m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets));
    273 }
    274 
    275 inline PropertyTable::PropertyTable(JSGlobalData&, JSCell* owner, unsigned initialCapacity, const PropertyTable& other)
    276     : m_indexSize(sizeForCapacity(initialCapacity))
    277     , m_indexMask(m_indexSize - 1)
    278     , m_index(static_cast<unsigned*>(fastZeroedMalloc(dataSize())))
    279     , m_keyCount(0)
    280     , m_deletedCount(0)
    281 {
    282     ASSERT(isPowerOf2(m_indexSize));
    283     ASSERT(initialCapacity >= other.m_keyCount);
    284 
    285     const_iterator end = other.end();
    286     for (const_iterator iter = other.begin(); iter != end; ++iter) {
    287         ASSERT(canInsert());
    288         reinsert(*iter);
    289         iter->key->ref();
    290         Heap::writeBarrier(owner, iter->specificValue.get());
    291     }
    292 
    293     // Copy the m_deletedOffsets vector.
    294     Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get();
    295     if (otherDeletedOffsets)
    296         m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets));
    297 }
    298 
    299 inline PropertyTable::~PropertyTable()
    300 {
    301     iterator end = this->end();
    302     for (iterator iter = begin(); iter != end; ++iter)
    303         iter->key->deref();
    304 
    305     fastFree(m_index);
    306 }
    307 
    308259inline PropertyTable::iterator PropertyTable::begin()
    309260{
     
    503454}
    504455
    505 inline PassOwnPtr<PropertyTable> PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, unsigned newCapacity)
     456inline PropertyTable* PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, unsigned newCapacity)
    506457{
    507458    ASSERT(newCapacity >= m_keyCount);
     
    510461    // save rehashing all keys.
    511462    if (sizeForCapacity(newCapacity) == m_indexSize)
    512         return adoptPtr(new PropertyTable(globalData, owner, *this));
    513     return adoptPtr(new PropertyTable(globalData, owner, newCapacity, *this));
     463        return PropertyTable::clone(globalData, owner, *this);
     464    return PropertyTable::clone(globalData, owner, newCapacity, *this);
    514465}
    515466
  • trunk/Source/JavaScriptCore/runtime/Structure.cpp

    r144767 r144910  
    132132        }
    133133
    134         if (structure->m_propertyTable) {
     134        if (structure->propertyTable()) {
    135135            ++numberWithPropertyMaps;
    136             totalPropertyMapsSize += structure->m_propertyTable->sizeInMemory();
     136            totalPropertyMapsSize += structure->propertyTable()->sizeInMemory();
    137137        }
    138138    }
     
    235235{
    236236    ASSERT(structure()->classInfo() == &s_info);
    237     ASSERT(!m_propertyTable);
     237    ASSERT(!propertyTable());
    238238
    239239    Vector<Structure*, 8> structures;
     
    245245    while ((structure = structure->previousID())) {
    246246        if (structure->m_isPinnedPropertyTable) {
    247             ASSERT(structure->m_propertyTable);
     247            ASSERT(structure->propertyTable());
    248248            ASSERT(!structure->previousID());
    249249
    250             m_propertyTable = structure->m_propertyTable->copy(globalData, 0, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
     250            propertyTable().set(globalData, this, structure->propertyTable()->copy(globalData, 0, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)));
    251251            break;
    252252        }
     
    255255    }
    256256
    257     if (!m_propertyTable)
    258         createPropertyMap(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
     257    if (!propertyTable())
     258        createPropertyMap(globalData, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
    259259
    260260    for (ptrdiff_t i = structures.size() - 1; i >= 0; --i) {
     
    263263            continue;
    264264        PropertyMapEntry entry(globalData, this, structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get());
    265         m_propertyTable->add(entry, m_offset, PropertyTable::PropertyOffsetMustNotChange);
     265        propertyTable()->add(entry, m_offset, PropertyTable::PropertyOffsetMustNotChange);
    266266    }
    267267   
     
    288288
    289289    ASSERT(isDictionary());
    290     ASSERT(m_propertyTable);
    291 
    292     PropertyMapEntry* entry = m_propertyTable->find(rep).first;
     290    ASSERT(propertyTable());
     291
     292    PropertyMapEntry* entry = propertyTable()->find(rep).first;
    293293    ASSERT(entry);
    294294    entry->specificValue.clear();
     
    373373    transition->m_attributesInPrevious = attributes;
    374374    transition->m_specificValueInPrevious.setMayBeNull(globalData, transition, specificValue);
    375 
    376     if (structure->m_propertyTable) {
    377         structure->checkOffsetConsistency();
    378         if (structure->m_isPinnedPropertyTable)
    379             transition->m_propertyTable = structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1);
    380         else
    381             transition->m_propertyTable = structure->m_propertyTable.release();
    382     } else {
    383         if (structure->previousID())
    384             transition->materializePropertyMap(globalData);
    385         else
    386             transition->createPropertyMap();
    387     }
     375    transition->propertyTable().set(globalData, transition, structure->takePropertyTableOrCloneIfPinned(globalData, transition));
    388376    transition->m_offset = structure->m_offset;
    389377
     
    416404
    417405    structure->materializePropertyMapIfNecessary(globalData);
    418     transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
     406    transition->propertyTable().set(globalData, transition, structure->copyPropertyTableForPinning(globalData, transition));
    419407    transition->m_offset = structure->m_offset;
    420408    transition->pin();
     
    432420
    433421    structure->materializePropertyMapIfNecessary(globalData);
    434     transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
     422    transition->propertyTable().set(globalData, transition, structure->copyPropertyTableForPinning(globalData, transition));
    435423    transition->m_offset = structure->m_offset;
    436424    transition->pin();
     
    453441
    454442        structure->materializePropertyMapIfNecessary(globalData);
    455         transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
     443        transition->propertyTable().set(globalData, transition, structure->copyPropertyTableForPinning(globalData, transition));
    456444        transition->m_offset = structure->m_offset;
    457445        transition->pin();
     
    460448    }
    461449
    462     ASSERT(structure->m_propertyTable);
    463     PropertyMapEntry* entry = structure->m_propertyTable->find(propertyName.uid()).first;
     450    ASSERT(structure->propertyTable());
     451    PropertyMapEntry* entry = structure->propertyTable()->find(propertyName.uid()).first;
    464452    ASSERT(entry);
    465453    entry->attributes = attributes;
     
    476464
    477465    structure->materializePropertyMapIfNecessary(globalData);
    478     transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
     466    transition->propertyTable().set(globalData, transition, structure->copyPropertyTableForPinning(globalData, transition));
    479467    transition->m_offset = structure->m_offset;
    480468    transition->m_dictionaryKind = kind;
     
    500488    Structure* transition = preventExtensionsTransition(globalData, structure);
    501489
    502     if (transition->m_propertyTable) {
    503         PropertyTable::iterator end = transition->m_propertyTable->end();
    504         for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter)
     490    if (transition->propertyTable()) {
     491        PropertyTable::iterator end = transition->propertyTable()->end();
     492        for (PropertyTable::iterator iter = transition->propertyTable()->begin(); iter != end; ++iter)
    505493            iter->attributes |= DontDelete;
    506494    }
     
    515503    Structure* transition = preventExtensionsTransition(globalData, structure);
    516504
    517     if (transition->m_propertyTable) {
    518         PropertyTable::iterator iter = transition->m_propertyTable->begin();
    519         PropertyTable::iterator end = transition->m_propertyTable->end();
     505    if (transition->propertyTable()) {
     506        PropertyTable::iterator iter = transition->propertyTable()->begin();
     507        PropertyTable::iterator end = transition->propertyTable()->end();
    520508        if (iter != end)
    521509            transition->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
     
    536524
    537525    structure->materializePropertyMapIfNecessary(globalData);
    538     transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
     526    transition->propertyTable().set(globalData, transition, structure->copyPropertyTableForPinning(globalData, transition));
    539527    transition->m_offset = structure->m_offset;
    540528    transition->m_preventExtensions = true;
     
    543531    transition->checkOffsetConsistency();
    544532    return transition;
     533}
     534
     535PropertyTable* Structure::takePropertyTableOrCloneIfPinned(JSGlobalData& globalData, Structure* owner)
     536{
     537    materializePropertyMapIfNecessaryForPinning(globalData);
     538    if (m_isPinnedPropertyTable)
     539        return propertyTable()->copy(globalData, owner, propertyTable()->size() + 1);
     540    PropertyTable* takenPropertyTable = propertyTable().get();
     541    propertyTable().clear();
     542    return takenPropertyTable;
    545543}
    546544
     
    570568    transition->m_attributesInPrevious = attributes;
    571569    transition->m_indexingType = indexingType;
     570    transition->propertyTable().set(globalData, transition, structure->takePropertyTableOrCloneIfPinned(globalData, transition));
    572571    transition->m_offset = structure->m_offset;
    573572    checkOffset(transition->m_offset, transition->inlineCapacity());
    574    
    575     if (structure->m_propertyTable) {
    576         structure->checkOffsetConsistency();
    577         if (structure->m_isPinnedPropertyTable)
    578             transition->m_propertyTable = structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1);
    579         else
    580             transition->m_propertyTable = structure->m_propertyTable.release();
    581     } else {
    582         if (structure->previousID())
    583             transition->materializePropertyMap(globalData);
    584         else
    585             transition->createPropertyMap();
    586     }
    587573   
    588574    structure->m_transitionTable.add(globalData, transition);
     
    598584
    599585    materializePropertyMapIfNecessary(globalData);
    600     if (!m_propertyTable)
     586    if (!propertyTable())
    601587        return true;
    602588
    603     PropertyTable::iterator end = m_propertyTable->end();
    604     for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
     589    PropertyTable::iterator end = propertyTable()->end();
     590    for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
    605591        if ((iter->attributes & DontDelete) != DontDelete)
    606592            return false;
     
    616602
    617603    materializePropertyMapIfNecessary(globalData);
    618     if (!m_propertyTable)
     604    if (!propertyTable())
    619605        return true;
    620606
    621     PropertyTable::iterator end = m_propertyTable->end();
    622     for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
     607    PropertyTable::iterator end = propertyTable()->end();
     608    for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
    623609        if (!(iter->attributes & DontDelete))
    624610            return false;
     
    634620    ASSERT(isDictionary());
    635621    if (isUncacheableDictionary()) {
    636         ASSERT(m_propertyTable);
    637 
    638         size_t propertyCount = m_propertyTable->size();
     622        ASSERT(propertyTable());
     623
     624        size_t propertyCount = propertyTable()->size();
    639625
    640626        // Holds our values compacted by insertion order.
     
    643629        // Copies out our values from their hashed locations, compacting property table offsets as we go.
    644630        unsigned i = 0;
    645         PropertyTable::iterator end = m_propertyTable->end();
     631        PropertyTable::iterator end = propertyTable()->end();
    646632        m_offset = invalidOffset;
    647         for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) {
     633        for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter, ++i) {
    648634            values[i] = object->getDirect(iter->offset);
    649635            m_offset = iter->offset = offsetForPropertyNumber(i, m_inlineCapacity);
     
    654640            object->putDirect(globalData, offsetForPropertyNumber(i, m_inlineCapacity), values[i]);
    655641
    656         m_propertyTable->clearDeletedOffsets();
     642        propertyTable()->clearDeletedOffsets();
    657643        checkOffsetConsistency();
    658644    }
     
    689675void Structure::pin()
    690676{
    691     ASSERT(m_propertyTable);
     677    ASSERT(propertyTable());
    692678    m_isPinnedPropertyTable = true;
    693679    clearPreviousID();
     
    738724#endif
    739725
    740 PassOwnPtr<PropertyTable> Structure::copyPropertyTable(JSGlobalData& globalData, Structure* owner)
    741 {
    742     return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : 0);
    743 }
    744 
    745 PassOwnPtr<PropertyTable> Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner)
    746 {
    747     return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)));
     726PropertyTable* Structure::copyPropertyTable(JSGlobalData& globalData, Structure* owner)
     727{
     728    if (!propertyTable())
     729        return 0;
     730    return PropertyTable::clone(globalData, owner, *propertyTable().get());
     731}
     732
     733PropertyTable* Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner)
     734{
     735    if (propertyTable())
     736        return PropertyTable::clone(globalData, owner, *propertyTable().get());
     737    return PropertyTable::create(globalData, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
    748738}
    749739
     
    753743
    754744    materializePropertyMapIfNecessary(globalData);
    755     if (!m_propertyTable)
     745    if (!propertyTable())
    756746        return invalidOffset;
    757747
    758     PropertyMapEntry* entry = m_propertyTable->find(propertyName.uid()).first;
     748    PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first;
    759749    if (!entry)
    760750        return invalidOffset;
     
    768758{
    769759    materializePropertyMapIfNecessary(globalData);
    770     if (!m_propertyTable)
     760    if (!propertyTable())
    771761        return false;
    772762
    773     PropertyMapEntry* entry = m_propertyTable->find(propertyName.uid()).first;
     763    PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first;
    774764    if (!entry)
    775765        return false;
     
    783773{
    784774    materializePropertyMapIfNecessary(globalData);
    785     if (!m_propertyTable)
     775    if (!propertyTable())
    786776        return;
    787777
    788     PropertyTable::iterator end = m_propertyTable->end();
    789     for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter)
     778    PropertyTable::iterator end = propertyTable()->end();
     779    for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter)
    790780        iter->specificValue.clear();
    791781}
     
    801791    StringImpl* rep = propertyName.uid();
    802792
    803     if (!m_propertyTable)
    804         createPropertyMap();
    805 
    806     PropertyOffset newOffset = m_propertyTable->nextOffset(m_inlineCapacity);
    807 
    808     m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue), m_offset, PropertyTable::PropertyOffsetMayChange);
     793    if (!propertyTable())
     794        createPropertyMap(globalData);
     795
     796    PropertyOffset newOffset = propertyTable()->nextOffset(m_inlineCapacity);
     797
     798    propertyTable()->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue), m_offset, PropertyTable::PropertyOffsetMayChange);
    809799   
    810800    checkConsistency();
     
    818808    StringImpl* rep = propertyName.uid();
    819809
    820     if (!m_propertyTable)
     810    if (!propertyTable())
    821811        return invalidOffset;
    822812
    823     PropertyTable::find_iterator position = m_propertyTable->find(rep);
     813    PropertyTable::find_iterator position = propertyTable()->find(rep);
    824814    if (!position.first)
    825815        return invalidOffset;
     
    827817    PropertyOffset offset = position.first->offset;
    828818
    829     m_propertyTable->remove(position);
    830     m_propertyTable->addDeletedOffset(offset);
     819    propertyTable()->remove(position);
     820    propertyTable()->addDeletedOffset(offset);
    831821
    832822    checkConsistency();
     
    834824}
    835825
    836 void Structure::createPropertyMap(unsigned capacity)
    837 {
    838     ASSERT(!m_propertyTable);
     826void Structure::createPropertyMap(JSGlobalData& globalData, unsigned capacity)
     827{
     828    ASSERT(!propertyTable());
    839829
    840830    checkConsistency();
    841     m_propertyTable = adoptPtr(new PropertyTable(capacity));
     831    propertyTable().set(globalData, this, PropertyTable::create(globalData, capacity));
    842832}
    843833
     
    845835{
    846836    materializePropertyMapIfNecessary(globalData);
    847     if (!m_propertyTable)
     837    if (!propertyTable())
    848838        return;
    849839
    850840    bool knownUnique = !propertyNames.size();
    851841
    852     PropertyTable::iterator end = m_propertyTable->end();
    853     for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
     842    PropertyTable::iterator end = propertyTable()->end();
     843    for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
    854844        ASSERT(m_hasNonEnumerableProperties || !(iter->attributes & DontEnum));
    855845        if (iter->key->isIdentifier() && (!(iter->attributes & DontEnum) || mode == IncludeDontEnumProperties)) {
     
    883873    visitor.append(&thisObject->m_previousOrRareData);
    884874    visitor.append(&thisObject->m_specificValueInPrevious);
    885     if (thisObject->m_propertyTable) {
    886         PropertyTable::iterator end = thisObject->m_propertyTable->end();
    887         for (PropertyTable::iterator ptr = thisObject->m_propertyTable->begin(); ptr != end; ++ptr)
    888             visitor.append(&ptr->specificValue);
    889     }
     875
     876    if (thisObject->m_isPinnedPropertyTable) {
     877        ASSERT(thisObject->m_propertyTableUnsafe);
     878        visitor.append(&thisObject->m_propertyTableUnsafe);
     879    } else if (thisObject->m_propertyTableUnsafe)
     880        thisObject->m_propertyTableUnsafe.clear();
    890881}
    891882
     
    978969void Structure::checkConsistency()
    979970{
    980     if (!m_propertyTable)
     971    if (!propertyTable())
    981972        return;
    982973
    983974    if (!m_hasNonEnumerableProperties) {
    984         PropertyTable::iterator end = m_propertyTable->end();
    985         for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
     975        PropertyTable::iterator end = propertyTable()->end();
     976        for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
    986977            ASSERT(!(iter->attributes & DontEnum));
    987978        }
    988979    }
    989980
    990     m_propertyTable->checkConsistency();
     981    propertyTable()->checkConsistency();
    991982}
    992983
  • trunk/Source/JavaScriptCore/runtime/Structure.h

    r144767 r144910  
    3232#include "JSCell.h"
    3333#include "JSType.h"
    34 #include "PropertyMapHashTable.h"
    3534#include "PropertyName.h"
    3635#include "PropertyNameArray.h"
     36#include "PropertyOffset.h"
    3737#include "Protect.h"
    3838#include "StructureRareData.h"
     
    4141#include "Watchpoint.h"
    4242#include "Weak.h"
    43 #include <wtf/PassOwnPtr.h>
    4443#include <wtf/PassRefPtr.h>
    4544#include <wtf/RefCounted.h>
     
    5251class PropertyNameArray;
    5352class PropertyNameArrayData;
     53class PropertyTable;
    5454class StructureChain;
    5555class SlotVisitor;
     
    109109    bool isExtensible() const { return !m_preventExtensions; }
    110110    bool didTransition() const { return m_didTransition; }
    111     bool putWillGrowOutOfLineStorage()
    112     {
    113         checkOffsetConsistency();
    114            
    115         ASSERT(outOfLineCapacity() >= outOfLineSize());
    116            
    117         if (!m_propertyTable) {
    118             unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset);
    119             ASSERT(outOfLineCapacity() >= currentSize);
    120             return currentSize == outOfLineCapacity();
    121         }
    122            
    123         ASSERT(totalStorageCapacity() >= m_propertyTable->propertyStorageSize());
    124         if (m_propertyTable->hasDeletedOffset())
    125             return false;
    126            
    127         ASSERT(totalStorageCapacity() >= m_propertyTable->size());
    128         return m_propertyTable->size() == totalStorageCapacity();
    129     }
     111    bool putWillGrowOutOfLineStorage();
    130112    JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity();
    131113
     
    383365    PropertyOffset remove(PropertyName);
    384366
    385     void createPropertyMap(unsigned keyCount = 0);
     367    void createPropertyMap(JSGlobalData&, unsigned keyCount = 0);
    386368    void checkConsistency();
    387369
     
    389371    void despecifyAllFunctions(JSGlobalData&);
    390372
    391     PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
    392     PassOwnPtr<PropertyTable> copyPropertyTableForPinning(JSGlobalData&, Structure* owner);
     373    WriteBarrier<PropertyTable>& propertyTable();
     374    PropertyTable* takePropertyTableOrCloneIfPinned(JSGlobalData&, Structure* owner);
     375    PropertyTable* copyPropertyTable(JSGlobalData&, Structure* owner);
     376    PropertyTable* copyPropertyTableForPinning(JSGlobalData&, Structure* owner);
    393377    JS_EXPORT_PRIVATE void materializePropertyMap(JSGlobalData&);
    394378    void materializePropertyMapIfNecessary(JSGlobalData& globalData)
     
    396380        ASSERT(structure()->classInfo() == &s_info);
    397381        ASSERT(checkOffsetConsistency());
    398         if (!m_propertyTable && previousID())
     382        if (!propertyTable() && previousID())
    399383            materializePropertyMap(globalData);
    400384    }
     
    403387        ASSERT(structure()->classInfo() == &s_info);
    404388        checkOffsetConsistency();
    405         if (!m_propertyTable)
     389        if (!propertyTable())
    406390            materializePropertyMap(globalData);
    407391    }
     
    446430    }
    447431       
    448     ALWAYS_INLINE bool checkOffsetConsistency() const
    449     {
    450         if (!m_propertyTable) {
    451             ASSERT(!m_isPinnedPropertyTable);
    452             return true;
    453         }
    454            
    455         RELEASE_ASSERT(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity) == m_propertyTable->propertyStorageSize());
    456         unsigned totalSize = m_propertyTable->propertyStorageSize();
    457         RELEASE_ASSERT((totalSize < inlineCapacity() ? 0 : totalSize - inlineCapacity()) == numberOfOutOfLineSlotsForLastOffset(m_offset));
    458            
    459         return true;
    460     }
     432    bool checkOffsetConsistency() const;
    461433
    462434    void allocateRareData(JSGlobalData&);
     
    483455    StructureTransitionTable m_transitionTable;
    484456
    485     OwnPtr<PropertyTable> m_propertyTable;
     457    // Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread.
     458    WriteBarrier<PropertyTable> m_propertyTableUnsafe;
    486459
    487460    mutable InlineWatchpointSet m_transitionWatchpointSet;
  • trunk/Source/JavaScriptCore/runtime/StructureInlines.h

    r144767 r144910  
    2727#define StructureInlines_h
    2828
     29#include "PropertyMapHashTable.h"
    2930#include "Structure.h"
    3031
     
    6263    ASSERT(structure()->classInfo() == &s_info);
    6364    materializePropertyMapIfNecessary(globalData);
    64     if (!m_propertyTable)
     65    if (!propertyTable())
    6566        return invalidOffset;
    6667
    67     PropertyMapEntry* entry = m_propertyTable->find(propertyName.uid()).first;
     68    PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first;
    6869    return entry ? entry->offset : invalidOffset;
    6970}
     
    7374    ASSERT(structure()->classInfo() == &s_info);
    7475    materializePropertyMapIfNecessary(globalData);
    75     if (!m_propertyTable)
     76    if (!propertyTable())
    7677        return invalidOffset;
    7778
    78     PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first;
     79    PropertyMapEntry* entry = propertyTable()->findWithString(name.impl()).first;
    7980    return entry ? entry->offset : invalidOffset;
    8081}
     
    180181}
    181182
     183inline bool Structure::putWillGrowOutOfLineStorage()
     184{
     185    checkOffsetConsistency();
     186
     187    ASSERT(outOfLineCapacity() >= outOfLineSize());
     188
     189    if (!propertyTable()) {
     190        unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset);
     191        ASSERT(outOfLineCapacity() >= currentSize);
     192        return currentSize == outOfLineCapacity();
     193    }
     194
     195    ASSERT(totalStorageCapacity() >= propertyTable()->propertyStorageSize());
     196    if (propertyTable()->hasDeletedOffset())
     197        return false;
     198
     199    ASSERT(totalStorageCapacity() >= propertyTable()->size());
     200    return propertyTable()->size() == totalStorageCapacity();
     201}
     202
     203ALWAYS_INLINE WriteBarrier<PropertyTable>& Structure::propertyTable()
     204{
     205    ASSERT(!globalObject() || !globalObject()->globalData().heap.isBusy());
     206    return m_propertyTableUnsafe;
     207}
     208
     209ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
     210{
     211    PropertyTable* propertyTable = m_propertyTableUnsafe.get();
     212
     213    if (!propertyTable) {
     214        ASSERT(!m_isPinnedPropertyTable);
     215        return true;
     216    }
     217
     218    RELEASE_ASSERT(numberOfSlotsForLastOffset(m_offset, m_inlineCapacity) == propertyTable->propertyStorageSize());
     219    unsigned totalSize = propertyTable->propertyStorageSize();
     220    RELEASE_ASSERT((totalSize < inlineCapacity() ? 0 : totalSize - inlineCapacity()) == numberOfOutOfLineSlotsForLastOffset(m_offset));
     221
     222    return true;
     223}
     224
    182225} // namespace JSC
    183226
  • trunk/Source/JavaScriptCore/runtime/WriteBarrier.h

    r144767 r144910  
    100100    T* get() const
    101101    {
    102         if (m_cell)
    103             validateCell(m_cell);
    104         return reinterpret_cast<T*>(static_cast<void*>(m_cell));
     102        // Copy m_cell to a local to avoid multiple-read issues. (See <http://webkit.org/b/110854>)
     103        JSCell* cell = m_cell;
     104        if (cell)
     105            validateCell(cell);
     106        return reinterpret_cast<T*>(static_cast<void*>(cell));
    105107    }
    106108
Note: See TracChangeset for help on using the changeset viewer.