Commit 85b26820 authored by akling@apple.com's avatar akling@apple.com

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.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.gypi:
* 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/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):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@144910 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent b6b1b9c0
......@@ -281,6 +281,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
......
2013-03-06 Andreas Kling <akling@apple.com>
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.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.gypi:
* 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/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):
2013-03-05 Filip Pizlo <fpizlo@apple.com>
Get rid of the invert argument to SpeculativeJIT::jumpSlowForUnwantedArrayMode
......
......@@ -724,6 +724,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 \
......
......@@ -758,6 +758,7 @@
'runtime/PropertyOffset.h',
'runtime/PropertySlot.cpp',
'runtime/PropertySlot.h',
'runtime/PropertyTable.cpp',
'runtime/PropertyStorage.h',
'runtime/Protect.h',
'runtime/PrototypeMap.cpp',
......
......@@ -305,6 +305,7 @@
<ClCompile Include="..\runtime\PropertyDescriptor.cpp" />
<ClCompile Include="..\runtime\PropertyNameArray.cpp" />
<ClCompile Include="..\runtime\PropertySlot.cpp" />
<ClCompile Include="..\runtime\PropertyTable.cpp" />
<ClCompile Include="..\runtime\PrototypeMap.cpp" />
<ClCompile Include="..\runtime\RegExp.cpp" />
<ClCompile Include="..\runtime\RegExpCache.cpp" />
......
......@@ -705,6 +705,7 @@
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 */; };
ADE39FFF16DD144B0003CD4A /* 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 */; };
......@@ -1622,6 +1623,7 @@
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>"; };
......@@ -2510,6 +2512,7 @@
65621E6B089E859700760F35 /* PropertySlot.cpp */,
65621E6C089E859700760F35 /* PropertySlot.h */,
0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */,
AD1CF06816DCAB2D00B97123 /* PropertyTable.cpp */,
65C02FBB0637462A003E7EE6 /* Protect.h */,
14D844A216AA2C7000A65AF0 /* PrototypeMap.cpp */,
14D844A316AA2C7000A65AF0 /* PrototypeMap.h */,
......@@ -4031,6 +4034,7 @@
0FBE0F7416C1DB090082C5E8 /* DFGPredictionInjectionPhase.cpp in Sources */,
0FBE0F7616C1DB0F0082C5E8 /* DFGUnificationPhase.cpp in Sources */,
0F493AFA16D0CAD30084508B /* SourceProvider.cpp in Sources */,
ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -299,6 +299,7 @@ SOURCES += \
runtime/PropertyDescriptor.cpp \
runtime/PropertyNameArray.cpp \
runtime/PropertySlot.cpp \
runtime/PropertyTable.cpp \
runtime/PrototypeMap.cpp \
runtime/RegExpConstructor.cpp \
runtime/RegExpCachedResult.cpp \
......
......@@ -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);
......
......@@ -256,6 +256,7 @@ namespace JSC {
Strong<Structure> unlinkedProgramCodeBlockStructure;
Strong<Structure> unlinkedEvalCodeBlockStructure;
Strong<Structure> unlinkedFunctionCodeBlockStructure;
Strong<Structure> propertyTableStructure;
IdentifierTable* identifierTable;
CommonIdentifiers* propertyNames;
......
......@@ -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
......
/*
* 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 "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "SlotVisitorInlines.h"
#include "StructureInlines.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);
}
}
This diff is collapsed.
......@@ -31,16 +31,15 @@
#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,27 +364,29 @@ 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);
WriteBarrier<PropertyTable>& propertyTable();
PropertyTable* takePropertyTableOrCloneIfPinned(JSGlobalData&, Structure* owner);
PropertyTable* copyPropertyTable(JSGlobalData&, Structure* owner);
PropertyTable* copyPropertyTableForPinning(JSGlobalData&, Structure* owner);
JS_EXPORT_PRIVATE void materializePropertyMap(JSGlobalData&);
void materializePropertyMapIfNecessary(JSGlobalData& globalData)
{
ASSERT(structure()->classInfo() == &s_info);
ASSERT(checkOffsetConsistency());
if (!m_propertyTable && previousID())
if (!propertyTable() && previousID())
materializePropertyMap(globalData);
}
void materializePropertyMapIfNecessaryForPinning(JSGlobalData& globalData)
{
ASSERT(structure()->classInfo() == &s_info);
checkOffsetConsistency();
if (!m_propertyTable)
if (!propertyTable())
materializePropertyMap(globalData);
}
......@@ -445,19 +429,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));