5
5
#include " rust_internal.h"
6
6
#include " rust_shape.h"
7
7
#include " rust_task.h"
8
+ #include < cassert>
8
9
#include < cstdio>
9
10
#include < cstdlib>
10
11
#include < map>
12
+ #include < set>
11
13
#include < vector>
12
14
#include < stdint.h>
13
15
@@ -23,7 +25,7 @@ typedef std::map<void *,uintptr_t> irc_map;
23
25
class irc : public shape ::data<irc,shape::ptr> {
24
26
friend class shape ::data<irc,shape::ptr>;
25
27
26
- irc_map ircs;
28
+ irc_map & ircs;
27
29
28
30
irc (const irc &other, const shape::ptr &in_dp)
29
31
: shape::data<irc,shape::ptr>(other.task, other.align, other.sp,
@@ -114,10 +116,13 @@ class irc : public shape::data<irc,shape::ptr> {
114
116
return ;
115
117
116
118
// Bump the internal reference count of the box.
117
- if (ircs.find ((void *)dp) == ircs.end ())
118
- ircs[(void *)dp] = 1 ;
119
- else
120
- ++ircs[(void *)dp];
119
+ if (ircs.find ((void *)ref_count_dp) == ircs.end ()) {
120
+ // DPRINT("setting internal reference count for %p\n",
121
+ // (void *)ref_count_dp);
122
+ ircs[(void *)ref_count_dp] = 1 ;
123
+ } else {
124
+ ++ircs[(void *)ref_count_dp];
125
+ }
121
126
122
127
// Do not traverse the contents of this box; it's in the allocation
123
128
// somewhere, so we're guaranteed to come back to it (if we haven't
@@ -167,7 +172,8 @@ irc::compute_ircs(rust_task *task, irc_map &ircs) {
167
172
168
173
type_desc *tydesc = begin->second ;
169
174
170
- DPRINT (" determining internal ref counts: %p, tydesc=%p\n " , p, tydesc);
175
+ // DPRINT("determining internal ref counts: %p, tydesc=%p\n", p,
176
+ // tydesc);
171
177
172
178
shape::arena arena;
173
179
shape::type_param *params =
@@ -187,10 +193,242 @@ irc::compute_ircs(rust_task *task, irc_map &ircs) {
187
193
}
188
194
189
195
196
+ // Root finding
197
+
198
+ void
199
+ find_roots (rust_task *task, irc_map &ircs, std::vector<void *> &roots) {
200
+ std::map<void *,type_desc *>::iterator begin (task->local_allocs .begin ()),
201
+ end (task->local_allocs .end ());
202
+ while (begin != end) {
203
+ void *alloc = begin->first ;
204
+ uintptr_t *ref_count_ptr = reinterpret_cast <uintptr_t *>(alloc);
205
+ uintptr_t ref_count = *ref_count_ptr;
206
+
207
+ uintptr_t irc;
208
+ if (ircs.find (alloc) != ircs.end ())
209
+ irc = ircs[alloc];
210
+ else
211
+ irc = 0 ;
212
+
213
+ if (irc < ref_count) {
214
+ // This allocation must be a root, because the internal reference
215
+ // count is smaller than the total reference count.
216
+ // DPRINT("root found: %p, irc %lu, ref count %lu\n", alloc, irc,
217
+ // ref_count);
218
+ roots.push_back (alloc);
219
+ } else {
220
+ // DPRINT("nonroot found: %p, ref count %lu\n", alloc, ref_count);
221
+ /* assert(irc == ref_count && "Internal reference count must be "
222
+ "less than or equal to the total reference count!");*/
223
+ }
224
+
225
+ ++begin;
226
+ }
227
+ }
228
+
229
+
230
+ // Marking
231
+
232
+ class mark : public shape ::data<mark,shape::ptr> {
233
+ friend class shape ::data<mark,shape::ptr>;
234
+
235
+ std::set<void *> &marked;
236
+
237
+ mark (const mark &other, const shape::ptr &in_dp)
238
+ : shape::data<mark,shape::ptr>(other.task, other.align, other.sp,
239
+ other.params, other.tables, in_dp),
240
+ marked (other.marked) {}
241
+
242
+ mark (const mark &other,
243
+ const uint8_t *in_sp,
244
+ const shape::type_param *in_params,
245
+ const rust_shape_tables *in_tables = NULL )
246
+ : shape::data<mark,shape::ptr>(other.task,
247
+ other.align,
248
+ in_sp,
249
+ in_params,
250
+ in_tables ? in_tables : other.tables,
251
+ other.dp),
252
+ marked (other.marked) {}
253
+
254
+ mark (const mark &other,
255
+ const uint8_t *in_sp,
256
+ const shape::type_param *in_params,
257
+ const rust_shape_tables *in_tables,
258
+ shape::ptr in_dp)
259
+ : shape::data<mark,shape::ptr>(other.task,
260
+ other.align,
261
+ in_sp,
262
+ in_params,
263
+ in_tables,
264
+ in_dp),
265
+ marked (other.marked) {}
266
+
267
+ mark (rust_task *in_task,
268
+ bool in_align,
269
+ const uint8_t *in_sp,
270
+ const shape::type_param *in_params,
271
+ const rust_shape_tables *in_tables,
272
+ uint8_t *in_data,
273
+ std::set<void *> &in_marked)
274
+ : shape::data<mark,shape::ptr>(in_task, in_align, in_sp, in_params,
275
+ in_tables, in_data),
276
+ marked (in_marked) {}
277
+
278
+ void walk_vec (bool is_pod, uint16_t sp_size) {
279
+ if (is_pod || shape::get_dp<void *>(dp) == NULL )
280
+ return ; // There can't be any outbound pointers from this.
281
+
282
+ std::pair<uint8_t *,uint8_t *> data_range (get_vec_data_range (dp));
283
+ if (data_range.second - data_range.first > 100000 )
284
+ abort (); // FIXME: Temporary sanity check.
285
+
286
+ mark sub (*this , data_range.first );
287
+ shape::ptr data_end = sub.end_dp = data_range.second ;
288
+ while (sub.dp < data_end) {
289
+ sub.walk_reset ();
290
+ align = true ;
291
+ }
292
+ }
293
+
294
+ void walk_tag (shape::tag_info &tinfo, uint32_t tag_variant) {
295
+ shape::data<mark,shape::ptr>::walk_variant (tinfo, tag_variant);
296
+ }
297
+
298
+ void walk_box () {
299
+ shape::data<mark,shape::ptr>::walk_box_contents ();
300
+ }
301
+
302
+ void walk_fn () {
303
+ shape::data<mark,shape::ptr>::walk_fn_contents (dp);
304
+ }
305
+
306
+ void walk_obj () {
307
+ shape::data<mark,shape::ptr>::walk_obj_contents (dp);
308
+ }
309
+
310
+ void walk_res (const shape::rust_fn *dtor, unsigned n_params,
311
+ const shape::type_param *params, const uint8_t *end_sp,
312
+ bool live) {
313
+ while (this ->sp != end_sp) {
314
+ this ->walk ();
315
+ align = true ;
316
+ }
317
+ }
318
+
319
+ void walk_subcontext (mark &sub) { sub.walk (); }
320
+
321
+ void walk_box_contents (mark &sub, shape::ptr &ref_count_dp) {
322
+ if (!ref_count_dp)
323
+ return ;
324
+
325
+ if (marked.find ((void *)ref_count_dp) != marked.end ())
326
+ return ; // Skip to avoid chasing cycles.
327
+
328
+ marked.insert ((void *)ref_count_dp);
329
+ sub.walk ();
330
+ }
331
+
332
+ void walk_struct (const uint8_t *end_sp) {
333
+ while (this ->sp != end_sp) {
334
+ this ->walk ();
335
+ align = true ;
336
+ }
337
+ }
338
+
339
+ void walk_variant (shape::tag_info &tinfo, uint32_t variant_id,
340
+ const std::pair<const uint8_t *,const uint8_t *>
341
+ variant_ptr_and_end);
342
+
343
+ template <typename T>
344
+ inline void walk_number () { /* no-op */ }
345
+
346
+ public:
347
+ static void do_mark (rust_task *task, const std::vector<void *> &roots,
348
+ std::set<void *> &marked);
349
+ };
350
+
351
+ void
352
+ mark::walk_variant (shape::tag_info &tinfo, uint32_t variant_id,
353
+ const std::pair<const uint8_t *,const uint8_t *>
354
+ variant_ptr_and_end) {
355
+ mark sub (*this , variant_ptr_and_end.first , tinfo.params );
356
+
357
+ assert (variant_id < 256 ); // FIXME: Temporary sanity check.
358
+
359
+ const uint8_t *variant_end = variant_ptr_and_end.second ;
360
+ while (sub.sp < variant_end) {
361
+ sub.walk ();
362
+ align = true ;
363
+ }
364
+ }
365
+
366
+ void
367
+ mark::do_mark (rust_task *task, const std::vector<void *> &roots,
368
+ std::set<void *> &marked) {
369
+ std::vector<void *>::const_iterator begin (roots.begin ()),
370
+ end (roots.end ());
371
+ while (begin != end) {
372
+ void *alloc = *begin;
373
+ if (marked.find (alloc) == marked.end ()) {
374
+ marked.insert (alloc);
375
+
376
+ uint8_t *p = reinterpret_cast <uint8_t *>(alloc);
377
+ p += sizeof (uintptr_t ); // Skip over the reference count.
378
+
379
+ type_desc *tydesc = task->local_allocs [*begin];
380
+
381
+ // DPRINT("marking: %p, tydesc=%p\n", p, tydesc);
382
+
383
+ shape::arena arena;
384
+ shape::type_param *params =
385
+ shape::type_param::from_tydesc (tydesc, arena);
386
+
387
+ #if 0
388
+ shape::log log(task, true, tydesc->shape, params,
389
+ tydesc->shape_tables, p, std::cerr);
390
+ log.walk();
391
+ DPRINT("\n");
392
+ #endif
393
+
394
+ mark mark (task, true , tydesc->shape , params, tydesc->shape_tables ,
395
+ p, marked);
396
+ mark.walk ();
397
+ }
398
+
399
+ ++begin;
400
+ }
401
+ }
402
+
403
+
404
+ void
405
+ sweep (rust_task *task, const std::set<void *> &marked) {
406
+ std::map<void *,type_desc *>::iterator begin (task->local_allocs .begin ()),
407
+ end (task->local_allocs .end ());
408
+ while (begin != end) {
409
+ void *alloc = begin->first ;
410
+ if (marked.find (alloc) == marked.end ()) {
411
+ DPRINT (" object is part of a cycle: %p\n " , alloc);
412
+ }
413
+ ++begin;
414
+ }
415
+ }
416
+
417
+
190
418
void
191
419
do_cc (rust_task *task) {
420
+ DPRINT (" cc; n allocs = %lu\n " , task->local_allocs .size ());
421
+
192
422
irc_map ircs;
193
423
irc::compute_ircs (task, ircs);
424
+
425
+ std::vector<void *> roots;
426
+ find_roots (task, ircs, roots);
427
+
428
+ std::set<void *> marked;
429
+ mark::do_mark (task, roots, marked);
430
+
431
+ sweep (task, marked);
194
432
}
195
433
196
434
void
0 commit comments