diff options
author | tbsaunde <tbsaunde@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-05-17 23:08:00 +0000 |
---|---|---|
committer | tbsaunde <tbsaunde@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-05-17 23:08:00 +0000 |
commit | 92f06184bb548e33327e5c9895b5d00f9e6d0304 (patch) | |
tree | 10dcc038bf8bcfb0dd6268ffbf36527b525bfb4e /gcc/ggc-page.c | |
parent | 16f97f36c2d368ed6618b8ac65958c0232187b55 (diff) | |
download | gcc-92f06184bb548e33327e5c9895b5d00f9e6d0304.tar.gz |
add finalizers to ggc
This implements finalizers by keeping a list of registered finalizers
and after every mark but before sweeping check to see if any of them are
for unmarked blocks.
gcc/ChangeLog:
* ggc-common.c (ggc_internal_cleared_alloc): Adjust.
* ggc-none.c (ggc_internal_alloc): Assert if a finalizer is passed.
(ggc_internal_cleared_alloc): Likewise.
* ggc-page.c (finalizer): New class.
(vec_finalizer): Likewise.
(globals::finalizers): New member.
(globals::vec_finalizers): Likewise.
(ggc_internal_alloc): Record the finalizer if any for the block being
allocated.
(ggc_handle_finalizers): New function.
(ggc_collect): Call ggc_handle_finalizers.
* ggc.h (ggc_internal_alloc): Add arguments to allow installing a
finalizer.
(ggc_internal_cleared_alloc): Likewise.
(finalize): New function.
(need_finalization_p): Likewise.
(ggc_alloc): Install the type's destructor as the finalizer if it
might do something.
(ggc_cleared_alloc): Likewise.
(ggc_vec_alloc): Likewise.
(ggc_cleared_vec_alloc): Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@210568 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ggc-page.c')
-rw-r--r-- | gcc/ggc-page.c | 87 |
1 files changed, 86 insertions, 1 deletions
diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index ae5e88ac00e..b3a1a2a103f 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -332,6 +332,41 @@ typedef struct page_table_chain #endif +class finalizer +{ +public: + finalizer (void *addr, void (*f)(void *)) : m_addr (addr), m_function (f) {} + + void *addr () const { return m_addr; } + + void call () const { m_function (m_addr); } + +private: + void *m_addr; + void (*m_function)(void *); +}; + +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) {} + + void call () const + { + for (size_t i = 0; i < m_n_objects; i++) + m_function (reinterpret_cast<void *> (m_addr + (i * m_object_size))); + } + + void *addr () const { return reinterpret_cast<void *> (m_addr); } + +private: + uintptr_t m_addr; + void (*m_function)(void *); + size_t m_object_size; + size_t m_n_objects; + }; + #ifdef ENABLE_GC_ALWAYS_COLLECT /* List of free objects to be verified as actually free on the next collection. */ @@ -425,6 +460,12 @@ static struct globals better runtime data access pattern. */ unsigned long **save_in_use; + /* Finalizers for single objects. */ + vec<finalizer> finalizers; + + /* Finalizers for vectors of objects. */ + vec<vec_finalizer> vec_finalizers; + #ifdef ENABLE_GC_ALWAYS_COLLECT /* List of free objects to be verified as actually free on the next collection. */ @@ -1202,7 +1243,8 @@ ggc_round_alloc_size (size_t requested_size) /* Allocate a chunk of memory of SIZE bytes. Its contents are undefined. */ void * -ggc_internal_alloc (size_t size MEM_STAT_DECL) +ggc_internal_alloc (size_t size, void (*f)(void *), size_t s, size_t n + MEM_STAT_DECL) { size_t order, word, bit, object_offset, object_size; struct page_entry *entry; @@ -1345,6 +1387,12 @@ ggc_internal_alloc (size_t size MEM_STAT_DECL) /* For timevar statistics. */ timevar_ggc_mem_total += object_size; + if (f && n == 1) + G.finalizers.safe_push (finalizer (result, f)); + else if (f) + G.vec_finalizers.safe_push + (vec_finalizer (reinterpret_cast<uintptr_t> (result), f, s, n)); + if (GATHER_STATISTICS) { size_t overhead = object_size - size; @@ -1811,6 +1859,42 @@ 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 ())) + { + f.call (); + G.finalizers.unordered_remove (i); + length--; + } + else + i++; + } + + + length = G.vec_finalizers.length (); + for (unsigned int i = 0; i < length;) + { + vec_finalizer &f = G.vec_finalizers[i]; + if (!ggc_marked_p (f.addr ())) + { + f.call (); + G.vec_finalizers.unordered_remove (i); + length--; + } + else + i++; + } +} + /* Free all empty pages. Partially empty pages need no attention because the `mark' bit doubles as an `unused' bit. */ @@ -2075,6 +2159,7 @@ ggc_collect (void) clear_marks (); ggc_mark_roots (); + ggc_handle_finalizers (); if (GATHER_STATISTICS) ggc_prune_overhead_list (); |