-
Notifications
You must be signed in to change notification settings - Fork 7
/
gc-finalizer.h
81 lines (72 loc) · 3.76 KB
/
gc-finalizer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#ifndef GC_FINALIZER_H_
#define GC_FINALIZER_H_
#include "gc-edge.h"
#include "gc-ref.h"
#include "gc-visibility.h"
// A finalizer allows the embedder to be notified when an object becomes
// unreachable.
//
// A finalizer has a priority. When the heap is created, the embedder
// should declare how many priorities there are. Lower-numbered
// priorities take precedence; if an object has a priority-0 finalizer
// outstanding, that will prevent any finalizer at level 1 (or 2, ...)
// from firing until no priority-0 finalizer remains.
//
// Call gc_attach_finalizer to attach a finalizer to an object.
//
// A finalizer also references an associated GC-managed closure object.
// A finalizer's reference to the closure object is strong: if a
// finalizer's closure closure references its finalizable object,
// directly or indirectly, the finalizer will never fire.
//
// When an object with a finalizer becomes unreachable, it is added to a
// queue. The embedder can call gc_pop_finalizable to get the next
// finalizable object and its associated closure. At that point the
// embedder can do anything with the object, including keeping it alive.
// Ephemeron associations will still be present while the finalizable
// object is live. Note however that any objects referenced by the
// finalizable object may themselves be already finalized; finalizers
// are enqueued for objects when they become unreachable, which can
// concern whole subgraphs of objects at once.
//
// The usual way for an embedder to know when the queue of finalizable
// object is non-empty is to call gc_set_finalizer_callback to
// provide a function that will be invoked when there are pending
// finalizers.
//
// Arranging to call gc_pop_finalizable and doing something with the
// finalizable object and closure is the responsibility of the embedder.
// The embedder's finalization action can end up invoking arbitrary
// code, so unless the embedder imposes some kind of restriction on what
// finalizers can do, generally speaking finalizers should be run in a
// dedicated thread instead of recursively from within whatever mutator
// thread caused GC. Setting up such a thread is the responsibility of
// the mutator. gc_pop_finalizable is thread-safe, allowing multiple
// finalization threads if that is appropriate.
//
// gc_allocate_finalizer returns a finalizer, which is a fresh
// GC-managed heap object. The mutator should then directly attach it
// to an object using gc_finalizer_attach. When the finalizer is fired,
// it becomes available to the mutator via gc_pop_finalizable.
struct gc_heap;
struct gc_mutator;
struct gc_finalizer;
GC_API_ size_t gc_finalizer_size(void);
GC_API_ struct gc_finalizer* gc_allocate_finalizer(struct gc_mutator *mut);
GC_API_ void gc_finalizer_attach(struct gc_mutator *mut,
struct gc_finalizer *finalizer,
unsigned priority,
struct gc_ref object, struct gc_ref closure);
GC_API_ struct gc_ref gc_finalizer_object(struct gc_finalizer *finalizer);
GC_API_ struct gc_ref gc_finalizer_closure(struct gc_finalizer *finalizer);
GC_API_ struct gc_finalizer* gc_pop_finalizable(struct gc_mutator *mut);
typedef void (*gc_finalizer_callback)(struct gc_heap *heap, size_t count);
GC_API_ void gc_set_finalizer_callback(struct gc_heap *heap,
gc_finalizer_callback callback);
GC_API_ void gc_trace_finalizer(struct gc_finalizer *finalizer,
void (*visit)(struct gc_edge edge,
struct gc_heap *heap,
void *visit_data),
struct gc_heap *heap,
void *trace_data);
#endif // GC_FINALIZER_H_