Commit 7ffc27bb authored by tkent@chromium.org's avatar tkent@chromium.org

Oilpan: Add support of pre-finalization callback to Oilpan infrastructure.

This CL introduces:
 - ThreadState::registerPreFinalizer(T&)
 - ThreadState::unregisterPreFinalizer(T&)
 - USING_PRE_FINALIZER(Class, method)

They are used like the following:

class Foo : GarbageCollected<Foo> {
    USING_PRE_FINALIZER(Foo, dispose);
public:
    Foo() { ThreadState::current()->registerPreFinalizer(*this); }
    void trace(Visitor*);
    ...
private:
    void dispose();

    Member<Bar> m_bar;
};

void Foo::dispose()
{
    m_bar->doesSomething();
}


BUG=420515

Review URL: https://codereview.chromium.org/623033002

git-svn-id: svn://svn.chromium.org/blink/trunk@183253 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 2a2e8c5f
...@@ -333,7 +333,7 @@ void IDBCursor::setValueReady(IDBKey* key, IDBKey* primaryKey, PassRefPtr<Shared ...@@ -333,7 +333,7 @@ void IDBCursor::setValueReady(IDBKey* key, IDBKey* primaryKey, PassRefPtr<Shared
m_blobInfo = blobInfo; m_blobInfo = blobInfo;
m_valueDirty = true; m_valueDirty = true;
if (m_blobInfo && m_blobInfo->size() > 0) if (m_blobInfo && m_blobInfo->size() > 0)
V8PerIsolateData::from(m_request->scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->registerCursor(*this); ThreadState::current()->registerPreFinalizer(*this);
} }
m_gotValue = true; m_gotValue = true;
...@@ -360,7 +360,7 @@ void IDBCursor::handleBlobAcks() ...@@ -360,7 +360,7 @@ void IDBCursor::handleBlobAcks()
ASSERT(m_request); ASSERT(m_request);
m_transaction->db()->ackReceivedBlobs(m_blobInfo.get()); m_transaction->db()->ackReceivedBlobs(m_blobInfo.get());
m_blobInfo.clear(); m_blobInfo.clear();
V8PerIsolateData::from(m_request->scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->unregisterCursor(*this); ThreadState::current()->unregisterPreFinalizer(*this);
} }
} }
......
...@@ -47,12 +47,12 @@ class WebBlobInfo; ...@@ -47,12 +47,12 @@ class WebBlobInfo;
class IDBCursor : public GarbageCollectedFinalized<IDBCursor>, public ScriptWrappable { class IDBCursor : public GarbageCollectedFinalized<IDBCursor>, public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
USING_PRE_FINALIZER(IDBCursor, dispose);
public: public:
static WebIDBCursorDirection stringToDirection(const String& modeString, ExceptionState&); static WebIDBCursorDirection stringToDirection(const String& modeString, ExceptionState&);
static IDBCursor* create(PassOwnPtr<WebIDBCursor>, WebIDBCursorDirection, IDBRequest*, IDBAny* source, IDBTransaction*); static IDBCursor* create(PassOwnPtr<WebIDBCursor>, WebIDBCursorDirection, IDBRequest*, IDBAny* source, IDBTransaction*);
virtual ~IDBCursor(); virtual ~IDBCursor();
void dispose();
void trace(Visitor*); void trace(Visitor*);
void contextWillBeDestroyed() { m_backend.clear(); } void contextWillBeDestroyed() { m_backend.clear(); }
...@@ -87,6 +87,7 @@ protected: ...@@ -87,6 +87,7 @@ protected:
IDBCursor(PassOwnPtr<WebIDBCursor>, WebIDBCursorDirection, IDBRequest*, IDBAny* source, IDBTransaction*); IDBCursor(PassOwnPtr<WebIDBCursor>, WebIDBCursorDirection, IDBRequest*, IDBAny* source, IDBTransaction*);
private: private:
void dispose();
IDBObjectStore* effectiveObjectStore() const; IDBObjectStore* effectiveObjectStore() const;
void handleBlobAcks(); void handleBlobAcks();
......
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
#include "config.h" #include "config.h"
#include "modules/indexeddb/IDBPendingTransactionMonitor.h" #include "modules/indexeddb/IDBPendingTransactionMonitor.h"
#include "modules/indexeddb/IDBCursor.h"
#include "modules/indexeddb/IDBRequest.h"
#include "modules/indexeddb/IDBTransaction.h" #include "modules/indexeddb/IDBTransaction.h"
namespace blink { namespace blink {
...@@ -36,10 +34,6 @@ IDBPendingTransactionMonitor::IDBPendingTransactionMonitor() ...@@ -36,10 +34,6 @@ IDBPendingTransactionMonitor::IDBPendingTransactionMonitor()
{ {
} }
IDBPendingTransactionMonitor::~IDBPendingTransactionMonitor()
{
}
void IDBPendingTransactionMonitor::addNewTransaction(IDBTransaction& transaction) void IDBPendingTransactionMonitor::addNewTransaction(IDBTransaction& transaction)
{ {
m_transactions.append(&transaction); m_transactions.append(&transaction);
...@@ -53,99 +47,4 @@ void IDBPendingTransactionMonitor::deactivateNewTransactions() ...@@ -53,99 +47,4 @@ void IDBPendingTransactionMonitor::deactivateNewTransactions()
m_transactions.clear(); m_transactions.clear();
} }
// IDBDisposerDispatcher should be RefCounted because it should outlive all of
// target objects.
class IDBDisposerDispatcher: public RefCounted<IDBDisposerDispatcher> {
public:
static PassRefPtr<IDBDisposerDispatcher> create() { return adoptRef(new IDBDisposerDispatcher()); }
private:
IDBDisposerDispatcher() { }
template<typename Owner, typename Target>
class Disposer {
public:
static PassOwnPtr<Disposer> create(Owner& owner, Target& target) { return adoptPtr(new Disposer(owner, target)); }
~Disposer()
{
if (!m_isDisabled)
m_target.dispose();
}
void setDisabled() { m_isDisabled = true; }
private:
Disposer(Owner& owner, Target& target)
: m_owner(owner)
, m_target(target)
, m_isDisabled(false)
{
}
RefPtr<Owner> m_owner;
Target& m_target;
bool m_isDisabled;
};
template<typename Target>
class DisposerMap {
DISALLOW_ALLOCATION();
public:
void registerTarget(IDBDisposerDispatcher& dispatcher, Target& target)
{
ASSERT(!m_disposerMap.contains(&target));
m_disposerMap.add(&target, Disposer<IDBDisposerDispatcher, Target>::create(dispatcher, target));
}
void unregisterTarget(IDBDisposerDispatcher& dispatcher, Target& target)
{
// Skip this function if this is called in Target::dispose().
if (ThreadState::current()->isSweepInProgress())
return;
auto it = m_disposerMap.find(&target);
ASSERT(it != m_disposerMap.end());
if (it == m_disposerMap.end())
return;
// m_disposerMap.remove() will trigger ~Disposer. We should not call
// Target::dispose() in ~Disposer in this case.
it->value->setDisabled();
m_disposerMap.remove(it);
}
private:
PersistentHeapHashMap<WeakMember<Target>, OwnPtr<Disposer<IDBDisposerDispatcher, Target>>> m_disposerMap;
};
DisposerMap<IDBRequest> m_requests;
DisposerMap<IDBCursor> m_cursors;
friend class IDBPendingTransactionMonitor;
};
void IDBPendingTransactionMonitor::registerRequest(IDBRequest& request)
{
if (!m_dispatcher)
m_dispatcher = IDBDisposerDispatcher::create();
m_dispatcher->m_requests.registerTarget(*m_dispatcher, request);
}
void IDBPendingTransactionMonitor::unregisterRequest(IDBRequest& request)
{
// We should not unregister without registeration.
ASSERT(m_dispatcher);
m_dispatcher->m_requests.unregisterTarget(*m_dispatcher, request);
}
void IDBPendingTransactionMonitor::registerCursor(IDBCursor& cursor)
{
if (!m_dispatcher)
m_dispatcher = IDBDisposerDispatcher::create();
m_dispatcher->m_cursors.registerTarget(*m_dispatcher, cursor);
}
void IDBPendingTransactionMonitor::unregisterCursor(IDBCursor& cursor)
{
// We should not unregister without registeration.
ASSERT(m_dispatcher);
m_dispatcher->m_cursors.unregisterTarget(*m_dispatcher, cursor);
}
} // namespace blink } // namespace blink
...@@ -31,42 +31,23 @@ ...@@ -31,42 +31,23 @@
namespace blink { namespace blink {
class IDBCursor;
class IDBDisposerDispatcher;
class IDBRequest;
class IDBTransaction; class IDBTransaction;
// This class keeps track of the transactions created during the current // This class keeps track of the transactions created during the current
// Javascript execution context. Transactions have an internal |active| flag // Javascript execution context. Transactions have an internal |active| flag
// which is set to true on creation, but must be set to false when control // which is set to true on creation, but must be set to false when control
// returns to the event loop. // returns to the event loop.
// Also, this class is responsible to call IDBRequest::dispose() before an
// IDBRequest object dies, and responsible to call IDBCursor::dispose() before
// an IDBCursor object dies.
// FIXME: Rename the class name.
class IDBPendingTransactionMonitor { class IDBPendingTransactionMonitor {
WTF_MAKE_NONCOPYABLE(IDBPendingTransactionMonitor); WTF_MAKE_NONCOPYABLE(IDBPendingTransactionMonitor);
public: public:
IDBPendingTransactionMonitor(); IDBPendingTransactionMonitor();
~IDBPendingTransactionMonitor();
void addNewTransaction(IDBTransaction&); void addNewTransaction(IDBTransaction&);
void deactivateNewTransactions(); void deactivateNewTransactions();
void registerRequest(IDBRequest&);
// It's ok to call unregisterRequest(*this) inside
// IDBRequest::dispose(). But we must not call unregisterRequest() with
// an object different from |this| of IDBRequest::dispose().
void unregisterRequest(IDBRequest&);
void registerCursor(IDBCursor&);
// It's ok to call unregisterCursor(*this) inside IDBCursor::dispose(). But
// we must not call unregisterCursor() with an object different from |this|
// of IDBCursor::dispose().
void unregisterCursor(IDBCursor&);
private: private:
PersistentHeapVector<Member<IDBTransaction> > m_transactions; PersistentHeapVector<Member<IDBTransaction> > m_transactions;
RefPtr<IDBDisposerDispatcher> m_dispatcher;
}; };
} // namespace blink } // namespace blink
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include "modules/indexeddb/IDBCursorWithValue.h" #include "modules/indexeddb/IDBCursorWithValue.h"
#include "modules/indexeddb/IDBDatabase.h" #include "modules/indexeddb/IDBDatabase.h"
#include "modules/indexeddb/IDBEventDispatcher.h" #include "modules/indexeddb/IDBEventDispatcher.h"
#include "modules/indexeddb/IDBPendingTransactionMonitor.h"
#include "modules/indexeddb/IDBTracing.h" #include "modules/indexeddb/IDBTracing.h"
#include "platform/SharedBuffer.h" #include "platform/SharedBuffer.h"
#include "public/platform/WebBlobInfo.h" #include "public/platform/WebBlobInfo.h"
...@@ -215,7 +214,7 @@ void IDBRequest::setBlobInfo(PassOwnPtr<Vector<WebBlobInfo>> blobInfo) ...@@ -215,7 +214,7 @@ void IDBRequest::setBlobInfo(PassOwnPtr<Vector<WebBlobInfo>> blobInfo)
ASSERT(!m_blobInfo); ASSERT(!m_blobInfo);
m_blobInfo = blobInfo; m_blobInfo = blobInfo;
if (m_blobInfo && m_blobInfo->size() > 0) if (m_blobInfo && m_blobInfo->size() > 0)
V8PerIsolateData::from(scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->registerRequest(*this); ThreadState::current()->registerPreFinalizer(*this);
} }
void IDBRequest::handleBlobAcks() void IDBRequest::handleBlobAcks()
...@@ -223,7 +222,7 @@ void IDBRequest::handleBlobAcks() ...@@ -223,7 +222,7 @@ void IDBRequest::handleBlobAcks()
if (m_blobInfo.get() && m_blobInfo->size()) { if (m_blobInfo.get() && m_blobInfo->size()) {
m_transaction->db()->ackReceivedBlobs(m_blobInfo.get()); m_transaction->db()->ackReceivedBlobs(m_blobInfo.get());
m_blobInfo.clear(); m_blobInfo.clear();
V8PerIsolateData::from(scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->unregisterRequest(*this); ThreadState::current()->unregisterPreFinalizer(*this);
} }
} }
...@@ -461,7 +460,7 @@ bool IDBRequest::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event) ...@@ -461,7 +460,7 @@ bool IDBRequest::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
cursorToNotify = getResultCursor(); cursorToNotify = getResultCursor();
if (cursorToNotify) { if (cursorToNotify) {
if (m_blobInfo && m_blobInfo->size() > 0) if (m_blobInfo && m_blobInfo->size() > 0)
V8PerIsolateData::from(scriptState()->isolate())->ensureIDBPendingTransactionMonitor()->unregisterRequest(*this); ThreadState::current()->unregisterPreFinalizer(*this);
cursorToNotify->setValueReady(m_cursorKey.release(), m_cursorPrimaryKey.release(), m_cursorValue.release(), m_blobInfo.release()); cursorToNotify->setValueReady(m_cursorKey.release(), m_cursorPrimaryKey.release(), m_cursorValue.release(), m_blobInfo.release());
} }
} }
......
...@@ -58,11 +58,11 @@ class IDBRequest ...@@ -58,11 +58,11 @@ class IDBRequest
, public ActiveDOMObject { , public ActiveDOMObject {
DEFINE_EVENT_TARGET_REFCOUNTING_WILL_BE_REMOVED(RefCountedGarbageCollected<IDBRequest>); DEFINE_EVENT_TARGET_REFCOUNTING_WILL_BE_REMOVED(RefCountedGarbageCollected<IDBRequest>);
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
USING_PRE_FINALIZER(IDBRequest, dispose);
WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(IDBRequest); WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(IDBRequest);
public: public:
static IDBRequest* create(ScriptState*, IDBAny* source, IDBTransaction*); static IDBRequest* create(ScriptState*, IDBAny* source, IDBTransaction*);
virtual ~IDBRequest(); virtual ~IDBRequest();
void dispose();
virtual void trace(Visitor*) OVERRIDE; virtual void trace(Visitor*) OVERRIDE;
ScriptState* scriptState() { return m_scriptState.get(); } ScriptState* scriptState() { return m_scriptState.get(); }
...@@ -142,6 +142,7 @@ protected: ...@@ -142,6 +142,7 @@ protected:
bool m_requestAborted; // May be aborted by transaction then receive async onsuccess; ignore vs. assert. bool m_requestAborted; // May be aborted by transaction then receive async onsuccess; ignore vs. assert.
private: private:
void dispose();
void setResultCursor(IDBCursor*, IDBKey*, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> >); void setResultCursor(IDBCursor*, IDBKey*, IDBKey* primaryKey, PassRefPtr<SharedBuffer> value, PassOwnPtr<Vector<WebBlobInfo> >);
void setBlobInfo(PassOwnPtr<Vector<WebBlobInfo>>); void setBlobInfo(PassOwnPtr<Vector<WebBlobInfo>>);
void handleBlobAcks(); void handleBlobAcks();
......
...@@ -1006,6 +1006,7 @@ private: ...@@ -1006,6 +1006,7 @@ private:
}; };
class Observable : public GarbageCollectedFinalized<Observable> { class Observable : public GarbageCollectedFinalized<Observable> {
USING_PRE_FINALIZER(Observable, willFinalize);
public: public:
static Observable* create(Bar* bar) { return new Observable(bar); } static Observable* create(Bar* bar) { return new Observable(bar); }
~Observable() { m_wasDestructed = true; } ~Observable() { m_wasDestructed = true; }
...@@ -1017,7 +1018,9 @@ public: ...@@ -1017,7 +1018,9 @@ public:
{ {
EXPECT_FALSE(m_wasDestructed); EXPECT_FALSE(m_wasDestructed);
EXPECT_FALSE(m_bar->hasBeenFinalized()); EXPECT_FALSE(m_bar->hasBeenFinalized());
s_willFinalizeWasCalled = true;
} }
static bool s_willFinalizeWasCalled;
private: private:
explicit Observable(Bar* bar) explicit Observable(Bar* bar)
...@@ -1030,6 +1033,34 @@ private: ...@@ -1030,6 +1033,34 @@ private:
bool m_wasDestructed; bool m_wasDestructed;
}; };
bool Observable::s_willFinalizeWasCalled = false;
class ObservableWithPreFinalizer : public GarbageCollected<ObservableWithPreFinalizer> {
USING_PRE_FINALIZER(ObservableWithPreFinalizer, dispose);
public:
static ObservableWithPreFinalizer* create() { return new ObservableWithPreFinalizer(); }
~ObservableWithPreFinalizer() { m_wasDestructed = true; }
void trace(Visitor*) { }
void dispose()
{
ThreadState::current()->unregisterPreFinalizer(*this);
EXPECT_FALSE(m_wasDestructed);
s_disposeWasCalled = true;
}
static bool s_disposeWasCalled;
private:
explicit ObservableWithPreFinalizer()
: m_wasDestructed(false)
{
ThreadState::current()->registerPreFinalizer(*this);
}
bool m_wasDestructed;
};
bool ObservableWithPreFinalizer::s_disposeWasCalled = false;
template <typename T> class FinalizationObserver : public GarbageCollected<FinalizationObserver<T> > { template <typename T> class FinalizationObserver : public GarbageCollected<FinalizationObserver<T> > {
public: public:
static FinalizationObserver* create(T* data) { return new FinalizationObserver(data); } static FinalizationObserver* create(T* data) { return new FinalizationObserver(data); }
...@@ -3282,6 +3313,38 @@ TEST(HeapTest, FinalizationObserver) ...@@ -3282,6 +3313,38 @@ TEST(HeapTest, FinalizationObserver)
EXPECT_TRUE(FinalizationObserverWithHashMap::s_didCallWillFinalize); EXPECT_TRUE(FinalizationObserverWithHashMap::s_didCallWillFinalize);
} }
TEST(HeapTest, PreFinalizer)
{
Observable::s_willFinalizeWasCalled = false;
{
Observable* foo = Observable::create(Bar::create());
ThreadState::current()->registerPreFinalizer(*foo);
}
Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
EXPECT_TRUE(Observable::s_willFinalizeWasCalled);
}
TEST(HeapTest, PreFinalizerIsNotCalledIfUnregistered)
{
Observable::s_willFinalizeWasCalled = false;
{
Observable* foo = Observable::create(Bar::create());
ThreadState::current()->registerPreFinalizer(*foo);
ThreadState::current()->unregisterPreFinalizer(*foo);
}
Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
EXPECT_FALSE(Observable::s_willFinalizeWasCalled);
}
TEST(HeapTest, PreFinalizerUnregistersItself)
{
ObservableWithPreFinalizer::s_disposeWasCalled = false;
ObservableWithPreFinalizer::create();
Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
EXPECT_TRUE(ObservableWithPreFinalizer::s_disposeWasCalled);
// Don't crash, and assertions don't fail.
}
TEST(HeapTest, Comparisons) TEST(HeapTest, Comparisons)
{ {
Persistent<Bar> barPersistent = Bar::create(); Persistent<Bar> barPersistent = Bar::create();
......
...@@ -455,6 +455,8 @@ void ThreadState::cleanup() ...@@ -455,6 +455,8 @@ void ThreadState::cleanup()
// We should not have any persistents left when getting to this point, // We should not have any persistents left when getting to this point,
// if we have it is probably a bug so adding a debug ASSERT to catch this. // if we have it is probably a bug so adding a debug ASSERT to catch this.
ASSERT(!currentCount); ASSERT(!currentCount);
// All of pre-finalizers should be consumed.
ASSERT(m_preFinalizers.isEmpty());
// Add pages to the orphaned page pool to ensure any global GCs from this point // Add pages to the orphaned page pool to ensure any global GCs from this point
// on will not trace objects on this thread's heaps. // on will not trace objects on this thread's heaps.
...@@ -1114,6 +1116,10 @@ void ThreadState::performPendingSweep() ...@@ -1114,6 +1116,10 @@ void ThreadState::performPendingSweep()
// Perform thread-specific weak processing. // Perform thread-specific weak processing.
while (popAndInvokeWeakPointerCallback(Heap::s_markingVisitor)) { } while (popAndInvokeWeakPointerCallback(Heap::s_markingVisitor)) { }
} }
{
TRACE_EVENT0("blink_gc", "ThreadState::invokePreFinalizers");
invokePreFinalizers(*Heap::s_markingVisitor);
}
leaveNoAllocationScope(); leaveNoAllocationScope();
// Perform sweeping and finalization. // Perform sweeping and finalization.
...@@ -1247,6 +1253,25 @@ ThreadState::AttachedThreadStateSet& ThreadState::attachedThreads() ...@@ -1247,6 +1253,25 @@ ThreadState::AttachedThreadStateSet& ThreadState::attachedThreads()
return threads; return threads;
} }
void ThreadState::unregisterPreFinalizerInternal(void* target)
{
if (isSweepInProgress())
return;
auto it = m_preFinalizers.find(target);
ASSERT(it != m_preFinalizers.end());
m_preFinalizers.remove(it);
}
void ThreadState::invokePreFinalizers(Visitor& visitor)
{
Vector<void*> deadObjects;
for (auto& entry : m_preFinalizers) {
if (entry.value(entry.key, visitor))
deadObjects.append(entry.key);
}
m_preFinalizers.removeAll(deadObjects);
}
#if ENABLE(GC_PROFILE_MARKING) #if ENABLE(GC_PROFILE_MARKING)
const GCInfo* ThreadState::findGCInfoFromAllThreads(Address address) const GCInfo* ThreadState::findGCInfoFromAllThreads(Address address)
{ {
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "platform/PlatformExport.h" #include "platform/PlatformExport.h"
#include "platform/heap/AddressSanitizer.h" #include "platform/heap/AddressSanitizer.h"
#include "public/platform/WebThread.h" #include "public/platform/WebThread.h"
#include "wtf/HashMap.h"
#include "wtf/HashSet.h" #include "wtf/HashSet.h"
#include "wtf/OwnPtr.h" #include "wtf/OwnPtr.h"
#include "wtf/PassOwnPtr.h" #include "wtf/PassOwnPtr.h"
...@@ -42,10 +43,6 @@ ...@@ -42,10 +43,6 @@
#include "wtf/ThreadingPrimitives.h" #include "wtf/ThreadingPrimitives.h"
#include "wtf/Vector.h" #include "wtf/Vector.h"
#if ENABLE(GC_PROFILE_HEAP)
#include "wtf/HashMap.h"
#endif
namespace blink { namespace blink {
class BaseHeap; class BaseHeap;
...@@ -131,6 +128,52 @@ struct ThreadingTrait { ...@@ -131,6 +128,52 @@ struct ThreadingTrait {
template<typename U> class ThreadingTrait<const U> : public ThreadingTrait<U> { }; template<typename U> class ThreadingTrait<const U> : public ThreadingTrait<U> { };
// Declare that a class has a pre-finalizer function. The function is called in
// the object's owner thread, and can access Member<>s to other
// garbarge-collected objects allocated in the thread. However we must not
// allocate new garbage-collected objects, nor update Member<> and Persistent<>
// pointers.
//
// This feature is similar to the HeapHashMap<WeakMember<Foo>, OwnPtr<Disposer>>
// idiom. The difference between this and the idiom is that pre-finalizer
// function is called whenever an object is destructed with this feature. The
// HeapHashMap<WeakMember...> idiom requires an assumption that the HeapHashMap
// outlives objects pointed by WeakMembers.
// FIXME: Replace all of the HeapHashMap<WeakMember<Foo>, OwnPtr<Disposer>>
// idiom usages with the pre-finalizer.
//
// See ThreadState::registerPreFinalizer.
//
// Usage:
//
// class Foo : GarbageCollected<Foo> {
// USING_PRE_FINALIZER(Foo, dispose);
// public:
// Foo()
// {
// ThreadState::current()->registerPreFinalizer(*this);
// }
// private:
// void dispose();
// Member<Bar> m_bar;
// };
//
// void Foo::dispose()
// {
// m_bar->...
// }
#define USING_PRE_FINALIZER(Class, method) \
public: \
static bool invokePreFinalizer(void* object, Visitor& visitor) \
{ \
Class* self = reinterpret_cast<Class*>(object); \
if (visitor.isAlive(self)) \
return false; \
self->method(); \
return true; \
} \
typedef char UsingPreFinazlizerMacroNeedsTrailingSemiColon
// List of typed heaps. The list is used to generate the implementation // List of typed heaps. The list is used to generate the implementation
// of typed heap related methods. // of typed heap related methods.
// //
...@@ -629,6 +672,29 @@ public: ...@@ -629,6 +672,29 @@ public:
void registerSweepingTask(); void registerSweepingTask();
void unregisterSweepingTask(); void unregisterSweepingTask();
// Request to call a pref-finalizer of the target object before the object
// is destructed. The class T must have USING_PRE_FINALIZER(). The
// argument should be |*this|. Registering a lot of objects affects GC
// performance. We should register an object only if the object really
// requires pre-finalizer, and we should unregister the object if
// pre-finalizer is unnecessary.
template<typename T>
void registerPreFinalizer(T& target)
{
ASSERT(!m_preFinalizers.contains(&target));
ASSERT(!isSweepInProgress());
m_preFinalizers.add(&target, &T::invokePreFinalizer);
}
// Cancel above requests. The argument should be |*this|. This function is
// ignored if it is called in pre-finalizer functions.
template<typename T>
void unregisterPreFinalizer(T& target)
{
ASSERT(&T::invokePreFinalizer);
unregisterPreFinalizerInternal(&target);
}
Mutex& sweepMutex() { return m_sweepMutex; } Mutex& sweepMutex() { return m_sweepMutex; }
private: private:
...@@ -667,6 +733,8 @@ private: ...@@ -667,6 +733,8 @@ private:
void setLowCollectionRate(bool value) { m_lowCollectionRate = value; } void setLowCollectionRate(bool value) { m_lowCollectionRate = value; }
void waitUntilSweepersDone(); void waitUntilSweepersDone();
void unregisterPreFinalizerInternal(void*);
void invokePreFinalizers(Visitor&);
static WTF::ThreadSpecific<ThreadState*>* s_threadSpecific; static WTF::ThreadSpecific<ThreadState*>* s_threadSpecific;
static SafePointBarrier* s_safePointBarrier; static SafePointBarrier* s_safePointBarrier;
...@@ -718,6 +786,7 @@ private: ...@@ -718,6 +786,7 @@ private:
ThreadCondition m_sweepThreadCondition; ThreadCondition m_sweepThreadCondition;
CallbackStack* m_weakCallbackStack; CallbackStack* m_weakCallbackStack;
HashMap<void*, bool (*)(void*, Visitor&)> m_preFinalizers;
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
void* m_asanFakeStack; void* m_asanFakeStack;
......
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