rust/src/rt/rust_gc.cpp

165 lines
3.5 KiB
C++

// Rust garbage collection.
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
#include <stdint.h>
#include "rust_abi.h"
#include "rust_debug.h"
#include "rust_gc.h"
#include "rust_internal.h"
#include "rust_shape.h"
#ifdef __WIN32__
#include <windows.h>
#else
#include <dlfcn.h>
#endif
using namespace stack_walk;
namespace gc {
weak_symbol<const uintptr_t> safe_point_data("rust_gc_safe_points");
struct root_info {
intptr_t frame_offset;
uintptr_t dynamic; // 0 = static, 1 = dynamic
const type_desc *tydesc;
};
struct root {
const type_desc *tydesc;
uint8_t *data;
root(const root_info &info, const frame &frame)
: tydesc(info.tydesc),
data((uint8_t *)frame.bp + info.frame_offset) {}
};
struct safe_point {
uintptr_t n_roots;
root_info roots[0];
};
struct safe_point_index_entry {
void (*ra)(); // The return address.
const struct safe_point *safe_point; // The safe point.
struct cmp {
bool operator()(const safe_point_index_entry &entry, void (*ra)())
const {
return entry.ra < ra;
}
bool operator()(void (*ra)(), const safe_point_index_entry &entry)
const {
return ra < entry.ra;
}
};
};
class safe_point_map {
uintptr_t n_safe_points;
const safe_point_index_entry *index;
const safe_point *safe_points;
public:
safe_point_map() {
const uintptr_t *data = *safe_point_data;
n_safe_points = *data++;
index = (const safe_point_index_entry *)data;
data += n_safe_points * 2;
safe_points = (const safe_point *)data;
}
const safe_point *get_safe_point(void (*addr)());
};
class gc {
private:
rust_task *task;
void mark(std::vector<root> &roots);
void sweep();
public:
gc(rust_task *in_task) : task(in_task) {}
void run();
};
const safe_point *
safe_point_map::get_safe_point(void (*addr)()) {
safe_point_index_entry::cmp cmp;
const safe_point_index_entry *entry =
std::lower_bound(index, index + n_safe_points, addr, cmp);
return (entry && entry->ra == addr) ? entry->safe_point : NULL;
}
void
gc::mark(std::vector<root> &roots) {
std::vector<root>::iterator ri = roots.begin(), rend = roots.end();
while (ri < rend) {
DPRINT("root: %p\n", ri->data);
shape::arena arena;
shape::type_param *params =
shape::type_param::from_tydesc_and_data(ri->tydesc, ri->data,
arena);
shape::log log(task, true, ri->tydesc->shape, params,
ri->tydesc->shape_tables, ri->data, std::cerr);
log.walk();
DPRINT("\n");
++ri;
}
// TODO
}
void
gc::sweep() {
// TODO
}
void
gc::run() {
safe_point_map map;
// Find roots.
std::vector<root> roots;
std::vector<frame> call_stack = backtrace();
for (unsigned i = 0; i < call_stack.size(); i++) {
frame f = call_stack[i];
const safe_point *sp = map.get_safe_point(f.ra);
if (!sp)
continue;
DPRINT("%u: ra %p, ebp %p\n", i, call_stack[i].ra, call_stack[i].bp);
for (unsigned j = 0; j < sp->n_roots; j++) {
root r(sp->roots[j], f);
roots.push_back(r);
}
}
// Mark and sweep.
mark(roots);
sweep();
}
void
maybe_gc(rust_task *task) {
if (*safe_point_data == NULL)
return;
static debug::flag zeal("RUST_GC_ZEAL");
if (*zeal) {
gc gc(task);
gc.run();
}
}
}