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() {
}
void HTMLCanvasElement::dispose() {
releasePlaceholderFrame();
if (placeholderFrame())
releasePlaceholderFrame();
if (m_context) {
m_context->detachCanvas();
......
......@@ -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 be registered in the constructor by using the following statement:
"`ThreadState::current()->registerPreFinalizer(this);`".
```c++
class YourClass : public GarbageCollectedFinalized<YourClass> {
USING_PRE_FINALIZER(YourClass, dispose);
public:
YourClass()
{
ThreadState::current()->registerPreFinalizer(this);
}
void dispose()
{
m_other->dispose(); // OK; you can touch other on-heap objects in a pre-finalizer.
......
......@@ -1160,7 +1160,6 @@ class ObservableWithPreFinalizer
~ObservableWithPreFinalizer() { m_wasDestructed = true; }
DEFINE_INLINE_TRACE() {}
void dispose() {
ThreadState::current()->unregisterPreFinalizer(this);
EXPECT_FALSE(m_wasDestructed);
s_disposeWasCalled = true;
}
......@@ -1168,7 +1167,6 @@ class ObservableWithPreFinalizer
protected:
ObservableWithPreFinalizer() : m_wasDestructed(false) {
ThreadState::current()->registerPreFinalizer(this);
}
bool m_wasDestructed;
......@@ -1197,7 +1195,6 @@ class PreFinalizerBase : public GarbageCollectedFinalized<PreFinalizerBase> {
protected:
PreFinalizerBase() : m_wasDestructed(false) {
ThreadState::current()->registerPreFinalizer(this);
}
bool m_wasDestructed;
};
......@@ -1218,7 +1215,6 @@ class PreFinalizerMixin : public GarbageCollectedMixin {
protected:
PreFinalizerMixin() : m_wasDestructed(false) {
ThreadState::current()->registerPreFinalizer(this);
}
bool m_wasDestructed;
};
......@@ -1241,7 +1237,6 @@ class PreFinalizerSubClass : public PreFinalizerBase, public PreFinalizerMixin {
protected:
PreFinalizerSubClass() : m_wasDestructed(false) {
ThreadState::current()->registerPreFinalizer(this);
}
bool m_wasDestructed;
};
......@@ -1561,7 +1556,6 @@ class PreFinalizationAllocator
public:
PreFinalizationAllocator(Persistent<IntWrapper>* wrapper)
: m_wrapper(wrapper) {
ThreadState::current()->registerPreFinalizer(this);
}
void dispose() {
......@@ -3881,25 +3875,11 @@ TEST(HeapTest, FinalizationObserver) {
TEST(HeapTest, PreFinalizer) {
Observable::s_willFinalizeWasCalled = false;
{
Observable* foo = Observable::create(Bar::create());
ThreadState::current()->registerPreFinalizer(foo);
}
{ Observable::create(Bar::create()); }
preciselyCollectGarbage();
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) {
ObservableWithPreFinalizer::s_disposeWasCalled = false;
ObservableWithPreFinalizer::create();
......
......@@ -91,11 +91,6 @@ class Visitor;
//
// class Foo : GarbageCollected<Foo> {
// USING_PRE_FINALIZER(Foo, dispose);
// public:
// Foo()
// {
// ThreadState::current()->registerPreFinalizer(this);
// }
// private:
// void dispose()
// {
......@@ -103,15 +98,18 @@ class Visitor;
// }
// Member<Bar> m_bar;
// };
#define USING_PRE_FINALIZER(Class, preFinalizer) \
public: \
static bool invokePreFinalizer(void* object) { \
Class* self = reinterpret_cast<Class*>(object); \
if (ThreadHeap::isHeapObjectAlive(self)) \
return false; \
self->Class::preFinalizer(); \
return true; \
} \
#define USING_PRE_FINALIZER(Class, preFinalizer) \
public: \
static bool invokePreFinalizer(void* object) { \
Class* self = reinterpret_cast<Class*>(object); \
if (ThreadHeap::isHeapObjectAlive(self)) \
return false; \
self->Class::preFinalizer(); \
return true; \
} \
\
private: \
ThreadState::PrefinalizerRegistration<Class> m_prefinalizerDummy = this; \
using UsingPreFinalizerMacroNeedsTrailingSemiColon = char
class PLATFORM_EXPORT ThreadState {
......@@ -415,32 +413,9 @@ class PLATFORM_EXPORT ThreadState {
size_t objectPayloadSizeForTesting();
// 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().
// TODO: no longer needed, remove all uses.
template <typename T>
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() {
......@@ -565,7 +540,29 @@ class PLATFORM_EXPORT ThreadState {
void collectGarbageForTerminatingThread();
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:
template <typename T>
friend class PrefinalizerRegistration;
enum SnapshotType { HeapSnapshot, FreelistSnapshot };
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