Ignore:
Timestamp:
May 10, 2012, 10:32:39 AM (13 years ago)
Author:
[email protected]
Message:

Enh: Hash Const JSString in Backing Stores to Save Memory
https://bugs.webkit.org/show_bug.cgi?id=86024

Reviewed by Filip Pizlo.

During garbage collection, each marking thread keeps a HashMap of
strings. While visiting via MarkStack::copyAndAppend(), we check to
see if the string we are visiting is already in the HashMap. If not
we add it. If so, we change the reference to the current string we're
visiting to the prior string.

To somewhat reduce the performance impact of this change, if a string
is unique at the end of a marking it will not be checked during further
GC phases. In some cases this won't catch all duplicates, but we are
trying to catch the growth of duplicate strings.

  • heap/Heap.cpp:

(JSC::Heap::markRoots):

  • heap/MarkStack.cpp:

(JSC::MarkStackThreadSharedData::resetChildren): New method called by the
main thread to reset the slave threads. This is primarily done to
clear the m_uniqueStrings HashMap.
(JSC):
(JSC::MarkStackThreadSharedData::markingThreadMain):
(JSC::MarkStackThreadSharedData::markingThreadStartFunc):
(JSC::MarkStackThreadSharedData::MarkStackThreadSharedData):
(JSC::MarkStackThreadSharedData::reset):
(JSC::MarkStack::reset): Added call to clear m_uniqueStrings.
(JSC::MarkStack::internalAppend): New method that performs the hash consting.
(JSC::SlotVisitor::copyAndAppend): Changed to call the new hash consting
internalAppend()

  • heap/MarkStack.h:

(MarkStackThreadSharedData):
(MarkStack):
(JSC::MarkStack::sharedData):

  • runtime/JSString.h:

(JSString): Added m_isHashConstSingleton flag, accessors for the flag and
code to initialize the flag.
(JSC::JSString::finishCreation):
(JSC::JSString::isHashConstSingleton):
(JSC::JSString::clearHashConstSingleton):
(JSC::JSString::setHashConstSingleton):
(JSC::JSRopeString::finishCreation):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/heap/MarkStack.cpp

    r113455 r116659  
    3737#include "ScopeChain.h"
    3838#include "Structure.h"
     39#include "UString.h"
    3940#include "WriteBarrier.h"
    4041#include <wtf/MainThread.h>
     
    219220
    220221#if ENABLE(PARALLEL_GC)
    221 void MarkStackThreadSharedData::markingThreadMain()
     222void MarkStackThreadSharedData::resetChildren()
     223{
     224    for (unsigned i = 0; i < m_slaveMarkStacks.size(); ++i)
     225       m_slaveMarkStacks[i]->reset();
     226}
     227
     228void MarkStackThreadSharedData::markingThreadMain(SlotVisitor* slotVisitor)
    222229{
    223230    WTF::registerGCThread();
    224     SlotVisitor slotVisitor(*this);
    225     ParallelModeEnabler enabler(slotVisitor);
    226     slotVisitor.drainFromShared(SlotVisitor::SlaveDrain);
    227 }
    228 
    229 void MarkStackThreadSharedData::markingThreadStartFunc(void* shared)
    230 {
    231     static_cast<MarkStackThreadSharedData*>(shared)->markingThreadMain();
     231    ParallelModeEnabler enabler(*slotVisitor);
     232    slotVisitor->drainFromShared(SlotVisitor::SlaveDrain);
     233    delete slotVisitor;
     234}
     235
     236void MarkStackThreadSharedData::markingThreadStartFunc(void* myVisitor)
     237{
     238    SlotVisitor* slotVisitor = static_cast<SlotVisitor*>(myVisitor);
     239    slotVisitor->sharedData().markingThreadMain(slotVisitor);
    232240}
    233241#endif
     
    242250#if ENABLE(PARALLEL_GC)
    243251    for (unsigned i = 1; i < Options::numberOfGCMarkers; ++i) {
    244         m_markingThreads.append(createThread(markingThreadStartFunc, this, "JavaScriptCore::Marking"));
     252        SlotVisitor* slotVisitor = new SlotVisitor(*this);
     253        m_slaveMarkStacks.append(slotVisitor);
     254        m_markingThreads.append(createThread(markingThreadStartFunc, slotVisitor, "JavaScriptCore::Marking"));
    245255        ASSERT(m_markingThreads.last());
    246256    }
     
    274284    ASSERT(m_opaqueRoots.isEmpty());
    275285#endif
    276    
    277286    m_weakReferenceHarvesters.removeAll();
    278287}
     
    287296    m_opaqueRoots.clear();
    288297#endif
     298    m_uniqueStrings.clear();
    289299}
    290300
     
    487497}
    488498
     499inline void MarkStack::internalAppend(JSValue* slot)
     500{
     501    ASSERT(slot);
     502    JSValue value = *slot;
     503    ASSERT(value);
     504    if (!value.isCell())
     505        return;
     506
     507    if (value.isString()) {
     508        JSString* string = jsCast<JSString*>(value.asCell());
     509        if (!string->isHashConstSingleton() && string->length() > 1 && !string->isRope()) {
     510            UniqueStringMap::AddResult addResult = m_uniqueStrings.add(string->string().impl(), value);
     511            if (addResult.isNewEntry)
     512                string->setHashConstSingleton();
     513            else {
     514                JSValue existingJSValue = addResult.iterator->second;
     515                if (value != existingJSValue)
     516                    jsCast<JSString*>(existingJSValue.asCell())->clearHashConstSingleton();
     517                *slot = existingJSValue;
     518                return;
     519            }
     520        }
     521    }
     522
     523    internalAppend(value.asCell());
     524}
     525
     526
    489527void SlotVisitor::copyAndAppend(void** ptr, size_t bytes, JSValue* values, unsigned length)
    490528{
     
    500538            if (!value)
    501539                continue;
    502             internalAppend(value);
     540            internalAppend(&newValues[i]);
    503541        }
    504542
Note: See TracChangeset for help on using the changeset viewer.