Remove experimental GC code

It's been sitting unused long enough to have bitrotted completely.
This commit is contained in:
Marijn Haverbeke 2012-02-03 09:34:42 +01:00
parent 1ea184285e
commit c1b075d042
24 changed files with 24 additions and 390 deletions

View File

@ -56,7 +56,6 @@ RUNTIME_CS_$(1) := \
rt/rust_kernel.cpp \
rt/rust_shape.cpp \
rt/rust_obstack.cpp \
rt/rust_gc.cpp \
rt/rust_abi.cpp \
rt/rust_cc.cpp \
rt/rust_debug.cpp \
@ -73,7 +72,6 @@ RUNTIME_HDR_$(1) := rt/globals.h \
rt/rust_abi.h \
rt/rust_cc.h \
rt/rust_debug.h \
rt/rust_gc.h \
rt/rust_internal.h \
rt/rust_util.h \
rt/rust_env.h \

View File

@ -56,7 +56,7 @@ fn declare_upcalls(targ_cfg: @session::config,
d("malloc", [T_ptr(tydesc_type)],
T_ptr(T_i8())),
free:
dv("free", [T_ptr(T_i8()), int_t]),
dv("free", [T_ptr(T_i8())]),
validate_box:
dv("validate_box", [T_ptr(T_i8())]),
shared_malloc:

View File

@ -412,7 +412,6 @@ fn build_session_options(match: getopts::match,
let addl_lib_search_paths = getopts::opt_strs(match, "L");
let cfg = parse_cfgspecs(getopts::opt_strs(match, "cfg"));
let test = opt_present(match, "test");
let do_gc = opt_present(match, "gc");
let warn_unused_imports = opt_present(match, "warn-unused-imports");
let sopts: @session::options =
@{crate_type: crate_type,
@ -434,7 +433,6 @@ fn build_session_options(match: getopts::match,
test: test,
parse_only: parse_only,
no_trans: no_trans,
do_gc: do_gc,
no_asm_comments: no_asm_comments,
warn_unused_imports: warn_unused_imports};
ret sopts;

View File

@ -46,7 +46,6 @@ type options =
test: bool,
parse_only: bool,
no_trans: bool,
do_gc: bool,
no_asm_comments: bool,
warn_unused_imports: bool};

View File

@ -1,148 +0,0 @@
// Routines useful for garbage collection.
import lib::llvm::{True, ValueRef};
import trans::base::get_tydesc;
import trans::common::*;
import trans::base;
import option::none;
import str;
import driver::session::session;
import lll = lib::llvm::llvm;
import bld = trans::build;
type ctxt = @{mutable next_tydesc_num: uint};
fn mk_ctxt() -> ctxt { ret @{mutable next_tydesc_num: 0u}; }
fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) -> ValueRef {
let llglobal =
str::as_buf(name,
{|buf|
lll::LLVMAddGlobal(ccx.llmod, val_ty(llval), buf)
});
lll::LLVMSetInitializer(llglobal, llval);
lll::LLVMSetGlobalConstant(llglobal, True);
ret llglobal;
}
fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> @block_ctxt {
let bcx = cx;
let ccx = bcx_ccx(cx);
if !type_is_gc_relevant(bcx_tcx(cx), ty) ||
ty::type_has_dynamic_size(bcx_tcx(cx), ty) {
ret bcx;
}
let gc_cx = bcx_ccx(cx).gc_cx;
// FIXME (issue #839): For now, we are unconditionally zeroing out all
// GC-relevant types. Eventually we should use typestate for this.
bcx = base::zero_alloca(bcx, llval, ty);
let ti = none;
let td_r = get_tydesc(bcx, ty, false, ti);
bcx = td_r.result.bcx;
let lltydesc = td_r.result.val;
let gcroot = bcx_ccx(bcx).intrinsics.get("llvm.gcroot");
let llvalptr = bld::PointerCast(bcx, llval, T_ptr(T_ptr(T_i8())));
alt td_r.kind {
tk_derived {
// It's a derived type descriptor. First, spill it.
let lltydescptr = base::alloca(bcx, val_ty(lltydesc));
let llderivedtydescs =
base::llderivedtydescs_block_ctxt(bcx_fcx(bcx));
bld::Store(llderivedtydescs, lltydesc, lltydescptr);
let number = gc_cx.next_tydesc_num;
gc_cx.next_tydesc_num += 1u;
let lldestindex =
add_global(bcx_ccx(bcx), C_struct([C_int(ccx, 0),
C_uint(ccx, number)]),
"rust_gc_tydesc_dest_index");
let llsrcindex =
add_global(bcx_ccx(bcx), C_struct([C_int(ccx, 1),
C_uint(ccx, number)]),
"rust_gc_tydesc_src_index");
lldestindex = lll::LLVMConstPointerCast(lldestindex, T_ptr(T_i8()));
llsrcindex = lll::LLVMConstPointerCast(llsrcindex, T_ptr(T_i8()));
lltydescptr =
bld::PointerCast(llderivedtydescs, lltydescptr,
T_ptr(T_ptr(T_i8())));
bld::Call(llderivedtydescs, gcroot, [lltydescptr, lldestindex]);
bld::Call(bcx, gcroot, [llvalptr, llsrcindex]);
}
tk_param {
bcx_tcx(cx).sess.bug("we should never be trying to root values " +
"of a type parameter");
}
tk_static {
// Static type descriptor.
let llstaticgcmeta =
add_global(bcx_ccx(bcx), C_struct([C_int(ccx, 2), lltydesc]),
"rust_gc_tydesc_static_gc_meta");
let llstaticgcmetaptr =
lll::LLVMConstPointerCast(llstaticgcmeta, T_ptr(T_i8()));
bld::Call(bcx, gcroot, [llvalptr, llstaticgcmetaptr]);
}
}
ret bcx;
}
fn type_is_gc_relevant(cx: ty::ctxt, ty: ty::t) -> bool {
alt ty::struct(cx, ty) {
ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_int(_) |
ty::ty_float(_) | ty::ty_uint(_) | ty::ty_str |
ty::ty_type | ty::ty_send_type | ty::ty_ptr(_) {
ret false;
}
ty::ty_rec(fields) {
for f in fields { if type_is_gc_relevant(cx, f.mt.ty) { ret true; } }
ret false;
}
ty::ty_tup(elts) {
for elt in elts { if type_is_gc_relevant(cx, elt) { ret true; } }
ret false;
}
ty::ty_enum(did, tps) {
let variants = ty::enum_variants(cx, did);
for variant in *variants {
for aty in variant.args {
let arg_ty = ty::substitute_type_params(cx, tps, aty);
if type_is_gc_relevant(cx, arg_ty) { ret true; }
}
}
ret false;
}
ty::ty_vec(tm) {
ret type_is_gc_relevant(cx, tm.ty);
}
ty::ty_constr(sub, _) { ret type_is_gc_relevant(cx, sub); }
ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_fn(_) |
ty::ty_param(_, _) | ty::ty_res(_, _, _) { ret true; }
ty::ty_opaque_closure_ptr(_) {
ret false; // I guess?
}
// A precondition to rule out these cases would be nice
ty::ty_var(_) {
fail "ty_var in type_is_gc_relevant";
}
ty::ty_iface(_, _) {
fail "ty_iface in type_is_gc_relevant";
}
ty::ty_named(_,_) {
fail "ty_named in type_is_gc_relevant";
}
}
}

View File

@ -21,7 +21,6 @@ import option::{some, none};
import driver::session;
import session::session;
import front::attr;
import middle::{ty, gc, resolve, debuginfo};
import middle::freevars::*;
import back::{link, abi, upcall};
import syntax::{ast, ast_util, codemap};
@ -350,14 +349,9 @@ fn trans_native_call(cx: @block_ctxt, externs: hashmap<str, ValueRef>,
ret Call(cx, llnative, call_args);
}
fn trans_free_if_not_gc(cx: @block_ctxt, v: ValueRef) -> @block_ctxt {
let ccx = bcx_ccx(cx);
if !ccx.sess.opts.do_gc {
Call(cx, ccx.upcalls.free,
[PointerCast(cx, v, T_ptr(T_i8())),
C_int(bcx_ccx(cx), 0)]);
}
ret cx;
fn trans_free(cx: @block_ctxt, v: ValueRef) -> @block_ctxt {
Call(cx, bcx_ccx(cx).upcalls.free, [PointerCast(cx, v, T_ptr(T_i8()))]);
cx
}
fn trans_shared_free(cx: @block_ctxt, v: ValueRef) -> @block_ctxt {
@ -1245,7 +1239,7 @@ fn free_box(bcx: @block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt {
let v = PointerCast(bcx, v, type_of_1(bcx, t));
let body = GEPi(bcx, v, [0, abi::box_field_body]);
let bcx = drop_ty(bcx, body, body_mt.ty);
trans_free_if_not_gc(bcx, v)
trans_free(bcx, v)
}
_ { fail "free_box invoked with non-box type"; }
@ -1280,7 +1274,7 @@ fn make_free_glue(bcx: @block_ctxt, v: ValueRef, t: ty::t) {
let ti = none;
call_tydesc_glue_full(bcx, body, tydesc,
abi::tydesc_field_drop_glue, ti);
trans_free_if_not_gc(bcx, b)
trans_free(bcx, b)
}
ty::ty_send_type {
// sendable type descriptors are basically unique pointers,
@ -4226,10 +4220,6 @@ fn alloc_ty(cx: @block_ctxt, t: ty::t) -> result {
// past caller conventions and may well make sense again,
// so we leave it as-is.
if bcx_tcx(cx).sess.opts.do_gc {
bcx = gc::add_gc_root(bcx, val, t);
}
ret rslt(cx, val);
}
@ -5604,7 +5594,6 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
opaque_vec_type: T_opaque_vec(targ_cfg),
builder: BuilderRef_res(llvm::LLVMCreateBuilder()),
shape_cx: shape::mk_ctxt(llmod),
gc_cx: gc::mk_ctxt(),
crate_map: crate_map,
dbg_cx: dbg_cx,
mutable do_not_commit_warning_issued: false};

View File

@ -716,7 +716,7 @@ fn make_opaque_cbox_free_glue(
alt ck {
ty::ck_block { fail "Impossible"; }
ty::ck_box {
trans_free_if_not_gc(bcx, cbox)
trans_free(bcx, cbox)
}
ty::ck_uniq {
let bcx = free_ty(bcx, tydesc, mk_tydesc_ty(tcx, ck));

View File

@ -120,7 +120,6 @@ type crate_ctxt =
opaque_vec_type: TypeRef,
builder: BuilderRef_res,
shape_cx: shape::ctxt,
gc_cx: gc::ctxt,
crate_map: ValueRef,
dbg_cx: option<@debuginfo::debug_ctxt>,
mutable do_not_commit_warning_issued: bool};
@ -286,7 +285,7 @@ fn add_clean_temp_mem(cx: @block_ctxt, val: ValueRef, ty: ty::t) {
fn add_clean_free(cx: @block_ctxt, ptr: ValueRef, shared: bool) {
let scope_cx = find_scope_cx(cx);
let free_fn = if shared { bind base::trans_shared_free(_, ptr) }
else { bind base::trans_free_if_not_gc(_, ptr) };
else { bind base::trans_free(_, ptr) };
scope_cx.cleanups += [clean_temp(ptr, free_fn)];
scope_cx.lpad_dirty = true;
}

View File

@ -39,7 +39,6 @@ mod middle {
mod kind;
mod freevars;
mod shape;
mod gc;
mod debuginfo;
mod capture;
mod pat_util;

View File

@ -17,7 +17,6 @@ native mod rustrt {
// visible-in-crate, but not re-exported.
fn last_os_error() -> str;
fn refcount<T>(t: @T) -> ctypes::intptr_t;
fn do_gc();
fn unsupervise();
fn shape_log_str<T>(t: *sys::type_desc, data: T) -> str;
fn rust_set_exit_status(code: ctypes::intptr_t);
@ -74,15 +73,6 @@ fn refcount<T>(t: @T) -> uint {
ret rustrt::refcount::<T>(t);
}
/*
Function: do_gc
Force a garbage collection
*/
fn do_gc() -> () {
ret rustrt::do_gc();
}
// FIXME: There's a wrapper for this in the task module and this really
// just belongs there
fn unsupervise() -> () {

View File

@ -91,11 +91,6 @@ refcount(intptr_t *v) {
return (*v) - 1;
}
extern "C" CDECL void
do_gc() {
// TODO
}
extern "C" CDECL void
unsupervise() {
rust_task *task = rust_scheduler::get_task();

View File

@ -2,7 +2,6 @@
// time until LLVM's GC infrastructure is more mature.
#include "rust_debug.h"
#include "rust_gc.h"
#include "rust_internal.h"
#include "rust_shape.h"
#include "rust_task.h"

View File

@ -1,164 +0,0 @@
// 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();
}
}
}

View File

@ -1,10 +0,0 @@
// Rust garbage collection.
struct rust_task;
namespace gc {
void maybe_gc(rust_task *task);
}

View File

@ -523,13 +523,13 @@ rust_task::malloc(size_t sz, const char *tag, type_desc *td)
}
void *
rust_task::realloc(void *data, size_t sz, bool is_gc)
rust_task::realloc(void *data, size_t sz)
{
return local_region.realloc(data, sz);
}
void
rust_task::free(void *p, bool is_gc)
rust_task::free(void *p)
{
local_region.free(p);
}

View File

@ -141,8 +141,8 @@ rust_task : public kernel_owned<rust_task>, rust_cond
bool dead();
void *malloc(size_t sz, const char *tag, type_desc *td=0);
void *realloc(void *data, size_t sz, bool gc_mem=false);
void free(void *p, bool gc_mem=false);
void *realloc(void *data, size_t sz);
void free(void *p);
void transition(rust_task_list *src, rust_task_list *dst);

View File

@ -7,7 +7,6 @@
*/
#include "rust_cc.h"
#include "rust_gc.h"
#include "rust_internal.h"
#include "rust_scheduler.h"
#include "rust_unwind.h"
@ -122,7 +121,6 @@ upcall_s_malloc(s_malloc_args *args) {
LOG(task, mem, "upcall malloc(0x%" PRIxPTR ")", args->td);
gc::maybe_gc(task);
cc::maybe_cc(task);
// FIXME--does this have to be calloc?
@ -151,7 +149,6 @@ upcall_malloc(type_desc *td) {
struct s_free_args {
void *ptr;
uintptr_t is_gc;
};
extern "C" CDECL void
@ -162,7 +159,7 @@ upcall_s_free(s_free_args *args) {
rust_scheduler *sched = task->sched;
DLOG(sched, mem,
"upcall free(0x%" PRIxPTR ", is_gc=%" PRIdPTR ")",
(uintptr_t)args->ptr, args->is_gc);
(uintptr_t)args->ptr);
debug::maybe_untrack_origin(task, args->ptr);
@ -171,8 +168,8 @@ upcall_s_free(s_free_args *args) {
}
extern "C" CDECL void
upcall_free(void* ptr, uintptr_t is_gc) {
s_free_args args = {ptr, is_gc};
upcall_free(void* ptr) {
s_free_args args = {ptr};
UPCALL_SWITCH_STACK(&args, upcall_s_free);
}

View File

@ -9,7 +9,6 @@ debug_ptrcast
debug_tag
debug_tydesc
debug_get_stk_seg
do_gc
drop_task
get_port_id
get_task_id

View File

@ -83,7 +83,6 @@ fn build_session() -> session::session {
test: false,
parse_only: false,
no_trans: false,
do_gc: false,
no_asm_comments: false,
warn_unused_imports: false
};

View File

@ -8,14 +8,14 @@
use std;
native mod rustrt {
fn do_gc();
fn last_os_error() -> str;
}
fn getbig_call_c_and_fail(i: int) {
if i != 0 {
getbig_call_c_and_fail(i - 1);
} else {
rustrt::do_gc();
rustrt::last_os_error();
fail;
}
}

View File

@ -4,7 +4,7 @@ Can we bind native things?
#[abi = "cdecl"]
native mod rustrt {
fn do_gc();
fn rand_new() -> *ctypes::void;
}
fn main() { bind rustrt::do_gc(); }
fn main() { bind rustrt::rand_new(); }

View File

@ -120,15 +120,13 @@ fn test_fn() {
#[abi = "cdecl"]
#[nolink]
native mod test {
fn do_gc();
fn unsupervise();
}
// FIXME (#1058): comparison of native fns
fn test_native_fn() {
/*
assert (native_mod::do_gc == native_mod::do_gc);
assert (native_mod::do_gc != native_mod::unsupervise);
assert (native_mod::last_os_error != native_mod::unsupervise);
*/
}

View File

@ -12,7 +12,6 @@ native mod rustrt {
fn last_os_error() -> str;
fn rust_getcwd() -> str;
fn refcount(box: @int);
fn do_gc();
fn get_task_id();
fn sched_threads();
fn rust_get_task();
@ -22,7 +21,6 @@ fn calllink01() { rustrt::unsupervise(); }
fn calllink02() { rustrt::last_os_error(); }
fn calllink03() { rustrt::rust_getcwd(); }
fn calllink04() { rustrt::refcount(@0); }
fn calllink05() { rustrt::do_gc(); }
fn calllink08() { rustrt::get_task_id(); }
fn calllink09() { rustrt::sched_threads(); }
fn calllink10() { rustrt::rust_get_task(); }
@ -55,7 +53,6 @@ fn main() {
calllink02,
calllink03,
calllink04,
calllink05,
calllink08,
calllink09,
calllink10

View File

@ -4,16 +4,16 @@
#[abi = "cdecl"]
#[link_name = "rustrt"]
native mod rustrt1 {
fn do_gc();
fn last_os_error() -> str;
}
#[abi = "cdecl"]
#[link_name = "rustrt"]
native mod rustrt2 {
fn do_gc();
fn last_os_error() -> str;
}
fn main() {
rustrt1::do_gc();
rustrt2::do_gc();
rustrt1::last_os_error();
rustrt2::last_os_error();
}