Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(982)

Unified Diff: Source/platform/heap/ThreadState.h

Issue 1200333006: Oilpan: Support nested pre-finalizers (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/platform/heap/HeapTest.cpp ('k') | Source/platform/heap/ThreadState.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/platform/heap/ThreadState.h
diff --git a/Source/platform/heap/ThreadState.h b/Source/platform/heap/ThreadState.h
index 56f9e15ee73462e93a0af440a557b1c91f5cd442..4280ad1be9e53457a725d65cc657686e302b583c 100644
--- a/Source/platform/heap/ThreadState.h
+++ b/Source/platform/heap/ThreadState.h
@@ -71,16 +71,21 @@ using VisitorCallback = void (*)(Visitor*, void* self);
using TraceCallback = VisitorCallback;
using WeakCallback = VisitorCallback;
using EphemeronCallback = VisitorCallback;
-
-// Declare that a class has a pre-finalizer function. The function is called in
-// the object's owner thread. The pre-finalizer is called before any object gets
-// swept, so it is allowed to touch on-heap objects that may be collected in the
-// GC cycle. If you cannot avoid touching on-heap objects in a destructor (which
-// is not allowed), you can consider using the pre-finalizer or
-// EARGERY_FINALIZED. The only restriction is that the pre-finalizer must not
-// resurrect dead objects (e.g., store unmarked objects into Members etc).
+using PreFinalizerCallback = bool(*)(void*);
+
+// Declare that a class has a pre-finalizer. The pre-finalizer is called
+// before any object gets swept, so it is safe to touch on-heap objects
+// that may be collected in the same GC cycle. If you cannot avoid touching
+// on-heap objects in a destructor (which is not allowed), you can consider
+// using the pre-finalizer. The only restriction is that the pre-finalizer
+// must not resurrect dead objects (e.g., store unmarked objects into
+// Members etc). The pre-finalizer is called on the thread that registered
+// the pre-finalizer.
+//
+// Since a pre-finalizer adds pressure on GC performance, you should use it
+// only if necessary.
//
-// This feature is similar to the HeapHashMap<WeakMember<Foo>, OwnPtr<Disposer>>
+// A pre-finalizer 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<Foo>, OwnPtr<Disposer>> idiom requires an assumption
@@ -89,8 +94,6 @@ using EphemeronCallback = VisitorCallback;
// idiom usages with the pre-finalizer if the replacement won't cause
// performance regressions.
//
-// See ThreadState::registerPreFinalizer.
-//
// Usage:
//
// class Foo : GarbageCollected<Foo> {
@@ -98,28 +101,26 @@ using EphemeronCallback = VisitorCallback;
// public:
// Foo()
// {
-// ThreadState::current()->registerPreFinalizer(*this);
+// ThreadState::current()->registerPreFinalizer(this, dispose);
// }
// private:
-// void dispose();
+// void dispose()
+// {
+// m_bar->...; // It is safe to touch other on-heap objects.
+// }
// Member<Bar> m_bar;
// };
-//
-// void Foo::dispose()
-// {
-// m_bar->...
-// }
-#define USING_PRE_FINALIZER(Class, method) \
- public: \
- static bool invokePreFinalizer(void* object) \
- { \
- Class* self = reinterpret_cast<Class*>(object); \
- if (Heap::isHeapObjectAlive(self)) \
- return false; \
- self->method(); \
- return true; \
- } \
- using UsingPreFinazlizerMacroNeedsTrailingSemiColon = char
+#define USING_PRE_FINALIZER(Class, preFinalizer) \
+public: \
+static bool invokePreFinalizer(void* object) \
+{ \
+ Class* self = reinterpret_cast<Class*>(object); \
+ if (Heap::isHeapObjectAlive(self)) \
+ return false; \
+ self->Class::preFinalizer(); \
+ return true; \
+} \
+using UsingPreFinazlizerMacroNeedsTrailingSemiColon = char
#if ENABLE(OILPAN)
#define WILL_BE_USING_PRE_FINALIZER(Class, method) USING_PRE_FINALIZER(Class, method)
@@ -536,29 +537,42 @@ public:
size_t objectPayloadSizeForTesting();
void prepareHeapForTermination();
- // 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.
+ // Register the pre-finalizer for the |self| object. This method is normally
+ // called in the constructor of the |self| object. The class T must have
+ // USING_PRE_FINALIZER().
template<typename T>
- void registerPreFinalizer(T& target)
+ void registerPreFinalizer(T* self)
{
+ static_assert(sizeof(&T::invokePreFinalizer) > 0, "USING_PRE_FINALIZER(T) must be defined.");
checkThread();
- ASSERT(!m_preFinalizers.contains(&target));
ASSERT(!sweepForbidden());
- m_preFinalizers.add(&target, &T::invokePreFinalizer);
+ auto it = m_preFinalizers.find(self);
+ Vector<PreFinalizerCallback>* callbackVector;
+ if (it == m_preFinalizers.end()) {
+ callbackVector = m_preFinalizers.add(self, adoptPtr(new Vector<PreFinalizerCallback>)).storedValue->value.get();
+ } else {
+ callbackVector = it->value.get();
+ }
+ ASSERT(!callbackVector->contains(&T::invokePreFinalizer));
+ callbackVector->append(&T::invokePreFinalizer);
}
- // Cancel above requests. The argument should be |*this|. This function is
- // ignored if it is called in pre-finalizer functions.
+ // Unregister the pre-finalizer for the |self| object.
template<typename T>
- void unregisterPreFinalizer(T& target)
+ void unregisterPreFinalizer(T* self)
{
- static_assert(sizeof(&T::invokePreFinalizer) > 0, "Declaration of USING_PRE_FINALIZER()'s prefinalizer trampoline not in scope.");
+ static_assert(sizeof(&T::invokePreFinalizer) > 0, "USING_PRE_FINALIZER(T) must be defined.");
checkThread();
- unregisterPreFinalizerInternal(&target);
+ // Ignore pre-finalizers called during pre-finalizers or destructors.
+ if (sweepForbidden())
+ return;
+ auto it = m_preFinalizers.find(self);
+ ASSERT(it != m_preFinalizers.end());
+ Vector<PreFinalizerCallback>* callbackVector = it->value.get();
+ ASSERT(it->value->contains(&T::invokePreFinalizer));
+ callbackVector->remove(callbackVector->find(&T::invokePreFinalizer));
+ if (callbackVector->isEmpty())
+ m_preFinalizers.remove(it);
}
Vector<PageMemoryRegion*>& allocatedRegionsSinceLastGC() { return m_allocatedRegionsSinceLastGC; }
@@ -691,7 +705,6 @@ private:
void cleanup();
void cleanupPages();
- void unregisterPreFinalizerInternal(void*);
void invokePreFinalizers();
void takeSnapshot(SnapshotType);
@@ -744,7 +757,7 @@ private:
GCState m_gcState;
CallbackStack* m_threadLocalWeakCallbackStack;
- HashMap<void*, bool (*)(void*)> m_preFinalizers;
+ HashMap<void*, OwnPtr<Vector<PreFinalizerCallback>>> m_preFinalizers;
v8::Isolate* m_isolate;
void (*m_traceDOMWrappers)(v8::Isolate*, Visitor*);
« no previous file with comments | « Source/platform/heap/HeapTest.cpp ('k') | Source/platform/heap/ThreadState.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698