Commit bc86f5fb authored by sigbjornf's avatar sigbjornf Committed by Commit bot

Implicit prefinalizer registration.

Switch to implicit registration of prefinalizers along with removing
the ability to dynamically unregister a prefinalizer; the latter
being an unused feature.

The requirement to manually register a prefinalizer has proven to be
a chore and a source of bugs. Case in point: HTMLCanvasElement
currently declares a prefinalizer, but doesn't register it. Simplify
the programming model by automatically registering prefinalizers.

R=haraken
BUG=673645

Review-Url: https://codereview.chromium.org/2565983002
Cr-Commit-Position: refs/heads/master@{#438110}
parent e3d284d7
...@@ -146,7 +146,8 @@ HTMLCanvasElement::~HTMLCanvasElement() { ...@@ -146,7 +146,8 @@ HTMLCanvasElement::~HTMLCanvasElement() {
} }
void HTMLCanvasElement::dispose() { void HTMLCanvasElement::dispose() {
releasePlaceholderFrame(); if (placeholderFrame())
releasePlaceholderFrame();
if (m_context) { if (m_context) {
m_context->detachCanvas(); m_context->detachCanvas();
......
...@@ -178,17 +178,10 @@ with a destructor. ...@@ -178,17 +178,10 @@ with a destructor.
A pre-finalizer must have the following function signature: `void preFinalizer()`. You can change the function name. A pre-finalizer must have the following function signature: `void preFinalizer()`. You can change the function name.
A pre-finalizer must be registered in the constructor by using the following statement:
"`ThreadState::current()->registerPreFinalizer(this);`".
```c++ ```c++
class YourClass : public GarbageCollectedFinalized<YourClass> { class YourClass : public GarbageCollectedFinalized<YourClass> {
USING_PRE_FINALIZER(YourClass, dispose); USING_PRE_FINALIZER(YourClass, dispose);
public: public:
YourClass()
{
ThreadState::current()->registerPreFinalizer(this);
}
void dispose() void dispose()
{ {
m_other->dispose(); // OK; you can touch other on-heap objects in a pre-finalizer. m_other->dispose(); // OK; you can touch other on-heap objects in a pre-finalizer.
......
...@@ -1160,7 +1160,6 @@ class ObservableWithPreFinalizer ...@@ -1160,7 +1160,6 @@ class ObservableWithPreFinalizer
~ObservableWithPreFinalizer() { m_wasDestructed = true; } ~ObservableWithPreFinalizer() { m_wasDestructed = true; }
DEFINE_INLINE_TRACE() {} DEFINE_INLINE_TRACE() {}
void dispose() { void dispose() {
ThreadState::current()->unregisterPreFinalizer(this);
EXPECT_FALSE(m_wasDestructed); EXPECT_FALSE(m_wasDestructed);
s_disposeWasCalled = true; s_disposeWasCalled = true;
} }
...@@ -1168,7 +1167,6 @@ class ObservableWithPreFinalizer ...@@ -1168,7 +1167,6 @@ class ObservableWithPreFinalizer
protected: protected:
ObservableWithPreFinalizer() : m_wasDestructed(false) { ObservableWithPreFinalizer() : m_wasDestructed(false) {
ThreadState::current()->registerPreFinalizer(this);
} }
bool m_wasDestructed; bool m_wasDestructed;
...@@ -1197,7 +1195,6 @@ class PreFinalizerBase : public GarbageCollectedFinalized<PreFinalizerBase> { ...@@ -1197,7 +1195,6 @@ class PreFinalizerBase : public GarbageCollectedFinalized<PreFinalizerBase> {
protected: protected:
PreFinalizerBase() : m_wasDestructed(false) { PreFinalizerBase() : m_wasDestructed(false) {
ThreadState::current()->registerPreFinalizer(this);
} }
bool m_wasDestructed; bool m_wasDestructed;
}; };
...@@ -1218,7 +1215,6 @@ class PreFinalizerMixin : public GarbageCollectedMixin { ...@@ -1218,7 +1215,6 @@ class PreFinalizerMixin : public GarbageCollectedMixin {
protected: protected:
PreFinalizerMixin() : m_wasDestructed(false) { PreFinalizerMixin() : m_wasDestructed(false) {
ThreadState::current()->registerPreFinalizer(this);
} }
bool m_wasDestructed; bool m_wasDestructed;
}; };
...@@ -1241,7 +1237,6 @@ class PreFinalizerSubClass : public PreFinalizerBase, public PreFinalizerMixin { ...@@ -1241,7 +1237,6 @@ class PreFinalizerSubClass : public PreFinalizerBase, public PreFinalizerMixin {
protected: protected:
PreFinalizerSubClass() : m_wasDestructed(false) { PreFinalizerSubClass() : m_wasDestructed(false) {
ThreadState::current()->registerPreFinalizer(this);
} }
bool m_wasDestructed; bool m_wasDestructed;
}; };
...@@ -1561,7 +1556,6 @@ class PreFinalizationAllocator ...@@ -1561,7 +1556,6 @@ class PreFinalizationAllocator
public: public:
PreFinalizationAllocator(Persistent<IntWrapper>* wrapper) PreFinalizationAllocator(Persistent<IntWrapper>* wrapper)
: m_wrapper(wrapper) { : m_wrapper(wrapper) {
ThreadState::current()->registerPreFinalizer(this);
} }
void dispose() { void dispose() {
...@@ -3881,25 +3875,11 @@ TEST(HeapTest, FinalizationObserver) { ...@@ -3881,25 +3875,11 @@ TEST(HeapTest, FinalizationObserver) {
TEST(HeapTest, PreFinalizer) { TEST(HeapTest, PreFinalizer) {
Observable::s_willFinalizeWasCalled = false; Observable::s_willFinalizeWasCalled = false;
{ { Observable::create(Bar::create()); }
Observable* foo = Observable::create(Bar::create());
ThreadState::current()->registerPreFinalizer(foo);
}
preciselyCollectGarbage(); preciselyCollectGarbage();
EXPECT_TRUE(Observable::s_willFinalizeWasCalled); 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);
}
preciselyCollectGarbage();
EXPECT_FALSE(Observable::s_willFinalizeWasCalled);
}
TEST(HeapTest, PreFinalizerUnregistersItself) { TEST(HeapTest, PreFinalizerUnregistersItself) {
ObservableWithPreFinalizer::s_disposeWasCalled = false; ObservableWithPreFinalizer::s_disposeWasCalled = false;
ObservableWithPreFinalizer::create(); ObservableWithPreFinalizer::create();
......
...@@ -91,11 +91,6 @@ class Visitor; ...@@ -91,11 +91,6 @@ class Visitor;
// //
// class Foo : GarbageCollected<Foo> { // class Foo : GarbageCollected<Foo> {
// USING_PRE_FINALIZER(Foo, dispose); // USING_PRE_FINALIZER(Foo, dispose);
// public:
// Foo()
// {
// ThreadState::current()->registerPreFinalizer(this);
// }
// private: // private:
// void dispose() // void dispose()
// { // {
...@@ -103,15 +98,18 @@ class Visitor; ...@@ -103,15 +98,18 @@ class Visitor;
// } // }
// Member<Bar> m_bar; // Member<Bar> m_bar;
// }; // };
#define USING_PRE_FINALIZER(Class, preFinalizer) \ #define USING_PRE_FINALIZER(Class, preFinalizer) \
public: \ public: \
static bool invokePreFinalizer(void* object) { \ static bool invokePreFinalizer(void* object) { \
Class* self = reinterpret_cast<Class*>(object); \ Class* self = reinterpret_cast<Class*>(object); \
if (ThreadHeap::isHeapObjectAlive(self)) \ if (ThreadHeap::isHeapObjectAlive(self)) \
return false; \ return false; \
self->Class::preFinalizer(); \ self->Class::preFinalizer(); \
return true; \ return true; \
} \ } \
\
private: \
ThreadState::PrefinalizerRegistration<Class> m_prefinalizerDummy = this; \
using UsingPreFinalizerMacroNeedsTrailingSemiColon = char using UsingPreFinalizerMacroNeedsTrailingSemiColon = char
class PLATFORM_EXPORT ThreadState { class PLATFORM_EXPORT ThreadState {
...@@ -415,32 +413,9 @@ class PLATFORM_EXPORT ThreadState { ...@@ -415,32 +413,9 @@ class PLATFORM_EXPORT ThreadState {
size_t objectPayloadSizeForTesting(); size_t objectPayloadSizeForTesting();
// Register the pre-finalizer for the |self| object. This method is normally // TODO: no longer needed, remove all uses.
// called in the constructor of the |self| object. The class T must have
// USING_PRE_FINALIZER().
template <typename T> template <typename T>
void registerPreFinalizer(T* self) { void registerPreFinalizer(T* self) {
static_assert(sizeof(&T::invokePreFinalizer) > 0,
"USING_PRE_FINALIZER(T) must be defined.");
ASSERT(checkThread());
ASSERT(!sweepForbidden());
ASSERT(!m_orderedPreFinalizers.contains(
PreFinalizer(self, T::invokePreFinalizer)));
m_orderedPreFinalizers.add(PreFinalizer(self, T::invokePreFinalizer));
}
// Unregister the pre-finalizer for the |self| object.
template <typename T>
void unregisterPreFinalizer(T* self) {
static_assert(sizeof(&T::invokePreFinalizer) > 0,
"USING_PRE_FINALIZER(T) must be defined.");
ASSERT(checkThread());
// Ignore pre-finalizers called during pre-finalizers or destructors.
if (sweepForbidden())
return;
ASSERT(m_orderedPreFinalizers.contains(
PreFinalizer(self, T::invokePreFinalizer)));
m_orderedPreFinalizers.remove(PreFinalizer(self, &T::invokePreFinalizer));
} }
void shouldFlushHeapDoesNotContainCache() { void shouldFlushHeapDoesNotContainCache() {
...@@ -565,7 +540,29 @@ class PLATFORM_EXPORT ThreadState { ...@@ -565,7 +540,29 @@ class PLATFORM_EXPORT ThreadState {
void collectGarbageForTerminatingThread(); void collectGarbageForTerminatingThread();
void collectAllGarbage(); void collectAllGarbage();
// Register the pre-finalizer for the |self| object. The class T must have
// USING_PRE_FINALIZER().
template <typename T>
class PrefinalizerRegistration final {
public:
PrefinalizerRegistration(T* self) {
static_assert(sizeof(&T::invokePreFinalizer) > 0,
"USING_PRE_FINALIZER(T) must be defined.");
ThreadState* state = ThreadState::current();
#if ENABLE(ASSERT)
DCHECK(state->checkThread());
#endif
DCHECK(!state->sweepForbidden());
DCHECK(!state->m_orderedPreFinalizers.contains(
PreFinalizer(self, T::invokePreFinalizer)));
state->m_orderedPreFinalizers.add(
PreFinalizer(self, T::invokePreFinalizer));
}
};
private: private:
template <typename T>
friend class PrefinalizerRegistration;
enum SnapshotType { HeapSnapshot, FreelistSnapshot }; enum SnapshotType { HeapSnapshot, FreelistSnapshot };
explicit ThreadState(BlinkGC::ThreadHeapMode); explicit ThreadState(BlinkGC::ThreadHeapMode);
......
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