1
Fork 0

rustc: Stub stack map generation machinery

This commit is contained in:
Patrick Walton 2011-08-17 19:11:01 -07:00
parent 51af43f192
commit 117d21d6c2
5 changed files with 124 additions and 46 deletions

View file

@ -1,32 +1,96 @@
// Routines useful for garbage collection.
import lib::llvm::False;
import lib::llvm::True;
import lib::llvm::llvm::ValueRef;
import middle::trans::get_tydesc;
import middle::trans_common::*;
import middle::ty;
import std::option::none;
import std::option::some;
import std::ptr;
import std::str;
import std::unsafe;
import std::vec;
import lll = lib::llvm::llvm;
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 = lll::LLVMAddGlobal(ccx.llmod, val_ty(llval),
str::buf(name));
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;
if !type_is_gc_relevant(bcx_tcx(cx), ty) { ret bcx; }
if !type_is_gc_relevant(bcx_tcx(cx), ty) ||
ty::type_has_dynamic_size(bcx_tcx(cx), ty) {
ret bcx;
}
let md_kind_name = "rusttydesc";
let md_kind = lll::LLVMGetMDKindID(str::buf(md_kind_name),
str::byte_len(md_kind_name));
let gc_cx = bcx_ccx(cx).gc_cx;
let ti = none;
let r = get_tydesc(bcx, ty, false, ti);
bcx = r.bcx;
let lltydesc = r.val;
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 = bcx.build.PointerCast(llval, T_ptr(T_ptr(T_i8())));
alt td_r.kind {
tk_derived. {
// It's a derived type descriptor. First, spill it.
let lltydescptr = trans::alloca(bcx, val_ty(lltydesc));
bcx.build.Store(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(0),
C_uint(number)]),
"rust_gc_tydesc_dest_index");
let llsrcindex = add_global(bcx_ccx(bcx),
C_struct(~[C_int(1), C_uint(number)]),
"rust_gc_tydesc_src_index");
lldestindex = lll::LLVMConstPointerCast(lldestindex,
T_ptr(T_i8()));
llsrcindex = lll::LLVMConstPointerCast(llsrcindex,
T_ptr(T_i8()));
lltydescptr = bcx.build.PointerCast(lltydescptr,
T_ptr(T_ptr(T_i8())));
bcx.build.Call(gcroot, ~[ lltydescptr, lldestindex ]);
bcx.build.Call(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(2), lltydesc]),
"rust_gc_tydesc_static_gc_meta");
let llstaticgcmetaptr = lll::LLVMConstPointerCast(llstaticgcmeta,
T_ptr(T_i8()));
bcx.build.Call(gcroot, ~[ llvalptr, llstaticgcmetaptr ]);
}
}
let llmdnode =
lll::LLVMMDNode(unsafe::reinterpret_cast(ptr::addr_of(lltydesc)), 1u);
lll::LLVMSetMetadata(llval, md_kind, llmdnode);
ret bcx;
}
@ -57,9 +121,7 @@ fn type_is_gc_relevant(cx: &ty::ctxt, ty: &ty::t) -> bool {
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;
}
if type_is_gc_relevant(cx, arg_ty) { ret true; }
}
}
ret false;

View file

@ -23,6 +23,7 @@ import std::option::some;
import std::option::none;
import std::fs;
import std::time;
import std::vec;
import syntax::ast;
import driver::session;
import middle::ty;
@ -901,7 +902,7 @@ fn trans_malloc_boxed(cx: &@block_ctxt, t: ty::t) ->
fn field_of_tydesc(cx: &@block_ctxt, t: &ty::t, escapes: bool, field: int) ->
result {
let ti = none::<@tydesc_info>;
let tydesc = get_tydesc(cx, t, escapes, ti);
let tydesc = get_tydesc(cx, t, escapes, ti).result;
ret rslt(tydesc.bcx,
tydesc.bcx.build.GEP(tydesc.val, ~[C_int(0), C_int(field)]));
}
@ -1028,16 +1029,19 @@ fn get_derived_tydesc(cx: &@block_ctxt, t: &ty::t, escapes: bool,
ret rslt(cx, v);
}
type get_tydesc_result = { kind: tydesc_kind, result: result };
fn get_tydesc(cx: &@block_ctxt, orig_t: &ty::t, escapes: bool,
static_ti: &mutable option::t<@tydesc_info>) -> result {
static_ti: &mutable option::t<@tydesc_info>)
-> get_tydesc_result {
let t = ty::strip_cname(bcx_tcx(cx), orig_t);
// Is the supplied type a type param? If so, return the passed-in tydesc.
alt ty::type_param(bcx_tcx(cx), t) {
some(id) {
if id < std::vec::len(cx.fcx.lltydescs) {
ret rslt(cx, cx.fcx.lltydescs.(id));
if id < vec::len(cx.fcx.lltydescs) {
ret { kind: tk_param, result: rslt(cx, cx.fcx.lltydescs.(id)) };
}
else {
bcx_tcx(cx).sess.span_bug(cx.sp, "Unbound typaram in get_tydesc: "
@ -1050,13 +1054,16 @@ fn get_tydesc(cx: &@block_ctxt, orig_t: &ty::t, escapes: bool,
// Does it contain a type param? If so, generate a derived tydesc.
if ty::type_contains_params(bcx_tcx(cx), t) {
ret get_derived_tydesc(cx, t, escapes, static_ti);
ret {
kind: tk_derived,
result: get_derived_tydesc(cx, t, escapes, static_ti)
};
}
// Otherwise, generate a tydesc if necessary, and return it.
let info = get_static_tydesc(cx, t, ~[]);
static_ti = some::<@tydesc_info>(info);
ret rslt(cx, info.tydesc);
ret { kind: tk_static, result: rslt(cx, info.tydesc) };
}
fn get_static_tydesc(cx: &@block_ctxt, orig_t: &ty::t, ty_params: &[uint]) ->
@ -1484,9 +1491,9 @@ fn trans_res_drop(cx: @block_ctxt, rs: ValueRef, did: &ast::def_id,
cx.build.Load(cx.build.GEP(dtor_pair,
~[C_int(0), C_int(abi::fn_field_box)]));
let args = ~[cx.fcx.llretptr, cx.fcx.lltaskptr, dtor_env];
for tp: ty::t in tps {
for tp: ty::t in tps {
let ti: option::t<@tydesc_info> = none;
let td = get_tydesc(cx, tp, false, ti);
let td = get_tydesc(cx, tp, false, ti).result;
args += ~[td.val];
cx = td.bcx;
}
@ -2130,7 +2137,7 @@ fn call_tydesc_glue_full(cx: &@block_ctxt, v: ValueRef, tydesc: ValueRef,
fn call_tydesc_glue(cx: &@block_ctxt, v: ValueRef, t: &ty::t, field: int) ->
result {
let ti: option::t<@tydesc_info> = none::<@tydesc_info>;
let td = get_tydesc(cx, t, false, ti);
let td = get_tydesc(cx, t, false, ti).result;
call_tydesc_glue_full(td.bcx, spill_if_immediate(td.bcx, v, t), td.val,
field, ti);
ret rslt(td.bcx, C_nil());
@ -2146,7 +2153,7 @@ fn call_cmp_glue(cx: &@block_ctxt, lhs: ValueRef, rhs: ValueRef, t: &ty::t,
let llrawlhsptr = cx.build.BitCast(lllhs, T_ptr(T_i8()));
let llrawrhsptr = cx.build.BitCast(llrhs, T_ptr(T_i8()));
let ti = none::<@tydesc_info>;
let r = get_tydesc(cx, t, false, ti);
let r = get_tydesc(cx, t, false, ti).result;
lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, ti);
let lltydesc = r.val;
let lltydescs =
@ -2561,10 +2568,10 @@ fn trans_vec_append(cx: &@block_ctxt, t: &ty::t, lhs: ValueRef, rhs: ValueRef)
}
let bcx = cx;
let ti = none::<@tydesc_info>;
let llvec_tydesc = get_tydesc(bcx, t, false, ti);
let llvec_tydesc = get_tydesc(bcx, t, false, ti).result;
bcx = llvec_tydesc.bcx;
ti = none::<@tydesc_info>;
let llelt_tydesc = get_tydesc(bcx, elt_ty, false, ti);
let llelt_tydesc = get_tydesc(bcx, elt_ty, false, ti).result;
lazily_emit_tydesc_glue(cx, abi::tydesc_field_copy_glue, ti);
lazily_emit_tydesc_glue(cx, abi::tydesc_field_drop_glue, ti);
lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, ti);
@ -2819,9 +2826,9 @@ mod ivec {
// FIXME (issue #511): This is needed to prevent a leak.
let no_tydesc_info = none;
rs = get_tydesc(bcx, t, false, no_tydesc_info);
rs = get_tydesc(bcx, t, false, no_tydesc_info).result;
bcx = rs.bcx;
rs = get_tydesc(bcx, unit_ty, false, no_tydesc_info);
rs = get_tydesc(bcx, unit_ty, false, no_tydesc_info).result;
bcx = rs.bcx;
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_copy_glue, none);
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, none);
@ -3527,7 +3534,7 @@ fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef],
if copying {
let bound_tydesc = GEPi(bcx, closure, ~[0, abi::closure_elt_tydesc]);
let ti = none;
let bindings_tydesc = get_tydesc(bcx, bindings_ty, true, ti);
let bindings_tydesc = get_tydesc(bcx, bindings_ty, true, ti).result;
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
bcx = bindings_tydesc.bcx;
@ -3848,7 +3855,7 @@ fn lval_generic_fn(cx: &@block_ctxt, tpt: &ty::ty_param_kinds_and_ty,
// TODO: Doesn't always escape.
let ti = none::<@tydesc_info>;
let td = get_tydesc(bcx, t, true, ti);
let td = get_tydesc(bcx, t, true, ti).result;
tis += ~[ti];
bcx = td.bcx;
tydescs += ~[td.val];
@ -5254,7 +5261,7 @@ fn trans_log(lvl: int, cx: &@block_ctxt, e: &@ast::expr) -> result {
let log_bcx = sub.bcx;
let ti = none::<@tydesc_info>;
let r = get_tydesc(log_bcx, e_ty, false, ti);
let r = get_tydesc(log_bcx, e_ty, false, ti).result;
log_bcx = r.bcx;
// Call the polymorphic log function.
@ -6926,6 +6933,9 @@ fn declare_intrinsics(llmod: ModuleRef) -> hashmap<str, ValueRef> {
let T_memset64_args: [TypeRef] =
~[T_ptr(T_i8()), T_i8(), T_i64(), T_i32(), T_i1()];
let T_trap_args: [TypeRef] = ~[];
let gcroot =
decl_cdecl_fn(llmod, "llvm.gcroot",
T_fn(~[T_ptr(T_ptr(T_i8())), T_ptr(T_i8())], T_void()));
let gcread =
decl_cdecl_fn(llmod, "llvm.gcread",
T_fn(~[T_ptr(T_i8()), T_ptr(T_ptr(T_i8()))], T_void()));
@ -6943,6 +6953,7 @@ fn declare_intrinsics(llmod: ModuleRef) -> hashmap<str, ValueRef> {
T_fn(T_memset64_args, T_void()));
let trap = decl_cdecl_fn(llmod, "llvm.trap", T_fn(T_trap_args, T_void()));
let intrinsics = new_str_hash::<ValueRef>();
intrinsics.insert("llvm.gcroot", gcroot);
intrinsics.insert("llvm.gcread", gcread);
intrinsics.insert("llvm.memmove.p0i8.p0i8.i32", memmove32);
intrinsics.insert("llvm.memmove.p0i8.p0i8.i64", memmove64);
@ -7142,7 +7153,8 @@ fn trans_crate(sess: &session::session, crate: &@ast::crate, tcx: &ty::ctxt,
rust_object_type: T_rust_object(),
tydesc_type: tydesc_type,
task_type: task_type,
shape_cx: shape::mk_ctxt(llmod)};
shape_cx: shape::mk_ctxt(llmod),
gc_cx: gc::mk_ctxt()};
let cx = new_local_ctxt(ccx);
collect_items(ccx, crate);
collect_tag_ctors(ccx, crate);

View file

@ -70,6 +70,12 @@ type derived_tydesc_info = {lltydesc: ValueRef, escapes: bool};
type glue_fns = {no_op_type_glue: ValueRef};
tag tydesc_kind {
tk_static; // Static (monomorphic) type descriptor.
tk_param; // Type parameter.
tk_derived; // Derived from a typaram or another derived tydesc.
}
type tydesc_info =
{ty: ty::t,
tydesc: ValueRef,
@ -142,7 +148,8 @@ type crate_ctxt = {
rust_object_type: TypeRef,
tydesc_type: TypeRef,
task_type: TypeRef,
shape_cx: shape::ctxt
shape_cx: shape::ctxt,
gc_cx: gc::ctxt
};
type local_ctxt =

View file

@ -133,7 +133,7 @@ fn trans_obj(cx: @local_ctxt, sp: &span, ob: &ast::_obj,
~[0, abi::obj_body_elt_tydesc]);
bcx = body_tydesc.bcx;
let ti = none::<@tydesc_info>;
let body_td = get_tydesc(bcx, body_ty, true, ti);
let body_td = get_tydesc(bcx, body_ty, true, ti).result;
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
bcx = body_td.bcx;
@ -327,7 +327,7 @@ fn trans_anon_obj(bcx: @block_ctxt, sp: &span, anon_obj: &ast::anon_obj,
~[0, abi::obj_body_elt_tydesc]);
bcx = body_tydesc.bcx;
let ti = none::<@tydesc_info>;
let body_td = get_tydesc(bcx, body_ty, true, ti);
let body_td = get_tydesc(bcx, body_ty, true, ti).result;
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
bcx = body_td.bcx;

View file

@ -16,19 +16,16 @@
using namespace llvm;
namespace {
class RustGCStrategy : public GCStrategy {
public:
RustGCStrategy();
};
}
class RustGCStrategy : public GCStrategy {
public:
RustGCStrategy() {
NeededSafePoints = 1 << GC::PostCall;
UsesMetadata = true;
InitRoots = false; // LLVM crashes with this on due to bitcasts.
}
};
static GCRegistry::Add<RustGCStrategy>
X("rust", "Rust GC");
RustGCStrategy::RustGCStrategy() {
NeededSafePoints = 1 << GC::PostCall;
UsesMetadata = true;
}
RustGCStrategyRegistration("rust", "Rust GC");