1
1
// Rust garbage collection.
2
2
3
+ #include < algorithm>
3
4
#include < utility>
5
+ #include < vector>
4
6
#include < stdint.h>
5
7
6
8
#include " rust_gc.h"
12
14
#include < dlfcn.h>
13
15
#endif
14
16
17
+ #define DPRINT (fmt,...) fprintf(stderr, fmt, ##__VA_ARGS__)
18
+
19
+ #define END_OF_STACK_RA (void (*)())0xdeadbeef
20
+
15
21
namespace gc {
16
22
17
- struct root {
23
+ struct frame {
24
+ uint8_t *bp; // The frame pointer.
25
+ void (*ra)(); // The return address.
26
+
27
+ frame (void *in_bp) : bp((uint8_t *)in_bp) {}
28
+
29
+ inline void read_ra () {
30
+ ra = *(void (**)())(bp + sizeof (void *));
31
+ }
32
+
33
+ inline void next () {
34
+ bp = *(uint8_t **)bp;
35
+ }
36
+ };
37
+
38
+ struct root_info {
18
39
intptr_t frame_offset;
19
40
uintptr_t dynamic; // 0 = static, 1 = dynamic
20
41
type_desc *tydesc;
21
42
};
22
43
44
+ struct root {
45
+ type_desc *tydesc;
46
+ uint8_t *data;
47
+
48
+ root (const root_info &info, const frame &frame)
49
+ : tydesc(info.tydesc),
50
+ data ((uint8_t *)frame.bp + info.frame_offset) {}
51
+ };
52
+
23
53
struct safe_point {
24
54
uintptr_t n_roots;
25
- root roots[0 ];
55
+ root_info roots[0 ];
56
+ };
57
+
58
+ struct safe_point_index_entry {
59
+ void (*ra)(); // The return address.
60
+ const safe_point *safe_point; // The safe point.
61
+
62
+ struct cmp {
63
+ bool operator ()(const safe_point_index_entry &entry, void (*ra)())
64
+ const {
65
+ return entry.ra < ra;
66
+ }
67
+ bool operator ()(void (*ra)(), const safe_point_index_entry &entry)
68
+ const {
69
+ return ra < entry.ra ;
70
+ }
71
+ };
26
72
};
27
73
28
74
class safe_point_map {
29
75
uintptr_t n_safe_points;
30
- const std::pair< void *, const safe_point *> *index;
76
+ const safe_point_index_entry *index;
31
77
const safe_point *safe_points;
32
78
33
79
public:
34
80
safe_point_map () {
35
81
const uintptr_t *data = get_safe_point_data ();
36
82
n_safe_points = *data++;
37
- index = (const std::pair< void *, const safe_point *> *)data;
83
+ index = (const safe_point_index_entry *)data;
38
84
data += n_safe_points * 2 ;
39
85
safe_points = (const safe_point *)data;
40
86
}
41
87
88
+ const safe_point *get_safe_point (void (*addr)());
89
+
42
90
static const uintptr_t *get_safe_point_data () {
43
91
static bool init = false ;
44
92
static const uintptr_t *data;
@@ -56,13 +104,76 @@ class safe_point_map {
56
104
}
57
105
};
58
106
107
+ class gc {
108
+ private:
109
+ void mark (std::vector<root> &roots);
110
+ void sweep ();
111
+
112
+ public:
113
+ void run (rust_task *task);
114
+ std::vector<frame> backtrace ();
115
+ };
116
+
117
+ const safe_point *
118
+ safe_point_map::get_safe_point (void (*addr)()) {
119
+ safe_point_index_entry::cmp cmp;
120
+ const safe_point_index_entry *entry =
121
+ std::lower_bound (index, index + n_safe_points, addr, cmp);
122
+ return (entry && entry->ra == addr) ? entry->safe_point : NULL ;
123
+ }
124
+
59
125
void
60
- gc (rust_task *task) {
61
- safe_point_map map;
126
+ gc::mark (std::vector<root> &roots) {
127
+ std::vector<root>::iterator ri = roots.begin (), rend = roots.end ();
128
+ while (ri < rend) {
129
+ DPRINT (" root: %p\n " , ri->data );
130
+ ++ri;
131
+ }
132
+ // TODO
133
+ }
62
134
135
+ void
136
+ gc::sweep () {
63
137
// TODO
64
138
}
65
139
140
+ std::vector<frame>
141
+ gc::backtrace () {
142
+ std::vector<frame> frames;
143
+ frame f (__builtin_frame_address (0 ));
144
+ while (f.ra != END_OF_STACK_RA) {
145
+ f.read_ra ();
146
+ frames.push_back (f);
147
+ f.next ();
148
+ }
149
+ return frames;
150
+ }
151
+
152
+ void
153
+ gc::run (rust_task *task) {
154
+ safe_point_map map;
155
+
156
+ // Find roots.
157
+ std::vector<root> roots;
158
+ std::vector<frame> call_stack = backtrace ();
159
+ for (unsigned i = 0 ; i < call_stack.size (); i++) {
160
+ frame f = call_stack[i];
161
+ const safe_point *sp = map.get_safe_point (f.ra );
162
+ if (!sp)
163
+ continue ;
164
+
165
+ DPRINT (" %u: ra %p, ebp %p\n " , i, call_stack[i].ra , call_stack[i].bp );
166
+ for (unsigned j = 0 ; j < sp->n_roots ; j++) {
167
+ root r (sp->roots [j], f);
168
+ roots.push_back (r);
169
+ }
170
+ }
171
+
172
+ // Mark and sweep.
173
+ mark (roots);
174
+ sweep ();
175
+ }
176
+
66
177
void
67
178
maybe_gc (rust_task *task) {
68
179
if (safe_point_map::get_safe_point_data () == NULL )
@@ -75,8 +186,10 @@ maybe_gc(rust_task *task) {
75
186
zeal = ev && ev[0 ] != ' \0 ' && ev[0 ] != ' 0' ;
76
187
}
77
188
78
- if (zeal)
79
- gc::gc (task);
189
+ if (zeal) {
190
+ gc gc;
191
+ gc.run (task);
192
+ }
80
193
}
81
194
82
195
}
0 commit comments