Changeset 113141 in webkit for trunk/Source/JavaScriptCore/heap


Ignore:
Timestamp:
Apr 3, 2012, 10:28:13 PM (13 years ago)
Author:
[email protected]
Message:

First step toward incremental Weak<T> finalization
https://bugs.webkit.org/show_bug.cgi?id=82670

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

This patch implements a Weak<T> heap that is compatible with incremental
finalization, while making as few behavior changes as possible. The behavior
changes it makes are:

(*) Weak<T>'s raw JSValue no longer reverts to JSValue() automatically --
instead, a separate flag indicates that the JSValue is no longer valid.
(This is required so that the JSValue can be preserved for later finalization.)
Objects dealing with WeakImpls directly must change to check the flag.

(*) Weak<T> is no longer a subclass of Handle<T>.

(*) DOM GC performance is different -- 9% faster in the geometric mean,
but 15% slower in one specific case:

gc-dom1.html: 6% faster
gc-dom2.html: 23% faster
gc-dom3.html: 17% faster
gc-dom4.html: 15% *slower*

The key features of this new heap are:

(*) Each block knows its own state, independent of any other blocks.

(*) Each block caches its own sweep result.

(*) The heap visits dead Weak<T>s at the end of GC. (It doesn't
mark them yet, since that would be a behavior change.)

  • API/JSCallbackObject.cpp:

(JSC::JSCallbackObjectData::finalize):

  • API/JSCallbackObjectFunctions.h:

(JSC::::init): Updated to use the new WeakHeap API.

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.gypi:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri: Paid the build system tax since I added some new files.
  • heap/Handle.h: Made WeakBlock a friend and exposed slot() as public,

so we can keep passing a Handle<T> to finalizers, to avoid more surface
area change in this patch. A follow-up patch should change the type we
pass to finalizers.

  • heap/HandleHeap.cpp:

(JSC):
(JSC::HandleHeap::writeBarrier):
(JSC::HandleHeap::isLiveNode):

  • heap/HandleHeap.h:

(JSC):
(HandleHeap):
(Node):
(JSC::HandleHeap::Node::Node): Removed all code related to Weak<T>, since
we have a separate WeakHeap now.

  • heap/Heap.cpp:

(JSC::Heap::Heap): Removed m_extraCost because extra cost is accounted
for through our watermark now. Removed m_waterMark because it was unused.

(JSC::Heap::destroy): Updated for addition of WeakHeap.

(JSC::Heap::reportExtraMemoryCostSlowCase): Changed from using its own
variable to participating in the watermark strategy. I wanted to standardize
WeakHeap and all other Heap clients on this strategy, to make sure it's
accurate.

(JSC::Heap::markRoots): Updated for addition of WeakHeap. Added WeakHeap
dead visit pass, as explained above.

(JSC::Heap::collect):
(JSC::Heap::resetAllocators): Updated for addition of WeakHeap.

(JSC::Heap::addFinalizer):
(JSC::Heap::FinalizerOwner::finalize): Updated for new Weak<T> API.

  • heap/Heap.h:

(JSC::Heap::weakHeap):
(Heap):
(JSC::Heap::addToWaterMark): Added a way to participate in the watermarking
strategy, since this is the best way for WeakHeap to report its memory
cost. (I plan to update this in a follow-up patch to make it more accurate,
but for now it is not less accurate than it used to be.)

  • heap/MarkedSpace.cpp:

(JSC::MarkedSpace::MarkedSpace):
(JSC::MarkedSpace::resetAllocators):

  • heap/MarkedSpace.h:

(MarkedSpace):
(JSC::MarkedSpace::addToWaterMark):
(JSC::MarkedSpace::didConsumeFreeList): Removed m_nurseryWaterMark because
it was unused, and I didn't want to update WeakHeap to keep an usused
variable working. Added API for above.

  • heap/PassWeak.h:

(JSC):
(WeakImplAccessor):
(PassWeak):
(JSC::::operator):
(JSC::::get):
(JSC::::was):
(JSC::::PassWeak):
(JSC::::~PassWeak):
(JSC::UnspecifiedBoolType):
(JSC::::leakImpl):
(JSC::adoptWeak):

  • heap/Strong.h:

(JSC::Strong::operator!):
(Strong):
(JSC::Strong::operator UnspecifiedBoolType*):
(JSC::Strong::get):

  • heap/Weak.h:

(Weak):
(JSC::::Weak):
(JSC):
(JSC::::isHashTableDeletedValue):
(JSC::::~Weak):
(JSC::::swap):
(JSC::=):
(JSC::::operator):
(JSC::UnspecifiedBoolType):
(JSC::::release):
(JSC::::clear):
(JSC::::hashTableDeletedValue): Lots of code changes here, but they boil
down to two things:

(*) Allocate WeakImpls from the WeakHeap instead of Handles from the HandleHeap.

(*) Explicitly check WeakImpl::state() for non-liveness before returning
a value (explained above).

These files implement the new Weak<T> heap behavior described above:

  • heap/WeakBlock.cpp: Added.
  • heap/WeakBlock.h: Added.
  • heap/WeakHandleOwner.cpp: Added.
  • heap/WeakHandleOwner.h: Added.
  • heap/WeakHeap.cpp: Added.
  • heap/WeakHeap.h: Added.
  • heap/WeakImpl.h: Added.

One interesting difference from the old heap is that we don't allow
clients to overwrite a WeakImpl after allocating it, and we don't recycle
WeakImpls prior to garbage collection. This is required for lazy finalization,
but it will also help us esablish a useful invariant in the future: allocating
a WeakImpl will be a binding contract to run a finalizer at some point in the
future, even if the WeakImpl is later deallocated.

  • jit/JITStubs.cpp:

(JSC::JITThunks::hostFunctionStub): Check the Weak<T> for ! instead of
its JSValue, since that's our API contract now, and the JSValue might
be stale.

  • runtime/JSCell.h:

(JSC::jsCast): Allow casting NULL pointers because it's useful and harmless.

  • runtime/Structure.cpp:

(JSC::StructureTransitionTable::add): I can't remember why I did this.

  • runtime/StructureTransitionTable.h:
  • runtime/WeakGCMap.h: I had to update these classes because they allocate

and deallocate weak pointers manually. They should probably stop doing that.

Source/WebCore:

Updated WebCore for Weak<T> API changes.

  • bindings/js/DOMWrapperWorld.cpp:

(WebCore::JSStringOwner::finalize): We're not allowed to get() a dead Weak<T>
anymore, so use the debug-only was() helper function instead.

  • bindings/js/JSDOMBinding.h:

(WebCore::uncacheWrapper): Ditto.

  • bindings/js/JSNodeCustom.h:

(WebCore::setInlineCachedWrapper):
(WebCore::clearInlineCachedWrapper): We're not allowed to get() a dead
Weak<T>, so I had to push down these ASSERTs into ScriptWrappable.

  • bindings/js/JSNodeFilterCondition.cpp:

(WebCore::JSNodeFilterCondition::acceptNode): Updated for non-Handle-ness
of Weak<T>.

  • bindings/js/ScriptWrappable.h:

(WebCore::ScriptWrappable::setWrapper):
(WebCore::ScriptWrappable::clearWrapper): Use was(), as above.

Source/WebKit2:

Updated for API change.

  • WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:

(WebKit::NPRuntimeObjectMap::finalize):

Location:
trunk/Source/JavaScriptCore/heap
Files:
7 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/heap/Handle.h

    r95901 r113141  
    6060    operator UnspecifiedBoolType*() const { return (m_slot && *m_slot) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
    6161
     62    HandleSlot slot() const { return m_slot; }
     63
    6264protected:
    6365    HandleBase(HandleSlot slot)
     
    6870    void swap(HandleBase& other) { std::swap(m_slot, other.m_slot); }
    6971
    70     HandleSlot slot() const { return m_slot; }
    7172    void setSlot(HandleSlot slot)
    7273    {
     
    134135private:
    135136    friend class HandleHeap;
     137    friend class WeakBlock;
    136138
    137139    static Handle<T> wrapSlot(HandleSlot slot)
  • trunk/Source/JavaScriptCore/heap/HandleHeap.cpp

    r103243 r113141  
    3232namespace JSC {
    3333
    34 WeakHandleOwner::~WeakHandleOwner()
    35 {
    36 }
    37 
    38 bool WeakHandleOwner::isReachableFromOpaqueRoots(Handle<Unknown>, void*, SlotVisitor&)
    39 {
    40     return false;
    41 }
    42 
    43 void WeakHandleOwner::finalize(Handle<Unknown>, void*)
    44 {
    45 }
    46 
    4734HandleHeap::HandleHeap(JSGlobalData* globalData)
    4835    : m_globalData(globalData)
     
    7461}
    7562
    76 void HandleHeap::visitWeakHandles(HeapRootVisitor& heapRootVisitor)
    77 {
    78     SlotVisitor& visitor = heapRootVisitor.visitor();
    79 
    80     Node* end = m_weakList.end();
    81     for (Node* node = m_weakList.begin(); node != end; node = node->next()) {
    82 #if ENABLE(GC_VALIDATION)
    83         if (!isValidWeakNode(node))
    84             CRASH();
    85 #endif
    86         JSCell* cell = node->slot()->asCell();
    87         if (Heap::isMarked(cell))
    88             continue;
    89 
    90         WeakHandleOwner* weakOwner = node->weakOwner();
    91         if (!weakOwner)
    92             continue;
    93 
    94         if (!weakOwner->isReachableFromOpaqueRoots(Handle<Unknown>::wrapSlot(node->slot()), node->weakOwnerContext(), visitor))
    95             continue;
    96 
    97         heapRootVisitor.visit(node->slot());
    98     }
    99 }
    100 
    101 void HandleHeap::finalizeWeakHandles()
    102 {
    103     Node* end = m_weakList.end();
    104     for (Node* node = m_weakList.begin(); node != end; node = m_nextToFinalize) {
    105         m_nextToFinalize = node->next();
    106 #if ENABLE(GC_VALIDATION)
    107         if (!isValidWeakNode(node))
    108             CRASH();
    109 #endif
    110 
    111         JSCell* cell = node->slot()->asCell();
    112         if (Heap::isMarked(cell))
    113             continue;
    114 
    115         if (WeakHandleOwner* weakOwner = node->weakOwner()) {
    116             weakOwner->finalize(Handle<Unknown>::wrapSlot(node->slot()), node->weakOwnerContext());
    117             if (m_nextToFinalize != node->next()) // Owner deallocated node.
    118                 continue;
    119         }
    120 #if ENABLE(GC_VALIDATION)
    121         if (!isLiveNode(node))
    122             CRASH();
    123 #endif
    124         *node->slot() = JSValue();
    125         SentinelLinkedList<Node>::remove(node);
    126         m_immediateList.push(node);
    127     }
    128    
    129     m_nextToFinalize = 0;
    130 }
    131 
    13263void HandleHeap::writeBarrier(HandleSlot slot, const JSValue& value)
    13364{
     
    14879    if (!value || !value.isCell()) {
    14980        m_immediateList.push(node);
    150         return;
    151     }
    152 
    153     if (node->isWeak()) {
    154         m_weakList.push(node);
    155 #if ENABLE(GC_VALIDATION)
    156         if (!isLiveNode(node))
    157             CRASH();
    158 #endif
    15981        return;
    16082    }
     
    189111    return true;
    190112}
    191 
    192 bool HandleHeap::isValidWeakNode(Node* node)
    193 {
    194     if (!isLiveNode(node))
    195         return false;
    196     if (!node->isWeak())
    197         return false;
    198 
    199     JSValue value = *node->slot();
    200     if (!value || !value.isCell())
    201         return false;
    202 
    203     JSCell* cell = value.asCell();
    204     if (!cell || !cell->structure())
    205         return false;
    206 
    207     return true;
    208 }
    209113#endif
    210114
  • trunk/Source/JavaScriptCore/heap/HandleHeap.h

    r110033 r113141  
    4141class SlotVisitor;
    4242
    43 class JS_EXPORT_PRIVATE WeakHandleOwner {
    44 public:
    45     virtual ~WeakHandleOwner();
    46     virtual bool isReachableFromOpaqueRoots(Handle<Unknown>, void* context, SlotVisitor&);
    47     virtual void finalize(Handle<Unknown>, void* context);
    48 };
    49 
    5043class HandleHeap {
    5144public:
     
    5952    void deallocate(HandleSlot);
    6053
    61     void makeWeak(HandleSlot, WeakHandleOwner* = 0, void* context = 0);
    62     HandleSlot copyWeak(HandleSlot);
    63 
    6454    void visitStrongHandles(HeapRootVisitor&);
    65     void visitWeakHandles(HeapRootVisitor&);
    66     void finalizeWeakHandles();
    6755
    6856    JS_EXPORT_PRIVATE void writeBarrier(HandleSlot, const JSValue&);
    69 
    70 #if !ASSERT_DISABLED
    71     bool hasWeakOwner(HandleSlot, WeakHandleOwner*);
    72     bool hasFinalizer(HandleSlot);
    73 #endif
    7457
    7558    unsigned protectedGlobalObjectCount();
     
    8669        HandleHeap* handleHeap();
    8770
    88         void makeWeak(WeakHandleOwner*, void* context);
    89         bool isWeak();
    90        
    91         WeakHandleOwner* weakOwner();
    92         void* weakOwnerContext();
    93 
    9471        void setPrev(Node*);
    9572        Node* prev();
     
    9976
    10077    private:
    101         WeakHandleOwner* emptyWeakOwner();
    102 
    10378        JSValue m_value;
    10479        HandleHeap* m_handleHeap;
    105         WeakHandleOwner* m_weakOwner;
    106         void* m_weakOwnerContext;
    10780        Node* m_prev;
    10881        Node* m_next;
     
    11588   
    11689#if ENABLE(GC_VALIDATION) || !ASSERT_DISABLED
    117     bool isValidWeakNode(Node*);
    11890    bool isLiveNode(Node*);
    11991#endif
     
    12395
    12496    SentinelLinkedList<Node> m_strongList;
    125     SentinelLinkedList<Node> m_weakList;
    12697    SentinelLinkedList<Node> m_immediateList;
    12798    SinglyLinkedList<Node> m_freeList;
     
    176147}
    177148
    178 inline HandleSlot HandleHeap::copyWeak(HandleSlot other)
    179 {
    180     Node* node = toNode(allocate());
    181     node->makeWeak(toNode(other)->weakOwner(), toNode(other)->weakOwnerContext());
    182     writeBarrier(node->slot(), *other);
    183     *node->slot() = *other;
    184     return toHandle(node);
    185 }
    186 
    187 inline void HandleHeap::makeWeak(HandleSlot handle, WeakHandleOwner* weakOwner, void* context)
    188 {
    189     // Forbid assignment to handles during the finalization phase, since it would violate many GC invariants.
    190     // File a bug with stack trace if you hit this.
    191     if (m_nextToFinalize)
    192         CRASH();
    193     Node* node = toNode(handle);
    194     node->makeWeak(weakOwner, context);
    195 
    196     SentinelLinkedList<Node>::remove(node);
    197     if (!*handle || !handle->isCell()) {
    198         m_immediateList.push(node);
    199         return;
    200     }
    201 
    202     m_weakList.push(node);
    203 }
    204 
    205 #if !ASSERT_DISABLED
    206 inline bool HandleHeap::hasWeakOwner(HandleSlot handle, WeakHandleOwner* weakOwner)
    207 {
    208     return toNode(handle)->weakOwner() == weakOwner;
    209 }
    210 
    211 inline bool HandleHeap::hasFinalizer(HandleSlot handle)
    212 {
    213     return toNode(handle)->weakOwner();
    214 }
    215 #endif
    216 
    217149inline HandleHeap::Node::Node(HandleHeap* handleHeap)
    218150    : m_handleHeap(handleHeap)
    219     , m_weakOwner(0)
    220     , m_weakOwnerContext(0)
    221151    , m_prev(0)
    222152    , m_next(0)
     
    226156inline HandleHeap::Node::Node(WTF::SentinelTag)
    227157    : m_handleHeap(0)
    228     , m_weakOwner(0)
    229     , m_weakOwnerContext(0)
    230158    , m_prev(0)
    231159    , m_next(0)
     
    243171}
    244172
    245 inline void HandleHeap::Node::makeWeak(WeakHandleOwner* weakOwner, void* context)
    246 {
    247     m_weakOwner = weakOwner ? weakOwner : emptyWeakOwner();
    248     m_weakOwnerContext = context;
    249 }
    250 
    251 inline bool HandleHeap::Node::isWeak()
    252 {
    253     return m_weakOwner; // True for emptyWeakOwner().
    254 }
    255 
    256 inline WeakHandleOwner* HandleHeap::Node::weakOwner()
    257 {
    258     return m_weakOwner == emptyWeakOwner() ? 0 : m_weakOwner; // 0 for emptyWeakOwner().
    259 }
    260 
    261 inline void* HandleHeap::Node::weakOwnerContext()
    262 {
    263     ASSERT(weakOwner());
    264     return m_weakOwnerContext;
    265 }
    266 
    267173inline void HandleHeap::Node::setPrev(Node* prev)
    268174{
     
    283189{
    284190    return m_next;
    285 }
    286 
    287 // Sentinel to indicate that a node is weak, but its owner has no meaningful
    288 // callbacks. This allows us to optimize by skipping such nodes.
    289 inline WeakHandleOwner* HandleHeap::Node::emptyWeakOwner()
    290 {
    291     return reinterpret_cast<WeakHandleOwner*>(-1);
    292191}
    293192
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r112624 r113141  
    314314    , m_minBytesPerCycle(heapSizeForHint(heapSize))
    315315    , m_lastFullGCSize(0)
    316     , m_waterMark(0)
    317316    , m_highWaterMark(m_minBytesPerCycle)
    318317    , m_operationInProgress(NoOperation)
     
    320319    , m_storageSpace(this)
    321320    , m_blockFreeingThreadShouldQuit(false)
    322     , m_extraCost(0)
    323321    , m_markListSet(0)
    324322    , m_activityCallback(DefaultGCActivityCallback::create(this))
     
    326324    , m_sharedData(globalData)
    327325    , m_slotVisitor(m_sharedData)
     326    , m_weakHeap(this)
    328327    , m_handleHeap(globalData)
    329328    , m_isSafeToCollect(false)
     
    377376    clearMarks();
    378377
    379     m_handleHeap.finalizeWeakHandles();
     378    m_weakHeap.finalizeAll();
    380379    m_globalData->smallStrings.finalizeSmallStrings();
    381380    shrink();
     
    467466    // collecting more frequently as long as it stays alive.
    468467
    469     if (m_extraCost > maxExtraCost && m_extraCost > highWaterMark() / 2)
    470         collectAllGarbage();
    471     m_extraCost += cost;
     468    addToWaterMark(cost);
    472469}
    473470
     
    688685    }
    689686
    690     // Weak handles must be marked last, because their owners use the set of
    691     // opaque roots to determine reachability.
    692     {
    693         GCPHASE(VisitingWeakHandles);
     687    // Weak references must be marked last because their liveness depends on
     688    // the liveness of the rest of the object graph.
     689    {
     690        GCPHASE(VisitingLiveWeakHandles);
    694691        while (true) {
    695             m_handleHeap.visitWeakHandles(heapRootVisitor);
     692            m_weakHeap.visitLiveWeakImpls(heapRootVisitor);
    696693            harvestWeakReferences();
    697694            if (visitor.isEmpty())
     
    706703        }
    707704    }
     705
     706    {
     707        GCPHASE(VisitingDeadWeakHandles);
     708        m_weakHeap.visitDeadWeakImpls(heapRootVisitor);
     709    }
     710
    708711    GCCOUNTER(VisitedValueCount, visitor.visitCount());
    709712
     
    816819    {
    817820        GCPHASE(FinalizeWeakHandles);
    818         m_handleHeap.finalizeWeakHandles();
     821        m_weakHeap.sweep();
    819822        m_globalData->smallStrings.finalizeSmallStrings();
    820823    }
     
    847850    if (fullGC) {
    848851        m_lastFullGCSize = newSize;
    849         setHighWaterMark(max(proportionalBytes, m_minBytesPerCycle));
     852        m_highWaterMark = max(proportionalBytes, m_minBytesPerCycle);
    850853    }
    851854    double lastGCEndTime = WTF::currentTime();
     
    863866void Heap::resetAllocators()
    864867{
    865     m_extraCost = 0;
    866868    m_objectSpace.resetAllocators();
     869    m_weakHeap.resetAllocator();
    867870}
    868871
     
    925928void Heap::addFinalizer(JSCell* cell, Finalizer finalizer)
    926929{
    927     Weak<JSCell> weak(*globalData(), cell, &m_finalizerOwner, reinterpret_cast<void*>(finalizer));
    928     weak.leakHandle(); // Balanced by FinalizerOwner::finalize().
     930    weakHeap()->allocate(cell, &m_finalizerOwner, reinterpret_cast<void*>(finalizer)); // Balanced by FinalizerOwner::finalize().
    929931}
    930932
    931933void Heap::FinalizerOwner::finalize(Handle<Unknown> handle, void* context)
    932934{
    933     Weak<JSCell> weak(Weak<JSCell>::Adopt, handle);
     935    HandleSlot slot = handle.slot();
    934936    Finalizer finalizer = reinterpret_cast<Finalizer>(context);
    935     finalizer(weak.get());
     937    finalizer(slot->asCell());
     938    WeakHeap::deallocate(WeakImpl::asWeakImpl(slot));
    936939}
    937940
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r112624 r113141  
    3131#include "MarkedSpace.h"
    3232#include "SlotVisitor.h"
     33#include "WeakHandleOwner.h"
     34#include "WeakHeap.h"
    3335#include "WriteBarrierSupport.h"
    3436#include <wtf/DoublyLinkedList.h>
     
    137139        template<typename Functor> typename Functor::ReturnType forEachProtectedCell();
    138140
     141        WeakHeap* weakHeap() { return &m_weakHeap; }
    139142        HandleHeap* handleHeap() { return &m_handleHeap; }
    140143        HandleStack* handleStack() { return &m_handleStack; }
    141144
    142145        void getConservativeRegisterRoots(HashSet<JSCell*>& roots);
     146
     147        void addToWaterMark(size_t);
    143148
    144149        double lastGCLength() { return m_lastGCLength; }
     
    161166        size_t waterMark();
    162167        size_t highWaterMark();
    163         void setHighWaterMark(size_t);
    164168        bool shouldCollect();
    165169
     
    205209        const size_t m_minBytesPerCycle;
    206210        size_t m_lastFullGCSize;
    207         size_t m_waterMark;
    208211        size_t m_highWaterMark;
    209212       
     
    224227#endif
    225228
    226         size_t m_extraCost;
    227 
    228229        ProtectCountSet m_protectedValues;
    229230        Vector<Vector<ValueStringPair>* > m_tempSortingVectors;
     
    237238        SlotVisitor m_slotVisitor;
    238239
     240        WeakHeap m_weakHeap;
    239241        HandleHeap m_handleHeap;
    240242        HandleStack m_handleStack;
     
    301303    }
    302304
    303     inline void Heap::setHighWaterMark(size_t newHighWaterMark)
    304     {
    305         m_highWaterMark = newHighWaterMark;
     305    inline void Heap::addToWaterMark(size_t size)
     306    {
     307        m_objectSpace.addToWaterMark(size);
     308        if (waterMark() > highWaterMark())
     309            collect(DoNotSweep);
    306310    }
    307311
  • trunk/Source/JavaScriptCore/heap/MarkedSpace.cpp

    r107445 r113141  
    3333MarkedSpace::MarkedSpace(Heap* heap)
    3434    : m_waterMark(0)
    35     , m_nurseryWaterMark(0)
    3635    , m_heap(heap)
    3736{
     
    5049{
    5150    m_waterMark = 0;
    52     m_nurseryWaterMark = 0;
    5351
    5452    for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) {
  • trunk/Source/JavaScriptCore/heap/MarkedSpace.h

    r110033 r113141  
    6767
    6868    size_t waterMark();
    69     size_t nurseryWaterMark();
     69    void addToWaterMark(size_t);
    7070
    7171    typedef HashSet<MarkedBlock*>::iterator BlockIterator;
     
    7878    void shrink();
    7979    void freeBlocks(MarkedBlock* head);
     80
    8081    void didAddBlock(MarkedBlock*);
    8182    void didConsumeFreeList(MarkedBlock*);
     
    103104
    104105    size_t m_waterMark;
    105     size_t m_nurseryWaterMark;
    106106    Heap* m_heap;
    107107    MarkedBlockSet m_blocks;
     
    113113}
    114114
    115 inline size_t MarkedSpace::nurseryWaterMark()
    116 {
    117     return m_nurseryWaterMark;
     115inline void MarkedSpace::addToWaterMark(size_t size)
     116{
     117    m_waterMark += size;
    118118}
    119119
     
    200200inline void MarkedSpace::didConsumeFreeList(MarkedBlock* block)
    201201{
    202     m_nurseryWaterMark += block->capacity() - block->size();
    203202    m_waterMark += block->capacity();
    204203}
  • trunk/Source/JavaScriptCore/heap/PassWeak.h

    r110033 r113141  
    2727#define PassWeak_h
    2828
     29#include "JSCell.h"
    2930#include <wtf/Assertions.h>
    30 #include "Handle.h"
    3131#include <wtf/NullPtr.h>
    3232#include <wtf/TypeTraits.h>
     
    3636template<typename T> class Weak;
    3737template<typename T> class PassWeak;
    38 template<typename T> PassWeak<T> adoptWeak(HandleSlot);
    39 
    40 template<typename T> class PassWeak : public Handle<T> {
    41     using Handle<T>::slot;
    42     using Handle<T>::setSlot;
    43 
     38template<typename T> PassWeak<T> adoptWeak(WeakImpl*);
     39
     40template<typename Base, typename T> class WeakImplAccessor {
    4441public:
    45     typedef typename Handle<T>::ExternalType ExternalType;
    46 
    47     PassWeak() : Handle<T>() { }
    48     PassWeak(std::nullptr_t) : Handle<T>() { }
    49 
    50     PassWeak(JSGlobalData& globalData, ExternalType externalType = ExternalType(), WeakHandleOwner* weakOwner = 0, void* context = 0)
    51         : Handle<T>(globalData.heap.handleHeap()->allocate())
    52     {
    53         HandleHeap::heapFor(slot())->makeWeak(slot(), weakOwner, context);
    54         JSValue value = HandleTypes<T>::toJSValue(externalType);
    55         HandleHeap::heapFor(slot())->writeBarrier(slot(), value);
    56         *slot() = value;
    57     }
     42    typedef T* GetType;
     43
     44    T* operator->() const;
     45    T& operator*() const;
     46    GetType get() const;
     47
     48#if !ASSERT_DISABLED
     49    bool was(GetType) const;
     50#endif
     51};
     52
     53template<typename Base> class WeakImplAccessor<Base, Unknown> {
     54public:
     55    typedef JSValue GetType;
     56
     57    const JSValue* operator->() const;
     58    const JSValue& operator*() const;
     59    GetType get() const;
     60};
     61
     62template<typename T> class PassWeak : public WeakImplAccessor<PassWeak<T>, T> {
     63public:
     64    friend class WeakImplAccessor<PassWeak<T>, T>;
     65    typedef typename WeakImplAccessor<PassWeak<T>, T>::GetType GetType;
     66
     67    PassWeak();
     68    PassWeak(std::nullptr_t);
     69    PassWeak(JSGlobalData&, GetType = GetType(), WeakHandleOwner* = 0, void* context = 0);
    5870
    5971    // It somewhat breaks the type system to allow transfer of ownership out of
    6072    // a const PassWeak. However, it makes it much easier to work with PassWeak
    6173    // temporaries, and we don't have a need to use real const PassWeaks anyway.
    62     PassWeak(const PassWeak& o) : Handle<T>(o.leakHandle()) { }
    63     template<typename U> PassWeak(const PassWeak<U>& o) : Handle<T>(o.leakHandle()) { }
    64 
    65     ~PassWeak()
    66     {
    67         if (!slot())
    68             return;
    69         HandleHeap::heapFor(slot())->deallocate(slot());
    70         setSlot(0);
    71     }
    72 
    73     ExternalType get() const { return  HandleTypes<T>::getFromSlot(slot()); }
    74 
    75     HandleSlot leakHandle() const WARN_UNUSED_RETURN;
     74    PassWeak(const PassWeak&);
     75    template<typename U> PassWeak(const PassWeak<U>&);
     76
     77    ~PassWeak();
     78
     79    bool operator!() const;
     80
     81    // This conversion operator allows implicit conversion to bool but not to other integer types.
     82    typedef JSValue (PassWeak::*UnspecifiedBoolType);
     83    operator UnspecifiedBoolType*() const;
     84
     85    WeakImpl* leakImpl() const WARN_UNUSED_RETURN;
    7686
    7787private:
    78     friend PassWeak adoptWeak<T>(HandleSlot);
    79 
    80     explicit PassWeak(HandleSlot slot) : Handle<T>(slot) { }
     88    friend PassWeak adoptWeak<T>(WeakImpl*);
     89    explicit PassWeak(WeakImpl*);
     90
     91    WeakImpl* m_impl;
    8192};
    8293
    83 template<typename T> inline HandleSlot PassWeak<T>::leakHandle() const
    84 {
    85     HandleSlot slot = this->slot();
    86     const_cast<PassWeak<T>*>(this)->setSlot(0);
    87     return slot;
    88 }
    89 
    90 template<typename T> PassWeak<T> adoptWeak(HandleSlot slot)
    91 {
    92     return PassWeak<T>(slot);
     94template<typename Base, typename T> inline T* WeakImplAccessor<Base, T>::operator->() const
     95{
     96    ASSERT(static_cast<const Base*>(this)->m_impl && static_cast<const Base*>(this)->m_impl->state() == WeakImpl::Live);
     97    return jsCast<T*>(static_cast<const Base*>(this)->m_impl->jsValue().asCell());
     98}
     99
     100template<typename Base, typename T> inline T& WeakImplAccessor<Base, T>::operator*() const
     101{
     102    ASSERT(static_cast<const Base*>(this)->m_impl && static_cast<const Base*>(this)->m_impl->state() == WeakImpl::Live);
     103    return *jsCast<T*>(static_cast<const Base*>(this)->m_impl->jsValue().asCell());
     104}
     105
     106template<typename Base, typename T> inline typename WeakImplAccessor<Base, T>::GetType WeakImplAccessor<Base, T>::get() const
     107{
     108    if (!static_cast<const Base*>(this)->m_impl || static_cast<const Base*>(this)->m_impl->state() != WeakImpl::Live)
     109        return GetType();
     110    return jsCast<T*>(static_cast<const Base*>(this)->m_impl->jsValue().asCell());
     111}
     112
     113#if !ASSERT_DISABLED
     114template<typename Base, typename T> inline bool WeakImplAccessor<Base, T>::was(typename WeakImplAccessor<Base, T>::GetType other) const
     115{
     116    return jsCast<T*>(static_cast<const Base*>(this)->m_impl->jsValue().asCell()) == other;
     117}
     118#endif
     119
     120template<typename Base> inline const JSValue* WeakImplAccessor<Base, Unknown>::operator->() const
     121{
     122    ASSERT(static_cast<const Base*>(this)->m_impl && static_cast<const Base*>(this)->m_impl->state() == WeakImpl::Live);
     123    return &static_cast<const Base*>(this)->m_impl->jsValue();
     124}
     125
     126template<typename Base> inline const JSValue& WeakImplAccessor<Base, Unknown>::operator*() const
     127{
     128    ASSERT(static_cast<const Base*>(this)->m_impl && static_cast<const Base*>(this)->m_impl->state() == WeakImpl::Live);
     129    return static_cast<const Base*>(this)->m_impl->jsValue();
     130}
     131
     132template<typename Base> inline typename WeakImplAccessor<Base, Unknown>::GetType WeakImplAccessor<Base, Unknown>::get() const
     133{
     134    if (!static_cast<const Base*>(this)->m_impl || static_cast<const Base*>(this)->m_impl->state() != WeakImpl::Live)
     135        return GetType();
     136    return static_cast<const Base*>(this)->m_impl->jsValue();
     137}
     138
     139template<typename T> inline PassWeak<T>::PassWeak()
     140    : m_impl(0)
     141{
     142}
     143
     144template<typename T> inline PassWeak<T>::PassWeak(std::nullptr_t)
     145    : m_impl(0)
     146{
     147}
     148
     149template<typename T> inline PassWeak<T>::PassWeak(JSGlobalData& globalData, typename PassWeak<T>::GetType getType, WeakHandleOwner* weakOwner, void* context)
     150    : m_impl(globalData.heap.weakHeap()->allocate(getType, weakOwner, context))
     151{
     152}
     153
     154template<typename T> inline PassWeak<T>::PassWeak(const PassWeak& o)
     155    : m_impl(o.leakImpl())
     156{
     157}
     158
     159template<typename T> template<typename U> inline PassWeak<T>::PassWeak(const PassWeak<U>& o)
     160    : m_impl(o.leakImpl())
     161{
     162}
     163
     164template<typename T> inline PassWeak<T>::~PassWeak()
     165{
     166    if (!m_impl)
     167        return;
     168    WeakHeap::deallocate(m_impl);
     169}
     170
     171template<typename T> inline bool PassWeak<T>::operator!() const
     172{
     173    return !m_impl || m_impl->state() != WeakImpl::Live || !m_impl->jsValue();
     174}
     175
     176template<typename T> inline PassWeak<T>::operator UnspecifiedBoolType*() const
     177{
     178    return reinterpret_cast<UnspecifiedBoolType*>(!!*this);
     179}
     180
     181template<typename T> inline PassWeak<T>::PassWeak(WeakImpl* impl)
     182: m_impl(impl)
     183{
     184}
     185
     186template<typename T> inline WeakImpl* PassWeak<T>::leakImpl() const
     187{
     188    WeakImpl* tmp = 0;
     189    std::swap(tmp, const_cast<WeakImpl*&>(m_impl));
     190    return tmp;
     191}
     192
     193template<typename T> PassWeak<T> inline adoptWeak(WeakImpl* impl)
     194{
     195    return PassWeak<T>(impl);
    93196}
    94197
  • trunk/Source/JavaScriptCore/heap/Strong.h

    r110033 r113141  
    8282    }
    8383
     84    bool operator!() const { return !slot() || !*slot(); }
     85
     86    // This conversion operator allows implicit conversion to bool but not to other integer types.
     87    typedef JSValue (HandleBase::*UnspecifiedBoolType);
     88    operator UnspecifiedBoolType*() const { return !!*this ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
     89
    8490    void swap(Strong& other)
    8591    {
    8692        Handle<T>::swap(other);
    8793    }
     94
     95    ExternalType get() const { return HandleTypes<T>::getFromSlot(this->slot()); }
    8896
    8997    void set(JSGlobalData&, ExternalType);
  • trunk/Source/JavaScriptCore/heap/Weak.h

    r110033 r113141  
    2828
    2929#include <wtf/Assertions.h>
    30 #include "Handle.h"
    31 #include "HandleHeap.h"
    3230#include "JSGlobalData.h"
    3331#include "PassWeak.h"
     
    3533namespace JSC {
    3634
    37 // A weakly referenced handle that becomes 0 when the value it points to is garbage collected.
    38 template <typename T> class Weak : public Handle<T> {
     35template<typename T> class Weak : public WeakImplAccessor<Weak<T>, T> {
    3936    WTF_MAKE_NONCOPYABLE(Weak);
     37public:
     38    friend class WeakImplAccessor<Weak<T>, T>;
     39    typedef typename WeakImplAccessor<Weak<T>, T>::GetType GetType;
    4040
    41     using Handle<T>::slot;
    42     using Handle<T>::setSlot;
    43 
    44 public:
    45     typedef typename Handle<T>::ExternalType ExternalType;
    46 
    47     Weak()
    48         : Handle<T>()
    49     {
    50     }
    51 
    52     Weak(std::nullptr_t)
    53         : Handle<T>()
    54     {
    55     }
    56 
    57     Weak(JSGlobalData& globalData, ExternalType externalType = ExternalType(), WeakHandleOwner* weakOwner = 0, void* context = 0)
    58         : Handle<T>(globalData.heap.handleHeap()->allocate())
    59     {
    60         HandleHeap::heapFor(slot())->makeWeak(slot(), weakOwner, context);
    61         JSValue value = HandleTypes<T>::toJSValue(externalType);
    62         HandleHeap::heapFor(slot())->writeBarrier(slot(), value);
    63         *slot() = value;
    64     }
    65 
    66     enum AdoptTag { Adopt };
    67     template<typename U> Weak(AdoptTag, Handle<U> handle)
    68         : Handle<T>(handle.slot())
    69     {
    70         validateCell(get());
    71     }
     41    Weak();
     42    Weak(std::nullptr_t);
     43    Weak(JSGlobalData&, GetType = GetType(), WeakHandleOwner* = 0, void* context = 0);
    7244
    7345    enum HashTableDeletedValueTag { HashTableDeletedValue };
    74     bool isHashTableDeletedValue() const { return slot() == hashTableDeletedValue(); }
    75     Weak(HashTableDeletedValueTag)
    76         : Handle<T>(hashTableDeletedValue())
    77     {
    78     }
     46    bool isHashTableDeletedValue() const;
     47    Weak(HashTableDeletedValueTag);
    7948
    80     template<typename U> Weak(const PassWeak<U>& other)
    81         : Handle<T>(other.leakHandle())
    82     {
    83     }
     49    template<typename U> Weak(const PassWeak<U>&);
    8450
    85     ~Weak()
    86     {
    87         clear();
    88     }
     51    ~Weak();
    8952
    90     void swap(Weak& other)
    91     {
    92         Handle<T>::swap(other);
    93     }
     53    void swap(Weak&);
     54    Weak& operator=(const PassWeak<T>&);
     55   
     56    bool operator!() const;
    9457
    95     Weak& operator=(const PassWeak<T>&);
     58    // This conversion operator allows implicit conversion to bool but not to other integer types.
     59    typedef JSValue (HandleBase::*UnspecifiedBoolType);
     60    operator UnspecifiedBoolType*() const;
    9661
    97     ExternalType get() const { return  HandleTypes<T>::getFromSlot(slot()); }
     62    PassWeak<T> release();
     63    void clear();
    9864   
    99     PassWeak<T> release() { PassWeak<T> tmp = adoptWeak<T>(slot()); setSlot(0); return tmp; }
     65private:
     66    static WeakImpl* hashTableDeletedValue();
    10067
    101     void clear()
    102     {
    103         if (!slot())
    104             return;
    105         HandleHeap::heapFor(slot())->deallocate(slot());
    106         setSlot(0);
    107     }
    108    
    109     HandleSlot leakHandle()
    110     {
    111         ASSERT(HandleHeap::heapFor(slot())->hasFinalizer(slot()));
    112         HandleSlot result = slot();
    113         setSlot(0);
    114         return result;
    115     }
     68    WeakImpl* m_impl;
     69};
    11670
    117 private:
    118     static HandleSlot hashTableDeletedValue() { return reinterpret_cast<HandleSlot>(-1); }
    119 };
     71template<typename T> inline Weak<T>::Weak()
     72    : m_impl(0)
     73{
     74}
     75
     76template<typename T> inline Weak<T>::Weak(std::nullptr_t)
     77    : m_impl(0)
     78{
     79}
     80
     81template<typename T> inline Weak<T>::Weak(JSGlobalData& globalData, typename Weak<T>::GetType getType, WeakHandleOwner* weakOwner, void* context)
     82    : m_impl(globalData.heap.weakHeap()->allocate(getType, weakOwner, context))
     83{
     84}
     85
     86template<typename T> inline bool Weak<T>::isHashTableDeletedValue() const
     87{
     88    return m_impl == hashTableDeletedValue();
     89}
     90
     91template<typename T> inline Weak<T>::Weak(typename Weak<T>::HashTableDeletedValueTag)
     92    : m_impl(hashTableDeletedValue())
     93{
     94}
     95
     96template<typename T> template<typename U>  inline Weak<T>::Weak(const PassWeak<U>& other)
     97    : m_impl(other.leakImpl())
     98{
     99}
     100
     101template<typename T> inline Weak<T>::~Weak()
     102{
     103    clear();
     104}
    120105
    121106template<class T> inline void swap(Weak<T>& a, Weak<T>& b)
     
    124109}
    125110
     111template<typename T> inline void Weak<T>::swap(Weak& other)
     112{
     113    std::swap(m_impl, other.m_impl);
     114}
     115
    126116template<typename T> inline Weak<T>& Weak<T>::operator=(const PassWeak<T>& o)
    127117{
    128118    clear();
    129     setSlot(o.leakHandle());
     119    m_impl = o.leakImpl();
    130120    return *this;
     121}
     122
     123template<typename T> inline bool Weak<T>::operator!() const
     124{
     125    return !m_impl || !m_impl->jsValue() || m_impl->state() != WeakImpl::Live;
     126}
     127
     128template<typename T> inline Weak<T>::operator UnspecifiedBoolType*() const
     129{
     130    return reinterpret_cast<UnspecifiedBoolType*>(!!*this);
     131}
     132
     133template<typename T> inline PassWeak<T> Weak<T>::release()
     134{
     135    PassWeak<T> tmp = adoptWeak<T>(m_impl);
     136    m_impl = 0;
     137    return tmp;
     138}
     139
     140template<typename T> inline void Weak<T>::clear()
     141{
     142    if (!m_impl)
     143        return;
     144    WeakHeap::deallocate(m_impl);
     145    m_impl = 0;
     146}
     147   
     148template<typename T> inline WeakImpl* Weak<T>::hashTableDeletedValue()
     149{
     150    return reinterpret_cast<WeakImpl*>(-1);
    131151}
    132152
     
    152172    static PassOutType passOut(EmptyValueType) { return PassOutType(); }
    153173
    154     typedef typename StorageType::ExternalType PeekType;
     174    typedef typename StorageType::GetType PeekType;
    155175    static PeekType peek(const StorageType& value) { return value.get(); }
    156176    static PeekType peek(EmptyValueType) { return PeekType(); }
Note: See TracChangeset for help on using the changeset viewer.