Commit 4d4086d8 authored by oliver@apple.com's avatar oliver@apple.com
Browse files

Allow anonymous storage inside JSObject

https://bugs.webkit.org/show_bug.cgi?id=29168

Reviewed by Geoff Garen

Add the concept of anonymous slots to Structures so that it is
possible to store references to values that need marking in the
standard JSObject storage buffer.  This allows us to reduce the
malloc overhead of some objects (by allowing them to store JS
values in the inline storage of the object) and reduce the
dependence of custom mark functions (if all an objects children
are in the standard object property storage there's no need to
mark them manually).

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@48403 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent f493144c
2009-09-10 Oliver Hunt <oliver@apple.com>
Reviewed by Geoff Garen.
Allow anonymous storage inside JSObject
https://bugs.webkit.org/show_bug.cgi?id=29168
Add the concept of anonymous slots to Structures so that it is
possible to store references to values that need marking in the
standard JSObject storage buffer. This allows us to reduce the
malloc overhead of some objects (by allowing them to store JS
values in the inline storage of the object) and reduce the
dependence of custom mark functions (if all an objects children
are in the standard object property storage there's no need to
mark them manually).
* JavaScriptCore.exp:
* runtime/JSObject.h:
(JSC::JSObject::putAnonymousValue):
(JSC::JSObject::getAnonymousValue):
(JSC::JSObject::addAnonymousSlots):
* runtime/JSWrapperObject.h:
(JSC::JSWrapperObject::createStructure):
(JSC::JSWrapperObject::JSWrapperObject):
(JSC::JSWrapperObject::setInternalValue):
* runtime/PropertyMapHashTable.h:
* runtime/Structure.cpp:
(JSC::Structure::~Structure):
(JSC::Structure::materializePropertyMap):
(JSC::Structure::addAnonymousSlotsTransition):
(JSC::Structure::copyPropertyTable):
(JSC::Structure::put):
(JSC::Structure::rehashPropertyMapHashTable):
* runtime/Structure.h:
(JSC::Structure::propertyStorageSize):
(JSC::StructureTransitionTable::reifySingleTransition):
* runtime/StructureTransitionTable.h:
(JSC::StructureTransitionTable::TransitionTable::addSlotTransition):
(JSC::StructureTransitionTable::TransitionTable::removeSlotTransition):
(JSC::StructureTransitionTable::TransitionTable::getSlotTransition):
(JSC::StructureTransitionTable::getAnonymousSlotTransition):
(JSC::StructureTransitionTable::addAnonymousSlotTransition):
(JSC::StructureTransitionTable::removeAnonymousSlotTransition):
2009-09-15 Alex Milowski <alex@milowski.com>
Reviewed by Tor Arne Vestbø.
......
......@@ -274,6 +274,7 @@ __ZN3JSC9Structure18startIgnoringLeaksEv
__ZN3JSC9Structure21addPropertyTransitionEPS0_RKNS_10IdentifierEjPNS_6JSCellERm
__ZN3JSC9Structure22materializePropertyMapEv
__ZN3JSC9Structure25changePrototypeTransitionEPS0_NS_7JSValueE
__ZN3JSC9Structure27addAnonymousSlotsTransitionEPS0_j
__ZN3JSC9Structure27despecifyDictionaryFunctionERKNS_10IdentifierE
__ZN3JSC9Structure27despecifyFunctionTransitionEPS0_RKNS_10IdentifierE
__ZN3JSC9Structure28addPropertyWithoutTransitionERKNS_10IdentifierEjPNS_6JSCellE
......
......@@ -209,6 +209,17 @@ namespace JSC {
return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark | HasDefaultGetPropertyNames));
}
protected:
void addAnonymousSlots(unsigned count);
void putAnonymousValue(unsigned index, JSValue value)
{
*locationForOffset(index) = value;
}
JSValue getAnonymousValue(unsigned index)
{
return *locationForOffset(index);
}
private:
// Nobody should ever ask any of these questions on something already known to be a JSObject.
using JSCell::isAPIValueWrapper;
......@@ -513,6 +524,17 @@ inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi
putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
}
inline void JSObject::addAnonymousSlots(unsigned count)
{
size_t currentCapacity = m_structure->propertyStorageCapacity();
RefPtr<Structure> structure = Structure::addAnonymousSlotsTransition(m_structure, count);
if (currentCapacity != structure->propertyStorageCapacity())
allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
setStructure(structure.release());
}
inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
{
ASSERT(value);
......
......@@ -38,7 +38,7 @@ namespace JSC {
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultGetPropertyNames));
return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultGetPropertyNames | HasDefaultMark));
}
private:
......@@ -50,6 +50,8 @@ namespace JSC {
inline JSWrapperObject::JSWrapperObject(PassRefPtr<Structure> structure)
: JSObject(structure)
{
addAnonymousSlots(1);
putAnonymousValue(0, jsNull());
}
inline void JSWrapperObject::setInternalValue(JSValue value)
......@@ -57,6 +59,7 @@ namespace JSC {
ASSERT(value);
ASSERT(!value.isObject());
m_internalValue = value;
putAnonymousValue(0, value);
}
} // namespace JSC
......
......@@ -61,6 +61,7 @@ namespace JSC {
unsigned size;
unsigned keyCount;
unsigned deletedSentinelCount;
unsigned anonymousSlotCount;
unsigned lastIndexUsed;
Vector<unsigned>* deletedOffsets;
unsigned entryIndices[1];
......
......@@ -152,8 +152,13 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo)
Structure::~Structure()
{
if (m_previous)
m_previous->table.remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
if (m_previous) {
if (m_nameInPrevious)
m_previous->table.remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
else
m_previous->table.removeAnonymousSlotTransition(m_anonymousSlotsInPrevious);
}
if (m_cachedPropertyNameArrayData)
m_cachedPropertyNameArrayData->setCachedStructure(0);
......@@ -267,6 +272,10 @@ void Structure::materializePropertyMap()
for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
structure = structures[i];
if (!structure->m_nameInPrevious) {
m_propertyTable->anonymousSlotCount += structure->m_anonymousSlotsInPrevious;
continue;
}
structure->m_nameInPrevious->ref();
PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious, ++m_propertyTable->lastIndexUsed);
insertIntoPropertyMapHashTable(entry);
......@@ -489,6 +498,47 @@ PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structur
return transition.release();
}
PassRefPtr<Structure> Structure::addAnonymousSlotsTransition(Structure* structure, unsigned count)
{
if (Structure* transition = structure->table.getAnonymousSlotTransition(count)) {
ASSERT(transition->storedPrototype() == structure->storedPrototype());
return transition;
}
ASSERT(count);
ASSERT(count < ((1<<6) - 2));
RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo());
transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain;
transition->m_previous = structure;
transition->m_nameInPrevious = 0;
transition->m_attributesInPrevious = 0;
transition->m_anonymousSlotsInPrevious = count;
transition->m_specificValueInPrevious = 0;
transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
if (structure->m_propertyTable) {
if (structure->m_isPinnedPropertyTable)
transition->m_propertyTable = structure->copyPropertyTable();
else {
transition->m_propertyTable = structure->m_propertyTable;
structure->m_propertyTable = 0;
}
} else {
if (structure->m_previous)
transition->materializePropertyMap();
else
transition->createPropertyMapHashTable();
}
transition->addAnonymousSlots(count);
if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
transition->growPropertyStorageCapacity();
structure->table.addAnonymousSlotTransition(count, transition.get());
return transition.release();
}
PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure)
{
RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo());
......@@ -613,6 +663,7 @@ PropertyMapHashTable* Structure::copyPropertyTable()
if (m_propertyTable->deletedOffsets)
newTable->deletedOffsets = new Vector<unsigned>(*m_propertyTable->deletedOffsets);
newTable->anonymousSlotCount = m_propertyTable->anonymousSlotCount;
return newTable;
}
......@@ -792,7 +843,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel
newOffset = m_propertyTable->deletedOffsets->last();
m_propertyTable->deletedOffsets->removeLast();
} else
newOffset = m_propertyTable->keyCount;
newOffset = m_propertyTable->keyCount + m_propertyTable->anonymousSlotCount;
m_propertyTable->entries()[entryIndex - 1].offset = newOffset;
++m_propertyTable->keyCount;
......@@ -804,6 +855,11 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel
return newOffset;
}
void Structure::addAnonymousSlots(unsigned count)
{
m_propertyTable->anonymousSlotCount += count;
}
bool Structure::hasTransition(UString::Rep* rep, unsigned attributes)
{
return table.hasTransition(make_pair(rep, attributes));
......@@ -962,6 +1018,7 @@ void Structure::rehashPropertyMapHashTable(unsigned newTableSize)
m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize)));
m_propertyTable->size = newTableSize;
m_propertyTable->sizeMask = newTableSize - 1;
m_propertyTable->anonymousSlotCount = oldTable->anonymousSlotCount;
unsigned lastIndexUsed = 0;
unsigned entryCount = oldTable->keyCount + oldTable->deletedSentinelCount;
......
......@@ -67,7 +67,8 @@ namespace JSC {
static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset);
static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype);
static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&);
static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&);
static PassRefPtr<Structure> addAnonymousSlotsTransition(Structure*, unsigned count);
static PassRefPtr<Structure> getterSetterTransition(Structure*);
static PassRefPtr<Structure> toDictionaryTransition(Structure*);
static PassRefPtr<Structure> fromDictionaryTransition(Structure*);
......@@ -93,7 +94,7 @@ namespace JSC {
void growPropertyStorageCapacity();
size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; }
size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; }
size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + m_propertyTable->anonymousSlotCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; }
bool isUsingInlineStorage() const;
size_t get(const Identifier& propertyName);
......@@ -129,6 +130,7 @@ namespace JSC {
size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
size_t remove(const Identifier& propertyName);
void addAnonymousSlots(unsigned slotCount);
void getEnumerableNamesFromPropertyTable(PropertyNameArray&);
void getEnumerableNamesFromClassInfoTable(ExecState*, const ClassInfo*, PropertyNameArray&);
......@@ -189,6 +191,7 @@ namespace JSC {
bool m_isPinnedPropertyTable : 1;
bool m_hasGetterSetterProperties : 1;
unsigned m_attributesInPrevious : 7;
unsigned m_anonymousSlotsInPrevious : 6;
};
inline size_t Structure::get(const Identifier& propertyName)
......@@ -282,10 +285,10 @@ namespace JSC {
{
ASSERT(usingSingleTransitionSlot());
Structure* existingTransition = singleTransition();
ASSERT(existingTransition);
TransitionTable* transitionTable = new TransitionTable;
setTransitionTable(transitionTable);
add(make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious);
if (existingTransition)
add(make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious);
}
} // namespace JSC
......
......@@ -31,6 +31,7 @@
#include <wtf/HashMap.h>
#include <wtf/HashTraits.h>
#include <wtf/PtrAndFlags.h>
#include <wtf/OwnPtr.h>
#include <wtf/RefPtr.h>
namespace JSC {
......@@ -68,7 +69,36 @@ namespace JSC {
class StructureTransitionTable {
typedef std::pair<Structure*, Structure*> Transition;
typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable;
struct TransitionTable : public HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> {
typedef HashMap<unsigned, Structure*> AnonymousSlotMap;
void addSlotTransition(unsigned count, Structure* structure)
{
ASSERT(!getSlotTransition(count));
if (!m_anonymousSlotTable)
m_anonymousSlotTable.set(new AnonymousSlotMap);
m_anonymousSlotTable->add(count, structure);
}
void removeSlotTransition(unsigned count)
{
ASSERT(getSlotTransition(count));
m_anonymousSlotTable->remove(count);
}
Structure* getSlotTransition(unsigned count)
{
if (!m_anonymousSlotTable)
return 0;
AnonymousSlotMap::iterator find = m_anonymousSlotTable->find(count);
if (find == m_anonymousSlotTable->end())
return 0;
return find->second;
}
private:
OwnPtr<AnonymousSlotMap> m_anonymousSlotTable;
};
public:
StructureTransitionTable() {
m_transitions.m_singleTransition.set(0);
......@@ -123,6 +153,27 @@ namespace JSC {
table()->add(key, Transition(0, structure));
}
}
Structure* getAnonymousSlotTransition(unsigned count)
{
if (usingSingleTransitionSlot())
return 0;
return table()->getSlotTransition(count);
}
void addAnonymousSlotTransition(unsigned count, Structure* structure)
{
if (usingSingleTransitionSlot())
reifySingleTransition();
ASSERT(!table()->getSlotTransition(count));
table()->addSlotTransition(count, structure);
}
void removeAnonymousSlotTransition(unsigned count)
{
ASSERT(!usingSingleTransitionSlot());
table()->removeSlotTransition(count);
}
private:
TransitionTable* table() const { ASSERT(!usingSingleTransitionSlot()); return m_transitions.m_table; }
Structure* singleTransition() const {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment