Ignore:
Timestamp:
Mar 13, 2014, 11:45:39 PM (11 years ago)
Author:
[email protected]
Message:

Reduce memory use for static property maps
https://bugs.webkit.org/show_bug.cgi?id=129986

Reviewed by Andreas Kling.

Static property tables are currently duplicated on first use from read-only memory into dirty memory
in every process, and since the entries are large (48 bytes) and the tables can be unusually sparse
(we use a custom hash table without a rehash) a lot of memory may be wasted.

Source/JavaScriptCore:

First, reduce the size of the hashtable. Instead of storing values in the table the hashtable maps
from string hashes to indicies into a densely packed array of values. Compute the index table at
compile time as a part of the derived sources step, such that this may be read-only data.

Second, don't copy all data from the HashTableValue array into a HashEntry objects. Instead refer
directly to the HashTableValue entries. The only data that needs to be allocated at runtime are the
keys, which are Identifiers.

  • create_hash_table:
    • emit the hash table index into the derived source (we were calculating this already to ensure chaining does not get too deep).
  • parser/Lexer.cpp:

(JSC::Lexer<LChar>::parseIdentifier):
(JSC::Lexer<UChar>::parseIdentifier):
(JSC::Lexer<T>::parseIdentifierSlowCase):

  • HashEntry -> HashTableValue.
  • parser/Lexer.h:

(JSC::Keywords::getKeyword):

  • HashEntry -> HashTableValue.
  • runtime/ClassInfo.h:
    • removed HashEntry.
  • runtime/JSObject.cpp:

(JSC::getClassPropertyNames):

  • use HashTable::ConstIterator.

(JSC::JSObject::put):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::findPropertyHashEntry):

  • HashEntry -> HashTableValue.

(JSC::JSObject::reifyStaticFunctionsForDelete):

  • changed HashTable::ConstIterator interface.
  • runtime/JSObject.h:
    • HashEntry -> HashTableValue.
  • runtime/Lookup.cpp:

(JSC::HashTable::createTable):

  • table -> keys, keys array is now densely packed.

(JSC::HashTable::deleteTable):

  • table -> keys.

(JSC::setUpStaticFunctionSlot):

  • HashEntry -> HashTableValue.
  • runtime/Lookup.h:

(JSC::HashTableValue::builtinGenerator):
(JSC::HashTableValue::function):
(JSC::HashTableValue::functionLength):
(JSC::HashTableValue::propertyGetter):
(JSC::HashTableValue::propertyPutter):
(JSC::HashTableValue::lexerValue):

  • added accessor methods from HashEntry.

(JSC::HashTable::copy):

  • fields changed.

(JSC::HashTable::initializeIfNeeded):

  • table -> keys.

(JSC::HashTable::entry):

  • HashEntry -> HashTableValue.

(JSC::HashTable::ConstIterator::ConstIterator):

  • iterate packed value array, so no need to skipInvalidKeys().

(JSC::HashTable::ConstIterator::value):
(JSC::HashTable::ConstIterator::key):
(JSC::HashTable::ConstIterator::operator->):

  • accessors now get HashTableValue/StringImpl* separately.

(JSC::HashTable::ConstIterator::operator++):

  • iterate packed value array, so no need to skipInvalidKeys().

(JSC::HashTable::end):

  • end is now size of dense not sparse array.

(JSC::getStaticPropertySlot):
(JSC::getStaticFunctionSlot):
(JSC::getStaticValueSlot):
(JSC::putEntry):
(JSC::lookupPut):

  • HashEntry -> HashTableValue.

Source/WebCore:

  • bindings/js/JSDOMBinding.h:

(WebCore::getStaticValueSlotEntryWithoutCaching):
(WebCore::getStaticValueSlotEntryWithoutCaching<JSDOMWrapper>):

  • HashEntry -> HashTableValue.
  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::getOwnPropertySlot):

  • HashEntry -> HashTableValue.
  • bindings/js/JSHistoryCustom.cpp:

(WebCore::JSHistory::getOwnPropertySlotDelegate):

  • HashEntry -> HashTableValue.
  • bindings/js/JSLocationCustom.cpp:

(WebCore::JSLocation::getOwnPropertySlotDelegate):
(WebCore::JSLocation::putDelegate):

  • HashEntry -> HashTableValue.
  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateGetOwnPropertySlotBody):

  • HashEntry -> HashTableValue.

(GenerateHashTable):

  • emit the hash table index into the derived source (we were calculating this already to ensure chaining does not get too deep).

LayoutTests:

  • inspector-protocol/debugger/setPauseOnExceptions-all-expected.txt:
  • inspector-protocol/debugger/setPauseOnExceptions-none-expected.txt:
  • inspector-protocol/debugger/setPauseOnExceptions-uncaught-expected.txt:
  • js/dom/dom-static-property-for-in-iteration-expected.txt:
    • Properties now iterated in correct order, not permuted by hash table.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r165497 r165603  
    7676static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode, bool didReify)
    7777{
     78    VM& vm = exec->vm();
     79
    7880    // Add properties from the static hashtables of properties
    7981    for (; classInfo; classInfo = classInfo->parentClass) {
    80         const HashTable* table = classInfo->propHashTable(exec);
     82        const HashTable* table = classInfo->propHashTable(vm);
    8183        if (!table)
    8284            continue;
    83         table->initializeIfNeeded(exec);
    84         ASSERT(table->table);
    85 
    86         int hashSizeMask = table->compactSize - 1;
    87         const HashEntry* entry = table->table;
    88         for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
    89             if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((entry->attributes() & BuiltinOrFunction) && didReify))
    90                 propertyNames.add(entry->key());
     85
     86        for (auto iter = table->begin(vm); iter != table->end(vm); ++iter) {
     87            if ((!(iter->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((iter->attributes() & BuiltinOrFunction) && didReify))
     88                propertyNames.add(iter.key());
    9189        }
    9290    }
     
    397395        const ClassInfo* info = obj->classInfo();
    398396        if (info->hasStaticSetterOrReadonlyProperties(vm)) {
    399             if (const HashEntry* entry = obj->findPropertyHashEntry(vm, propertyName)) {
     397            if (const HashTableValue* entry = obj->findPropertyHashEntry(vm, propertyName)) {
    400398                putEntry(exec, entry, obj, propertyName, value, slot);
    401399                return;
     
    12741272
    12751273    // Look in the static hashtable of properties
    1276     const HashEntry* entry = thisObject->findPropertyHashEntry(vm, propertyName);
     1274    const HashTableValue* entry = thisObject->findPropertyHashEntry(vm, propertyName);
    12771275    if (entry) {
    12781276        if (entry->attributes() & DontDelete && !vm.isInDefineOwnProperty())
     
    14021400}
    14031401
    1404 const HashEntry* JSObject::findPropertyHashEntry(VM& vm, PropertyName propertyName) const
     1402const HashTableValue* JSObject::findPropertyHashEntry(VM& vm, PropertyName propertyName) const
    14051403{
    14061404    for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
    14071405        if (const HashTable* propHashTable = info->propHashTable(vm)) {
    1408             if (const HashEntry* entry = propHashTable->entry(vm, propertyName))
     1406            if (const HashTableValue* entry = propHashTable->entry(vm, propertyName))
    14091407                return entry;
    14101408        }
     
    16221620
    16231621    for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
    1624         const HashTable* hashTable = info->propHashTable(globalObject()->globalExec());
     1622        const HashTable* hashTable = info->propHashTable(vm);
    16251623        if (!hashTable)
    16261624            continue;
    16271625        PropertySlot slot(this);
    1628         for (HashTable::ConstIterator iter = hashTable->begin(vm); iter != hashTable->end(vm); ++iter) {
     1626        for (auto iter = hashTable->begin(vm); iter != hashTable->end(vm); ++iter) {
    16291627            if (iter->attributes() & BuiltinOrFunction)
    1630                 setUpStaticFunctionSlot(globalObject()->globalExec(), *iter, this, Identifier(&vm, iter->key()), slot);
     1628                setUpStaticFunctionSlot(globalObject()->globalExec(), iter.value(), this, Identifier(&vm, iter.key()), slot);
    16311629        }
    16321630    }
Note: See TracChangeset for help on using the changeset viewer.