diff --git a/src/rt/rust_cc.cpp b/src/rt/rust_cc.cpp index 8129f60fc7c..87b9f62e106 100644 --- a/src/rt/rust_cc.cpp +++ b/src/rt/rust_cc.cpp @@ -1,45 +1,191 @@ // Rust cycle collector. Temporary, but will probably stick around for some // time until LLVM's GC infrastructure is more mature. -#include -#include -#include -#include #include "rust_gc.h" #include "rust_internal.h" #include "rust_shape.h" #include "rust_task.h" +#include +#include +#include +#include +#include #undef DPRINT #define DPRINT(fmt,...) fprintf(stderr, fmt, ##__VA_ARGS__) namespace cc { +// Internal reference count computation + +typedef std::map irc_map; + +class irc : public shape::data { + friend class shape::data; + + irc_map ircs; + + irc(const irc &other, const shape::ptr &in_dp) + : shape::data(other.task, other.align, other.sp, + other.params, other.tables, in_dp), + ircs(other.ircs) {} + + irc(const irc &other, + const uint8_t *in_sp, + const shape::type_param *in_params, + const rust_shape_tables *in_tables = NULL) + : shape::data(other.task, + other.align, + in_sp, + in_params, + in_tables ? in_tables : other.tables, + other.dp), + ircs(other.ircs) {} + + irc(const irc &other, + const uint8_t *in_sp, + const shape::type_param *in_params, + const rust_shape_tables *in_tables, + shape::ptr in_dp) + : shape::data(other.task, + other.align, + in_sp, + in_params, + in_tables, + in_dp), + ircs(other.ircs) {} + + irc(rust_task *in_task, + bool in_align, + const uint8_t *in_sp, + const shape::type_param *in_params, + const rust_shape_tables *in_tables, + uint8_t *in_data, + irc_map &in_ircs) + : shape::data(in_task, in_align, in_sp, in_params, + in_tables, in_data), + ircs(in_ircs) {} + + void walk_vec(bool is_pod, uint16_t sp_size) { + if (is_pod || shape::get_dp(dp) == NULL) + return; // There can't be any outbound pointers from this. + + std::pair data_range(get_vec_data_range(dp)); + if (data_range.second - data_range.first > 10000) + abort(); // FIXME: Temporary sanity check. + + irc sub(*this, data_range.first); + shape::ptr data_end = sub.end_dp = data_range.second; + while (sub.dp < data_end) { + sub.walk_reset(); + align = true; + } + } + + void walk_tag(shape::tag_info &tinfo, uint32_t tag_variant) { + shape::data::walk_variant(tinfo, tag_variant); + } + + void walk_box() { + shape::data::walk_box_contents(); + } + + void walk_fn() { + shape::data::walk_fn_contents(dp); + } + + void walk_obj() { + shape::data::walk_obj_contents(dp); + } + + void walk_res(const shape::rust_fn *dtor, unsigned n_params, + const shape::type_param *params, const uint8_t *end_sp, + bool live) { + while (this->sp != end_sp) { + this->walk(); + align = true; + } + } + + void walk_subcontext(irc &sub) { sub.walk(); } + + void walk_box_contents(irc &sub, shape::ptr &ref_count_dp) { + if (!ref_count_dp) + return; + + // Bump the internal reference count of the box. + if (ircs.find((void *)dp) == ircs.end()) + ircs[(void *)dp] = 1; + else + ++ircs[(void *)dp]; + + // Do not traverse the contents of this box; it's in the allocation + // somewhere, so we're guaranteed to come back to it (if we haven't + // traversed it already). + } + + void walk_struct(const uint8_t *end_sp) { + while (this->sp != end_sp) { + this->walk(); + align = true; + } + } + + void walk_variant(shape::tag_info &tinfo, uint32_t variant_id, + const std::pair + variant_ptr_and_end); + + template + inline void walk_number() { /* no-op */ } + +public: + static void compute_ircs(rust_task *task, irc_map &ircs); +}; + void -do_cc(rust_task *task) { - std::map::iterator begin(task->local_allocs.begin()); - std::map::iterator end(task->local_allocs.end()); +irc::walk_variant(shape::tag_info &tinfo, uint32_t variant_id, + const std::pair + variant_ptr_and_end) { + irc sub(*this, variant_ptr_and_end.first, tinfo.params); + + assert(variant_id < 256); // FIXME: Temporary sanity check. + + const uint8_t *variant_end = variant_ptr_and_end.second; + while (sub.sp < variant_end) { + sub.walk(); + align = true; + } +} + +void +irc::compute_ircs(rust_task *task, irc_map &ircs) { + std::map::iterator begin(task->local_allocs.begin()), + end(task->local_allocs.end()); while (begin != end) { - void *p = begin->first; + uint8_t *p = reinterpret_cast(begin->first); type_desc *tydesc = begin->second; - DPRINT("marking allocation: %p, tydesc=%p\n", p, tydesc); + DPRINT("determining internal ref counts: %p, tydesc=%p\n", p, tydesc); // Prevents warnings for now - (void)p; - (void)tydesc; -#if 0 shape::arena arena; shape::type_param *params = shape::type_param::from_tydesc(tydesc, arena); - mark mark(task, true, tydesc->shape, params, tydesc->shape_tables, p); - mark.walk(); -#endif + irc irc(task, true, tydesc->shape, params, tydesc->shape_tables, p, + ircs); + irc.walk(); ++begin; } } + +void +do_cc(rust_task *task) { + irc_map ircs; + irc::compute_ircs(task, ircs); +} + void maybe_cc(rust_task *task) { // FIXME: We ought to lock this.