-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgc.h
112 lines (79 loc) · 3.66 KB
/
gc.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#ifndef AEM_GC_H
#define AEM_GC_H
#include <stddef.h>
#include <aem/memory.h>
#include <aem/iter_gen.h>
/// GC object
struct aem_gc_object;
struct aem_gc_context;
struct aem_stringbuf;
struct aem_gc_vtbl {
const char *name;
void (*free)(struct aem_gc_object *obj, struct aem_gc_context *ctx);
void (*dtor)(struct aem_gc_object *obj, struct aem_gc_context *ctx);
void (*mark)(struct aem_gc_object *obj, struct aem_gc_context *ctx);
void (*describe_gv)(const struct aem_gc_object *obj, struct aem_stringbuf *out);
};
void aem_gc_free_default(struct aem_gc_object *obj, struct aem_gc_context *ctx);
struct aem_gc_object {
const struct aem_gc_vtbl *vtbl;
// Singly linked list of instances belonging to the same aem_gc_context
// rooted in ctx->objects
struct aem_gc_object *ctx_next;
struct aem_iter_gen iter;
size_t refs;
};
/// GC root
struct aem_gc_root {
struct aem_gc_root *root_prev; // AEM_LL2
struct aem_gc_root *root_next;
void (*mark)(struct aem_gc_root *root, struct aem_gc_context *ctx);
};
#define AEM_GC_ROOT_MARK_DECL(_tp, _obj) void _tp##_root_mark(struct aem_gc_root *root, struct aem_gc_context *ctx)
#define AEM_GC_GET_ROOT(_tp, _root) struct _tp *_root = aem_container_of(root, struct _tp, root);
// You must set root->mark yourself before calling this.
void aem_gc_root_register(struct aem_gc_root *root, struct aem_gc_context *ctx);
void aem_gc_root_deregister(struct aem_gc_context *ctx, struct aem_gc_root *root);
// Convenience macro that automagically sets _root->root.mark - use with AEM_GC_ROOT_MARK_DECL
#define AEM_GC_ROOT_REGISTER(_tp, _root, _ctx) do { struct aem_gc_root *aem_gc_root = &(_root)->root; struct aem_gc_context *aem_gc_ctx = (_ctx); aem_gc_root->mark = _tp##_root_mark; aem_gc_root_register(aem_gc_root, aem_gc_ctx); } while (0)
/// GC context
struct aem_gc_context {
struct aem_gc_object objects;
// objects.iter is master iterator
struct aem_gc_root roots;
};
void aem_gc_init(struct aem_gc_context *ctx);
void aem_gc_dtor(struct aem_gc_context *ctx);
void aem_gc_register(struct aem_gc_object *obj, const struct aem_gc_vtbl *vtbl, struct aem_gc_context *ctx);
#define AEM_GC_REGISTER(_tp, _obj, _ctx) aem_gc_register(&(_obj)->gc, &_tp##_vtbl, (_ctx))
void aem_gc_run(struct aem_gc_context *ctx);
void aem_gc_mark(struct aem_gc_object *obj, struct aem_gc_context *ctx);
#define AEM_GC_MARK_OBJ(_obj) do { \
__typeof__(_obj) _obj_ = (_obj); \
if (_obj_) { \
const struct aem_gc_object *_gc = &_obj_->gc; \
aem_gc_mark((struct aem_gc_object *)_gc, ctx); \
} \
} while (0)
#define AEM_GC_FREE_DECL(_tp, _obj) void _tp##_gc_free(struct aem_gc_object *obj, struct aem_gc_context *ctx)
#define AEM_GC_DTOR_DECL(_tp, _obj) void _tp##_gc_dtor(struct aem_gc_object *obj, struct aem_gc_context *ctx)
#define AEM_GC_MARK_DECL(_tp, _obj) void _tp##_gc_mark(struct aem_gc_object *obj, struct aem_gc_context *ctx)
#define AEM_GC_GET_OBJ(_tp, _obj) struct _tp *_obj = aem_container_of(obj, struct _tp, gc);
#define AEM_GC_VTBL_DECL(_tp) struct aem_gc_vtbl _tp##_vtbl
#define AEM_GC_VTBL_INST(_tp) \
AEM_GC_VTBL_DECL(_tp) = { \
.name = #_tp, \
.free = _tp##_gc_free, \
.dtor = _tp##_gc_dtor, \
.mark = _tp##_gc_mark, \
.describe_gv = _tp##_describe_gv, \
};
void aem_gc_ref(struct aem_gc_object *obj);
void aem_gc_unref(struct aem_gc_object *obj);
/// Graphviz Output
// Objects created in the context after the last call of aem_gc_run will not
// appear in this report; call aem_gc_run immediately before calling this to
// ensure all objects are described.
void gc_dump_objects_gv(struct aem_gc_context *ctx, struct aem_stringbuf *out);
void gc_write_objects_gv(struct aem_gc_context *ctx, const char *path);
#endif /* AEM_GC_H */