While I was looking at the interaction of delayed folding with GGC, I
noticed that ggc_handle_finalizers currently runs no finalizers if
G.context_depth != 0. So any GC objects in a greater depth will still
be collected, but they won't have their finalizers run. This
specifically affects compiles that use a PCH file, since G.context_depth
is set to 1 after loading the PCH.
This patch fixes ggc_handle_finalizers to look at the depth of each
finalizer so that we still don't try to run finalizers for
non-collectable objects loaded from the PCH, but we do run finalizers
for collectable objects allocated after loading the PCH.
I ended up not relying on this for delayed folding, but it still seems
like a good bug fix.
Tested x86_64-pc-linux-gnu. OK for trunk?
commit 0bd746ae39b37b9b08e4d861d97fe30ecf4e8ad8
Author: Jason Merrill <ja...@redhat.com>
Date: Fri Nov 13 09:39:15 2015 -0500
Support GGC finalizers with PCH.
* ggc-page.c (class finalizer): Add m_depth field.
(finalizer::finalizer): Initialize it.
(finalizer::depth): Return it.
(class vec_finalizer): Likewise.
(ggc_internal_alloc): Adjust constructor calls.
(ggc_handle_finalizers): Run finalizers that are deep enough.
diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c
index deb21bb..1d5aeef 100644
--- a/gcc/ggc-page.c
+++ b/gcc/ggc-page.c
@@ -331,22 +331,26 @@ typedef struct page_table_chain
class finalizer
{
public:
- finalizer (void *addr, void (*f)(void *)) : m_addr (addr), m_function (f) {}
+ finalizer (void *addr, void (*f)(void *), unsigned short depth)
+ : m_addr (addr), m_function (f), m_depth(depth) {}
void *addr () const { return m_addr; }
-
+ unsigned short depth () const { return m_depth; }
void call () const { m_function (m_addr); }
private:
void *m_addr;
void (*m_function)(void *);
+ unsigned short m_depth;
};
class vec_finalizer
{
public:
- vec_finalizer (uintptr_t addr, void (*f)(void *), size_t s, size_t n) :
- m_addr (addr), m_function (f), m_object_size (s), m_n_objects (n) {}
+ vec_finalizer (uintptr_t addr, void (*f)(void *), size_t s, size_t n,
+ unsigned short depth)
+ : m_addr (addr), m_function (f), m_object_size (s), m_n_objects (n),
+ m_depth (depth) {}
void call () const
{
@@ -355,13 +359,15 @@ public:
}
void *addr () const { return reinterpret_cast<void *> (m_addr); }
+ unsigned short depth () const { return m_depth; }
private:
uintptr_t m_addr;
void (*m_function)(void *);
size_t m_object_size;
size_t m_n_objects;
- };
+ unsigned short m_depth;
+};
#ifdef ENABLE_GC_ALWAYS_COLLECT
/* List of free objects to be verified as actually free on the
@@ -1388,10 +1394,11 @@ ggc_internal_alloc (size_t size, void (*f)(void *), size_t s, size_t n
timevar_ggc_mem_total += object_size;
if (f && n == 1)
- G.finalizers.safe_push (finalizer (result, f));
+ G.finalizers.safe_push (finalizer (result, f, G.context_depth));
else if (f)
G.vec_finalizers.safe_push
- (vec_finalizer (reinterpret_cast<uintptr_t> (result), f, s, n));
+ (vec_finalizer (reinterpret_cast<uintptr_t> (result), f, s, n,
+ G.context_depth));
if (GATHER_STATISTICS)
{
@@ -1875,14 +1882,12 @@ clear_marks (void)
static void
ggc_handle_finalizers ()
{
- if (G.context_depth != 0)
- return;
-
unsigned length = G.finalizers.length ();
for (unsigned int i = 0; i < length;)
{
finalizer &f = G.finalizers[i];
- if (!ggc_marked_p (f.addr ()))
+ if (f.depth() >= G.context_depth
+ && !ggc_marked_p (f.addr ()))
{
f.call ();
G.finalizers.unordered_remove (i);
@@ -1897,7 +1902,8 @@ ggc_handle_finalizers ()
for (unsigned int i = 0; i < length;)
{
vec_finalizer &f = G.vec_finalizers[i];
- if (!ggc_marked_p (f.addr ()))
+ if (f.depth() >= G.context_depth
+ && !ggc_marked_p (f.addr ()))
{
f.call ();
G.vec_finalizers.unordered_remove (i);