-
Notifications
You must be signed in to change notification settings - Fork 21
/
gc-hooks.patch
145 lines (138 loc) · 3.55 KB
/
gc-hooks.patch
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
diff --git a/gc.c b/gc.c
index 6381eb1..487ee60 100644
--- a/source/gc.c
+++ b/source/gc.c
@@ -192,6 +192,76 @@ static void run_final();
static VALUE nomem_error;
static void garbage_collect();
+/* likely */
+#if __GNUC__ >= 3
+#define LIKELY(x) (__builtin_expect((x), 1))
+#define UNLIKELY(x) (__builtin_expect((x), 0))
+#else /* __GNUC__ >= 3 */
+#define LIKELY(x) (x)
+#define UNLIKELY(x) (x)
+#endif /* __GNUC__ >= 3 */
+
+typedef struct gc_event_hook {
+ rb_gc_event_hook_func_t func;
+ rb_gc_event_t events;
+ struct gc_event_hook *next;
+} rb_gc_event_hook_t;
+
+static rb_gc_event_hook_t *gc_event_hooks;
+
+#define EXEC_GC_EVENT_HOOK(event, obj) \
+ do { \
+ rb_gc_event_hook_t *hook = gc_event_hooks; \
+ rb_gc_event_hook_func_t hook_func; \
+ rb_gc_event_t events; \
+ \
+ while (hook) { \
+ hook_func = hook->func; \
+ events = hook->events; \
+ hook = hook->next; \
+ if (events & event) \
+ (*hook_func)(event, obj); \
+ } \
+ } while (0)
+
+void
+rb_gc_add_event_hook(func, events)
+ rb_gc_event_hook_func_t func;
+ rb_gc_event_t events;
+{
+ rb_gc_event_hook_t *hook;
+
+ hook = ALLOC(rb_gc_event_hook_t);
+ hook->func = func;
+ hook->events = events;
+ hook->next = gc_event_hooks;
+ gc_event_hooks = hook;
+}
+
+int
+rb_gc_remove_event_hook(func)
+ rb_gc_event_hook_func_t func;
+{
+ rb_gc_event_hook_t *prev, *hook;
+
+ prev = NULL;
+ hook = gc_event_hooks;
+ while (hook) {
+ if (hook->func == func) {
+ if (prev) {
+ prev->next = hook->next;
+ }
+ else {
+ gc_event_hooks = hook->next;
+ }
+ xfree(hook);
+ return 0;
+ }
+ prev = hook;
+ hook = hook->next;
+ }
+ return -1;
+}
NORETURN(void rb_exc_jump _((VALUE)));
@@ -1008,6 +1078,9 @@ rb_newobj()
#endif
live_objects++;
allocated_objects++;
+ if (UNLIKELY(gc_event_hooks != NULL)) {
+ EXEC_GC_EVENT_HOOK(RUBY_GC_EVENT_NEWOBJ, obj);
+ }
return obj;
}
@@ -1893,6 +1966,9 @@ static int
obj_free(obj)
VALUE obj;
{
+ if (UNLIKELY(gc_event_hooks != NULL)) {
+ EXEC_GC_EVENT_HOOK(RUBY_GC_EVENT_OBJFREE, obj);
+ }
switch (BUILTIN_TYPE(obj)) {
case T_NIL:
case T_FIXNUM:
@@ -2191,6 +2267,9 @@ garbage_collect()
/* This assumes that all registers are saved into the jmp_buf (and stack) */
rb_setjmp(save_regs_gc_mark);
+ if (UNLIKELY(gc_event_hooks != NULL)) {
+ EXEC_GC_EVENT_HOOK(RUBY_GC_EVENT_START, Qnil);
+ }
#if STACK_WIPE_SITES & 0x400
# ifdef nativeAllocA
if (__stack_past (top, stack_limit)) {
@@ -2211,6 +2290,9 @@ garbage_collect()
#else
garbage_collect_0(top);
#endif
+ if (UNLIKELY(gc_event_hooks != NULL)) {
+ EXEC_GC_EVENT_HOOK(RUBY_GC_EVENT_END, Qnil);
+ }
}
void
diff --git a/node.h b/node.h
index 3e60603..af7a3fd 100644
--- a/source/node.h
+++ b/source/node.h
@@ -375,6 +375,19 @@ NODE *rb_copy_node_scope _((NODE *, NODE *));
void rb_add_event_hook _((rb_event_hook_func_t,rb_event_t));
int rb_remove_event_hook _((rb_event_hook_func_t));
+typedef unsigned int rb_gc_event_t;
+
+#define RUBY_GC_EVENT_NONE 0x00
+#define RUBY_GC_EVENT_START 0x01
+#define RUBY_GC_EVENT_END 0x02
+#define RUBY_GC_EVENT_NEWOBJ 0x04
+#define RUBY_GC_EVENT_OBJFREE 0x08
+#define RUBY_GC_EVENT_ALL 0xff
+
+typedef void (*rb_gc_event_hook_func_t) _((rb_gc_event_t,VALUE));
+void rb_gc_add_event_hook _((rb_gc_event_hook_func_t,rb_gc_event_t));
+int rb_gc_remove_event_hook _((rb_gc_event_hook_func_t));
+
#if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT)
#include <ucontext.h>
#define USE_CONTEXT