auto merge of #12059 : thestinger/rust/glue, r=pcwalton

A follow-up from the work I started with 383e3fd13b.
This commit is contained in:
bors 2014-02-07 19:31:31 -08:00
commit 80c6c73647
17 changed files with 389 additions and 317 deletions

View File

@ -214,8 +214,7 @@ impl Arena {
#[inline] #[inline]
fn alloc_pod<'a, T>(&'a mut self, op: || -> T) -> &'a T { fn alloc_pod<'a, T>(&'a mut self, op: || -> T) -> &'a T {
unsafe { unsafe {
let tydesc = get_tydesc::<T>(); let ptr = self.alloc_pod_inner(mem::size_of::<T>(), mem::min_align_of::<T>());
let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align);
let ptr: *mut T = transmute(ptr); let ptr: *mut T = transmute(ptr);
intrinsics::move_val_init(&mut (*ptr), op()); intrinsics::move_val_init(&mut (*ptr), op());
return transmute(ptr); return transmute(ptr);
@ -272,7 +271,7 @@ impl Arena {
unsafe { unsafe {
let tydesc = get_tydesc::<T>(); let tydesc = get_tydesc::<T>();
let (ty_ptr, ptr) = let (ty_ptr, ptr) =
self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align); self.alloc_nonpod_inner(mem::size_of::<T>(), mem::min_align_of::<T>());
let ty_ptr: *mut uint = transmute(ty_ptr); let ty_ptr: *mut uint = transmute(ty_ptr);
let ptr: *mut T = transmute(ptr); let ptr: *mut T = transmute(ptr);
// Write in our tydesc along with a bit indicating that it // Write in our tydesc along with a bit indicating that it

View File

@ -352,7 +352,6 @@ pub fn malloc_raw_dyn<'a>(
if heap == heap_exchange { if heap == heap_exchange {
let llty_value = type_of::type_of(ccx, t); let llty_value = type_of::type_of(ccx, t);
// Allocate space: // Allocate space:
let r = callee::trans_lang_call( let r = callee::trans_lang_call(
bcx, bcx,
@ -375,17 +374,14 @@ pub fn malloc_raw_dyn<'a>(
// Grab the TypeRef type of box_ptr_ty. // Grab the TypeRef type of box_ptr_ty.
let box_ptr_ty = ty::mk_box(bcx.tcx(), t); let box_ptr_ty = ty::mk_box(bcx.tcx(), t);
let llty = type_of(ccx, box_ptr_ty); let llty = type_of(ccx, box_ptr_ty);
let llalign = C_uint(ccx, llalign_of_min(ccx, llty) as uint);
// Get the tydesc for the body:
let static_ti = get_tydesc(ccx, t);
glue::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti);
// Allocate space: // Allocate space:
let tydesc = PointerCast(bcx, static_ti.tydesc, Type::i8p()); let drop_glue = glue::get_drop_glue(ccx, t);
let r = callee::trans_lang_call( let r = callee::trans_lang_call(
bcx, bcx,
langcall, langcall,
[tydesc, size], [PointerCast(bcx, drop_glue, Type::glue_fn(Type::i8p()).ptr_to()), size, llalign],
None); None);
rslt(r.bcx, PointerCast(r.bcx, r.val, llty)) rslt(r.bcx, PointerCast(r.bcx, r.val, llty))
} }

View File

@ -114,7 +114,6 @@ pub struct tydesc_info {
size: ValueRef, size: ValueRef,
align: ValueRef, align: ValueRef,
name: ValueRef, name: ValueRef,
drop_glue: Cell<Option<ValueRef>>,
visit_glue: Cell<Option<ValueRef>>, visit_glue: Cell<Option<ValueRef>>,
} }

View File

@ -36,83 +36,84 @@ use syntax::ast;
use syntax::parse::token::InternedString; use syntax::parse::token::InternedString;
pub struct CrateContext { pub struct CrateContext {
sess: session::Session, sess: session::Session,
llmod: ModuleRef, llmod: ModuleRef,
llcx: ContextRef, llcx: ContextRef,
metadata_llmod: ModuleRef, metadata_llmod: ModuleRef,
td: TargetData, td: TargetData,
tn: TypeNames, tn: TypeNames,
externs: RefCell<ExternMap>, externs: RefCell<ExternMap>,
intrinsics: HashMap<&'static str, ValueRef>, intrinsics: HashMap<&'static str, ValueRef>,
item_vals: RefCell<HashMap<ast::NodeId, ValueRef>>, item_vals: RefCell<HashMap<ast::NodeId, ValueRef>>,
exp_map2: resolve::ExportMap2, exp_map2: resolve::ExportMap2,
reachable: @RefCell<HashSet<ast::NodeId>>, reachable: @RefCell<HashSet<ast::NodeId>>,
item_symbols: RefCell<HashMap<ast::NodeId, ~str>>, item_symbols: RefCell<HashMap<ast::NodeId, ~str>>,
link_meta: LinkMeta, link_meta: LinkMeta,
tydescs: RefCell<HashMap<ty::t, @tydesc_info>>, drop_glues: RefCell<HashMap<ty::t, ValueRef>>,
// Set when running emit_tydescs to enforce that no more tydescs are tydescs: RefCell<HashMap<ty::t, @tydesc_info>>,
// created. // Set when running emit_tydescs to enforce that no more tydescs are
finished_tydescs: Cell<bool>, // created.
// Track mapping of external ids to local items imported for inlining finished_tydescs: Cell<bool>,
external: RefCell<HashMap<ast::DefId, Option<ast::NodeId>>>, // Track mapping of external ids to local items imported for inlining
// Backwards version of the `external` map (inlined items to where they external: RefCell<HashMap<ast::DefId, Option<ast::NodeId>>>,
// came from) // Backwards version of the `external` map (inlined items to where they
external_srcs: RefCell<HashMap<ast::NodeId, ast::DefId>>, // came from)
// A set of static items which cannot be inlined into other crates. This external_srcs: RefCell<HashMap<ast::NodeId, ast::DefId>>,
// will pevent in IIItem() structures from being encoded into the metadata // A set of static items which cannot be inlined into other crates. This
// that is generated // will pevent in IIItem() structures from being encoded into the metadata
non_inlineable_statics: RefCell<HashSet<ast::NodeId>>, // that is generated
// Cache instances of monomorphized functions non_inlineable_statics: RefCell<HashSet<ast::NodeId>>,
monomorphized: RefCell<HashMap<mono_id, ValueRef>>, // Cache instances of monomorphized functions
monomorphizing: RefCell<HashMap<ast::DefId, uint>>, monomorphized: RefCell<HashMap<mono_id, ValueRef>>,
// Cache generated vtables monomorphizing: RefCell<HashMap<ast::DefId, uint>>,
vtables: RefCell<HashMap<(ty::t, mono_id), ValueRef>>, // Cache generated vtables
// Cache of constant strings, vtables: RefCell<HashMap<(ty::t, mono_id), ValueRef>>,
const_cstr_cache: RefCell<HashMap<InternedString, ValueRef>>, // Cache of constant strings,
const_cstr_cache: RefCell<HashMap<InternedString, ValueRef>>,
// Reverse-direction for const ptrs cast from globals. // Reverse-direction for const ptrs cast from globals.
// Key is an int, cast from a ValueRef holding a *T, // Key is an int, cast from a ValueRef holding a *T,
// Val is a ValueRef holding a *[T]. // Val is a ValueRef holding a *[T].
// //
// Needed because LLVM loses pointer->pointee association // Needed because LLVM loses pointer->pointee association
// when we ptrcast, and we have to ptrcast during translation // when we ptrcast, and we have to ptrcast during translation
// of a [T] const because we form a slice, a [*T,int] pair, not // of a [T] const because we form a slice, a [*T,int] pair, not
// a pointer to an LLVM array type. // a pointer to an LLVM array type.
const_globals: RefCell<HashMap<int, ValueRef>>, const_globals: RefCell<HashMap<int, ValueRef>>,
// Cache of emitted const values // Cache of emitted const values
const_values: RefCell<HashMap<ast::NodeId, ValueRef>>, const_values: RefCell<HashMap<ast::NodeId, ValueRef>>,
// Cache of external const values // Cache of external const values
extern_const_values: RefCell<HashMap<ast::DefId, ValueRef>>, extern_const_values: RefCell<HashMap<ast::DefId, ValueRef>>,
impl_method_cache: RefCell<HashMap<(ast::DefId, ast::Name), ast::DefId>>, impl_method_cache: RefCell<HashMap<(ast::DefId, ast::Name), ast::DefId>>,
// Cache of closure wrappers for bare fn's. // Cache of closure wrappers for bare fn's.
closure_bare_wrapper_cache: RefCell<HashMap<ValueRef, ValueRef>>, closure_bare_wrapper_cache: RefCell<HashMap<ValueRef, ValueRef>>,
module_data: RefCell<HashMap<~str, ValueRef>>, module_data: RefCell<HashMap<~str, ValueRef>>,
lltypes: RefCell<HashMap<ty::t, Type>>, lltypes: RefCell<HashMap<ty::t, Type>>,
llsizingtypes: RefCell<HashMap<ty::t, Type>>, llsizingtypes: RefCell<HashMap<ty::t, Type>>,
adt_reprs: RefCell<HashMap<ty::t, @adt::Repr>>, adt_reprs: RefCell<HashMap<ty::t, @adt::Repr>>,
symbol_hasher: RefCell<Sha256>, symbol_hasher: RefCell<Sha256>,
type_hashcodes: RefCell<HashMap<ty::t, ~str>>, type_hashcodes: RefCell<HashMap<ty::t, ~str>>,
all_llvm_symbols: RefCell<HashSet<~str>>, all_llvm_symbols: RefCell<HashSet<~str>>,
tcx: ty::ctxt, tcx: ty::ctxt,
maps: astencode::Maps, maps: astencode::Maps,
stats: @Stats, stats: @Stats,
tydesc_type: Type, tydesc_type: Type,
int_type: Type, int_type: Type,
opaque_vec_type: Type, opaque_vec_type: Type,
builder: BuilderRef_res, builder: BuilderRef_res,
crate_map: ValueRef, crate_map: ValueRef,
crate_map_name: ~str, crate_map_name: ~str,
// Set when at least one function uses GC. Needed so that // Set when at least one function uses GC. Needed so that
// decl_gc_metadata knows whether to link to the module metadata, which // decl_gc_metadata knows whether to link to the module metadata, which
// is not emitted by LLVM's GC pass when no functions use GC. // is not emitted by LLVM's GC pass when no functions use GC.
uses_gc: bool, uses_gc: bool,
dbg_cx: Option<debuginfo::CrateDebugContext>, dbg_cx: Option<debuginfo::CrateDebugContext>,
do_not_commit_warning_issued: Cell<bool>, do_not_commit_warning_issued: Cell<bool>,
} }
impl CrateContext { impl CrateContext {
@ -175,64 +176,65 @@ impl CrateContext {
} }
CrateContext { CrateContext {
sess: sess, sess: sess,
llmod: llmod, llmod: llmod,
llcx: llcx, llcx: llcx,
metadata_llmod: metadata_llmod, metadata_llmod: metadata_llmod,
td: td, td: td,
tn: tn, tn: tn,
externs: RefCell::new(HashMap::new()), externs: RefCell::new(HashMap::new()),
intrinsics: intrinsics, intrinsics: intrinsics,
item_vals: RefCell::new(HashMap::new()), item_vals: RefCell::new(HashMap::new()),
exp_map2: emap2, exp_map2: emap2,
reachable: reachable, reachable: reachable,
item_symbols: RefCell::new(HashMap::new()), item_symbols: RefCell::new(HashMap::new()),
link_meta: link_meta, link_meta: link_meta,
tydescs: RefCell::new(HashMap::new()), drop_glues: RefCell::new(HashMap::new()),
finished_tydescs: Cell::new(false), tydescs: RefCell::new(HashMap::new()),
external: RefCell::new(HashMap::new()), finished_tydescs: Cell::new(false),
external_srcs: RefCell::new(HashMap::new()), external: RefCell::new(HashMap::new()),
non_inlineable_statics: RefCell::new(HashSet::new()), external_srcs: RefCell::new(HashMap::new()),
monomorphized: RefCell::new(HashMap::new()), non_inlineable_statics: RefCell::new(HashSet::new()),
monomorphizing: RefCell::new(HashMap::new()), monomorphized: RefCell::new(HashMap::new()),
vtables: RefCell::new(HashMap::new()), monomorphizing: RefCell::new(HashMap::new()),
const_cstr_cache: RefCell::new(HashMap::new()), vtables: RefCell::new(HashMap::new()),
const_globals: RefCell::new(HashMap::new()), const_cstr_cache: RefCell::new(HashMap::new()),
const_values: RefCell::new(HashMap::new()), const_globals: RefCell::new(HashMap::new()),
extern_const_values: RefCell::new(HashMap::new()), const_values: RefCell::new(HashMap::new()),
impl_method_cache: RefCell::new(HashMap::new()), extern_const_values: RefCell::new(HashMap::new()),
closure_bare_wrapper_cache: RefCell::new(HashMap::new()), impl_method_cache: RefCell::new(HashMap::new()),
module_data: RefCell::new(HashMap::new()), closure_bare_wrapper_cache: RefCell::new(HashMap::new()),
lltypes: RefCell::new(HashMap::new()), module_data: RefCell::new(HashMap::new()),
llsizingtypes: RefCell::new(HashMap::new()), lltypes: RefCell::new(HashMap::new()),
adt_reprs: RefCell::new(HashMap::new()), llsizingtypes: RefCell::new(HashMap::new()),
symbol_hasher: RefCell::new(symbol_hasher), adt_reprs: RefCell::new(HashMap::new()),
type_hashcodes: RefCell::new(HashMap::new()), symbol_hasher: RefCell::new(symbol_hasher),
all_llvm_symbols: RefCell::new(HashSet::new()), type_hashcodes: RefCell::new(HashMap::new()),
tcx: tcx, all_llvm_symbols: RefCell::new(HashSet::new()),
maps: maps, tcx: tcx,
stats: @Stats { maps: maps,
n_static_tydescs: Cell::new(0u), stats: @Stats {
n_glues_created: Cell::new(0u), n_static_tydescs: Cell::new(0u),
n_null_glues: Cell::new(0u), n_glues_created: Cell::new(0u),
n_real_glues: Cell::new(0u), n_null_glues: Cell::new(0u),
n_fns: Cell::new(0u), n_real_glues: Cell::new(0u),
n_monos: Cell::new(0u), n_fns: Cell::new(0u),
n_inlines: Cell::new(0u), n_monos: Cell::new(0u),
n_closures: Cell::new(0u), n_inlines: Cell::new(0u),
n_llvm_insns: Cell::new(0u), n_closures: Cell::new(0u),
llvm_insns: RefCell::new(HashMap::new()), n_llvm_insns: Cell::new(0u),
fn_stats: RefCell::new(~[]), llvm_insns: RefCell::new(HashMap::new()),
}, fn_stats: RefCell::new(~[]),
tydesc_type: tydesc_type, },
int_type: int_type, tydesc_type: tydesc_type,
opaque_vec_type: opaque_vec_type, int_type: int_type,
builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), opaque_vec_type: opaque_vec_type,
crate_map: crate_map, builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
crate_map_name: crate_map_name, crate_map: crate_map,
uses_gc: false, crate_map_name: crate_map_name,
dbg_cx: dbg_cx, uses_gc: false,
do_not_commit_warning_issued: Cell::new(false), dbg_cx: dbg_cx,
do_not_commit_warning_issued: Cell::new(false),
} }
} }
} }

View File

@ -1779,7 +1779,7 @@ fn boxed_type_metadata(cx: &CrateContext,
offset: ComputedMemberOffset, offset: ComputedMemberOffset,
}, },
MemberDescription { MemberDescription {
name: ~"tydesc", name: ~"drop_glue",
llvm_type: member_llvm_types[1], llvm_type: member_llvm_types[1],
type_metadata: nil_pointer_type_metadata, type_metadata: nil_pointer_type_metadata,
offset: ComputedMemberOffset, offset: ComputedMemberOffset,
@ -1824,7 +1824,7 @@ fn boxed_type_metadata(cx: &CrateContext,
-> bool { -> bool {
member_llvm_types.len() == 5 && member_llvm_types.len() == 5 &&
member_llvm_types[0] == cx.int_type && member_llvm_types[0] == cx.int_type &&
member_llvm_types[1] == cx.tydesc_type.ptr_to() && member_llvm_types[1] == Type::generic_glue_fn(cx).ptr_to() &&
member_llvm_types[2] == Type::i8().ptr_to() && member_llvm_types[2] == Type::i8().ptr_to() &&
member_llvm_types[3] == Type::i8().ptr_to() && member_llvm_types[3] == Type::i8().ptr_to() &&
member_llvm_types[4] == content_llvm_type member_llvm_types[4] == content_llvm_type

View File

@ -73,14 +73,49 @@ pub fn take_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
} }
} }
pub fn drop_ty<'a>(cx: &'a Block<'a>, v: ValueRef, t: ty::t) fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
let tcx = ccx.tcx;
if !ty::type_needs_drop(tcx, t) {
return ty::mk_i8();
}
match ty::get(t).sty {
ty::ty_box(typ) if !ty::type_needs_drop(tcx, typ) =>
ty::mk_box(tcx, ty::mk_i8()),
ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) => {
let llty = sizing_type_of(ccx, typ);
// Unique boxes do not allocate for zero-size types. The standard library may assume
// that `free` is never called on the pointer returned for `~ZeroSizeType`.
if llsize_of_alloc(ccx, llty) == 0 {
ty::mk_i8()
} else {
ty::mk_uniq(tcx, ty::mk_i8())
}
}
ty::ty_vec(mt, ty::vstore_uniq) if !ty::type_needs_drop(tcx, mt.ty) =>
ty::mk_uniq(tcx, ty::mk_i8()),
_ => t
}
}
pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
-> &'a Block<'a> { -> &'a Block<'a> {
// NB: v is an *alias* of type t here, not a direct value. // NB: v is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("drop_ty"); let _icx = push_ctxt("drop_ty");
if ty::type_needs_drop(cx.tcx(), t) { let ccx = bcx.ccx();
return call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue); if ty::type_needs_drop(bcx.tcx(), t) {
let glue = get_drop_glue(ccx, t);
let glue_type = get_drop_glue_type(ccx, t);
let ptr = if glue_type != t {
PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to())
} else {
v
};
Call(bcx, glue, [ptr], []);
} }
return cx; bcx
} }
pub fn drop_ty_immediate<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) pub fn drop_ty_immediate<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
@ -91,95 +126,49 @@ pub fn drop_ty_immediate<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
drop_ty(bcx, vp, t) drop_ty(bcx, vp, t)
} }
pub fn lazily_emit_all_tydesc_glue(ccx: @CrateContext, pub fn get_drop_glue(ccx: @CrateContext, t: ty::t) -> ValueRef {
static_ti: @tydesc_info) { let t = get_drop_glue_type(ccx, t);
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti); {
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_visit_glue, static_ti); let drop_glues = ccx.drop_glues.borrow();
} match drop_glues.get().find(&t) {
Some(&glue) => return glue,
fn get_glue_type(ccx: &CrateContext, field: uint, t: ty::t) -> ty::t { _ => { }
let tcx = ccx.tcx;
if field == abi::tydesc_field_drop_glue {
if !ty::type_needs_drop(tcx, t) {
return ty::mk_i8();
}
match ty::get(t).sty {
ty::ty_box(typ) if !ty::type_needs_drop(tcx, typ) =>
return ty::mk_box(tcx, ty::mk_i8()),
ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) => {
let llty = sizing_type_of(ccx, typ);
// Unique boxes do not allocate for zero-size types. The standard library may assume
// that `free` is never called on the pointer returned for `~ZeroSizeType`.
if llsize_of_alloc(ccx, llty) == 0 {
return ty::mk_i8();
} else {
return ty::mk_uniq(tcx, ty::mk_i8());
}
}
ty::ty_vec(mt, ty::vstore_uniq) if !ty::type_needs_drop(tcx, mt.ty) =>
return ty::mk_uniq(tcx, ty::mk_i8()),
_ => {}
} }
} }
t let llfnty = Type::glue_fn(type_of(ccx, t).ptr_to());
let glue = declare_generic_glue(ccx, t, llfnty, "drop");
{
let mut drop_glues = ccx.drop_glues.borrow_mut();
drop_glues.get().insert(t, glue);
}
make_generic_glue(ccx, t, glue, make_drop_glue, "drop");
glue
} }
pub fn lazily_emit_tydesc_glue(ccx: @CrateContext, field: uint, ti: @tydesc_info) { pub fn lazily_emit_visit_glue(ccx: @CrateContext, ti: @tydesc_info) {
let _icx = push_ctxt("lazily_emit_tydesc_glue"); let _icx = push_ctxt("lazily_emit_visit_glue");
let simpl = get_glue_type(ccx, field, ti.ty);
if simpl != ti.ty {
let _icx = push_ctxt("lazily_emit_simplified_tydesc_glue");
let simpl_ti = get_tydesc(ccx, simpl);
lazily_emit_tydesc_glue(ccx, field, simpl_ti);
if field == abi::tydesc_field_drop_glue {
ti.drop_glue.set(simpl_ti.drop_glue.get());
} else if field == abi::tydesc_field_visit_glue {
ti.visit_glue.set(simpl_ti.visit_glue.get());
}
return;
}
let llfnty = Type::glue_fn(type_of(ccx, ti.ty).ptr_to()); let llfnty = Type::glue_fn(type_of(ccx, ti.ty).ptr_to());
if field == abi::tydesc_field_drop_glue { match ti.visit_glue.get() {
match ti.drop_glue.get() { Some(_) => (),
Some(_) => (), None => {
None => { debug!("+++ lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_str(ccx.tcx, ti.ty));
debug!("+++ lazily_emit_tydesc_glue DROP {}",
ppaux::ty_to_str(ccx.tcx, ti.ty));
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "drop");
ti.drop_glue.set(Some(glue_fn));
make_generic_glue(ccx, ti.ty, glue_fn, make_drop_glue, "drop");
debug!("--- lazily_emit_tydesc_glue DROP {}",
ppaux::ty_to_str(ccx.tcx, ti.ty));
}
}
} else if field == abi::tydesc_field_visit_glue {
match ti.visit_glue.get() {
Some(_) => (),
None => {
debug!("+++ lazily_emit_tydesc_glue VISIT {}",
ppaux::ty_to_str(ccx.tcx, ti.ty));
let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "visit"); let glue_fn = declare_generic_glue(ccx, ti.ty, llfnty, "visit");
ti.visit_glue.set(Some(glue_fn)); ti.visit_glue.set(Some(glue_fn));
make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit"); make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit");
debug!("--- lazily_emit_tydesc_glue VISIT {}", debug!("--- lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_str(ccx.tcx, ti.ty));
ppaux::ty_to_str(ccx.tcx, ti.ty));
}
} }
} }
} }
// See [Note-arg-mode] // See [Note-arg-mode]
pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef, pub fn call_visit_glue(bcx: &Block, v: ValueRef, tydesc: ValueRef,
field: uint, static_ti: Option<@tydesc_info>) { static_ti: Option<@tydesc_info>) {
let _icx = push_ctxt("call_tydesc_glue_full"); let _icx = push_ctxt("call_tydesc_glue_full");
let ccx = bcx.ccx(); let ccx = bcx.ccx();
// NB: Don't short-circuit even if this block is unreachable because // NB: Don't short-circuit even if this block is unreachable because
@ -189,37 +178,23 @@ pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef,
let static_glue_fn = match static_ti { let static_glue_fn = match static_ti {
None => None, None => None,
Some(sti) => { Some(sti) => {
lazily_emit_tydesc_glue(ccx, field, sti); lazily_emit_visit_glue(ccx, sti);
if field == abi::tydesc_field_drop_glue { sti.visit_glue.get()
sti.drop_glue.get()
} else if field == abi::tydesc_field_visit_glue {
sti.visit_glue.get()
} else {
None
}
} }
}; };
// When static type info is available, avoid casting parameter unless the // When static type info is available, avoid casting to a generic pointer.
// glue is using a simplified type, because the function already has the
// right type. Otherwise cast to generic pointer.
let llrawptr = if static_glue_fn.is_none() { let llrawptr = if static_glue_fn.is_none() {
PointerCast(bcx, v, Type::i8p()) PointerCast(bcx, v, Type::i8p())
} else { } else {
let ty = static_ti.unwrap().ty; v
let simpl = get_glue_type(ccx, field, ty);
if simpl != ty {
PointerCast(bcx, v, type_of(ccx, simpl).ptr_to())
} else {
v
}
}; };
let llfn = { let llfn = {
match static_glue_fn { match static_glue_fn {
None => { None => {
// Select out the glue function to call from the tydesc // Select out the glue function to call from the tydesc
let llfnptr = GEPi(bcx, tydesc, [0u, field]); let llfnptr = GEPi(bcx, tydesc, [0u, abi::tydesc_field_visit_glue]);
Load(bcx, llfnptr) Load(bcx, llfnptr)
} }
Some(sgf) => sgf Some(sgf) => sgf
@ -229,15 +204,6 @@ pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef,
Call(bcx, llfn, [llrawptr], []); Call(bcx, llfn, [llrawptr], []);
} }
// See [Note-arg-mode]
fn call_tydesc_glue<'a>(cx: &'a Block<'a>, v: ValueRef, t: ty::t, field: uint)
-> &'a Block<'a> {
let _icx = push_ctxt("call_tydesc_glue");
let ti = get_tydesc(cx.ccx(), t);
call_tydesc_glue_full(cx, v, ti.tydesc, field, Some(ti));
cx
}
fn make_visit_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) fn make_visit_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
-> &'a Block<'a> { -> &'a Block<'a> {
let _icx = push_ctxt("make_visit_glue"); let _icx = push_ctxt("make_visit_glue");
@ -355,9 +321,9 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]); let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
// Only drop the value when it is non-null // Only drop the value when it is non-null
with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| { with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| {
let lldtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable])); let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
let lldtor = Load(bcx, lldtor_ptr); let dtor = Load(bcx, dtor_ptr);
Call(bcx, lldtor, [PointerCast(bcx, lluniquevalue, Type::i8p())], []); Call(bcx, dtor, [PointerCast(bcx, lluniquevalue, Type::i8p())], []);
bcx bcx
}) })
} }
@ -367,18 +333,12 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
let env_ptr_ty = Type::at_box(ccx, Type::i8()).ptr_to(); let env_ptr_ty = Type::at_box(ccx, Type::i8()).ptr_to();
let env = PointerCast(bcx, env, env_ptr_ty); let env = PointerCast(bcx, env, env_ptr_ty);
with_cond(bcx, IsNotNull(bcx, env), |bcx| { with_cond(bcx, IsNotNull(bcx, env), |bcx| {
// Load the type descr found in the env let dtor_ptr = GEPi(bcx, env, [0u, abi::box_field_tydesc]);
let lltydescty = ccx.tydesc_type.ptr_to(); let dtor = Load(bcx, dtor_ptr);
let tydescptr = GEPi(bcx, env, [0u, abi::box_field_tydesc]);
let tydesc = Load(bcx, tydescptr);
let tydesc = PointerCast(bcx, tydesc, lltydescty);
// Drop the tuple data then free the descriptor
let cdata = GEPi(bcx, env, [0u, abi::box_field_body]); let cdata = GEPi(bcx, env, [0u, abi::box_field_body]);
call_tydesc_glue_full(bcx, cdata, tydesc, Call(bcx, dtor, [PointerCast(bcx, cdata, Type::i8p())], []);
abi::tydesc_field_drop_glue, None);
// Free the ty descr (if necc) and the env itself // Free the environment itself
trans_exchange_free(bcx, env) trans_exchange_free(bcx, env)
}) })
} }
@ -468,7 +428,6 @@ pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> @tydesc_info {
size: llsize, size: llsize,
align: llalign, align: llalign,
name: ty_name, name: ty_name,
drop_glue: Cell::new(None),
visit_glue: Cell::new(None), visit_glue: Cell::new(None),
}; };
debug!("--- declare_tydesc {}", ppaux::ty_to_str(ccx.tcx, t)); debug!("--- declare_tydesc {}", ppaux::ty_to_str(ccx.tcx, t));
@ -520,7 +479,7 @@ fn make_generic_glue(ccx: @CrateContext,
llfn llfn
} }
pub fn emit_tydescs(ccx: &CrateContext) { pub fn emit_tydescs(ccx: @CrateContext) {
let _icx = push_ctxt("emit_tydescs"); let _icx = push_ctxt("emit_tydescs");
// As of this point, allow no more tydescs to be created. // As of this point, allow no more tydescs to be created.
ccx.finished_tydescs.set(true); ccx.finished_tydescs.set(true);
@ -533,21 +492,10 @@ pub fn emit_tydescs(ccx: &CrateContext) {
// before being put into the tydesc because we only have a singleton // before being put into the tydesc because we only have a singleton
// tydesc type. Then we'll recast each function to its real type when // tydesc type. Then we'll recast each function to its real type when
// calling it. // calling it.
let drop_glue = let drop_glue = unsafe {
match ti.drop_glue.get() { llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref())
None => { };
ccx.stats.n_null_glues.set(ccx.stats.n_null_glues.get() + ccx.stats.n_real_glues.set(ccx.stats.n_real_glues.get() + 1);
1u);
C_null(glue_fn_ty)
}
Some(v) => {
unsafe {
ccx.stats.n_real_glues.set(ccx.stats.n_real_glues.get() +
1);
llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
}
}
};
let visit_glue = let visit_glue =
match ti.visit_glue.get() { match ti.visit_glue.get() {
None => { None => {

View File

@ -11,7 +11,6 @@
#[allow(non_uppercase_pattern_statics)]; #[allow(non_uppercase_pattern_statics)];
use arena::TypedArena; use arena::TypedArena;
use back::abi;
use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg}; use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg};
use lib::llvm::{ValueRef, Pointer, Array, Struct}; use lib::llvm::{ValueRef, Pointer, Array, Struct};
use lib; use lib;
@ -326,7 +325,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
"get_tydesc" => { "get_tydesc" => {
let tp_ty = substs.tys[0]; let tp_ty = substs.tys[0];
let static_ti = get_tydesc(ccx, tp_ty); let static_ti = get_tydesc(ccx, tp_ty);
glue::lazily_emit_all_tydesc_glue(ccx, static_ti); glue::lazily_emit_visit_glue(ccx, static_ti);
// FIXME (#3730): ideally this shouldn't need a cast, // FIXME (#3730): ideally this shouldn't need a cast,
// but there's a circularity between translating rust types to llvm // but there's a circularity between translating rust types to llvm
@ -459,8 +458,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
let td = get_param(decl, first_real_arg); let td = get_param(decl, first_real_arg);
let visitor = get_param(decl, first_real_arg + 1u); let visitor = get_param(decl, first_real_arg + 1u);
let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to()); let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to());
glue::call_tydesc_glue_full(bcx, visitor, td, glue::call_visit_glue(bcx, visitor, td, None);
abi::tydesc_field_visit_glue, None);
RetVoid(bcx); RetVoid(bcx);
} }
"morestack_addr" => { "morestack_addr" => {

View File

@ -479,11 +479,9 @@ pub fn get_vtable(bcx: &Block,
} }
}); });
// Generate a type descriptor for the vtable. // Generate a destructor for the vtable.
let tydesc = get_tydesc(ccx, self_ty); let drop_glue = glue::get_drop_glue(ccx, self_ty);
glue::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, tydesc); let vtable = make_vtable(ccx, drop_glue, methods);
let vtable = make_vtable(ccx, tydesc, methods);
let mut vtables = ccx.vtables.borrow_mut(); let mut vtables = ccx.vtables.borrow_mut();
vtables.get().insert(hash_id, vtable); vtables.get().insert(hash_id, vtable);
@ -492,13 +490,13 @@ pub fn get_vtable(bcx: &Block,
/// Helper function to declare and initialize the vtable. /// Helper function to declare and initialize the vtable.
pub fn make_vtable(ccx: &CrateContext, pub fn make_vtable(ccx: &CrateContext,
tydesc: &tydesc_info, drop_glue: ValueRef,
ptrs: &[ValueRef]) ptrs: &[ValueRef])
-> ValueRef { -> ValueRef {
unsafe { unsafe {
let _icx = push_ctxt("meth::make_vtable"); let _icx = push_ctxt("meth::make_vtable");
let mut components = ~[tydesc.drop_glue.get().unwrap()]; let mut components = ~[drop_glue];
for &ptr in ptrs.iter() { for &ptr in ptrs.iter() {
components.push(ptr) components.push(ptr)
} }

View File

@ -81,7 +81,7 @@ impl<'a> Reflector<'a> {
pub fn c_tydesc(&mut self, t: ty::t) -> ValueRef { pub fn c_tydesc(&mut self, t: ty::t) -> ValueRef {
let bcx = self.bcx; let bcx = self.bcx;
let static_ti = get_tydesc(bcx.ccx(), t); let static_ti = get_tydesc(bcx.ccx(), t);
glue::lazily_emit_all_tydesc_glue(bcx.ccx(), static_ti); glue::lazily_emit_visit_glue(bcx.ccx(), static_ti);
PointerCast(bcx, static_ti.tydesc, self.tydesc_ty.ptr_to()) PointerCast(bcx, static_ti.tydesc, self.tydesc_ty.ptr_to())
} }

View File

@ -238,7 +238,7 @@ impl Type {
// The box pointed to by @T. // The box pointed to by @T.
pub fn at_box(ctx: &CrateContext, ty: Type) -> Type { pub fn at_box(ctx: &CrateContext, ty: Type) -> Type {
Type::struct_([ Type::struct_([
ctx.int_type, ctx.tydesc_type.ptr_to(), ctx.int_type, Type::glue_fn(Type::i8p()).ptr_to(),
Type::i8p(), Type::i8p(), ty Type::i8p(), Type::i8p(), ty
], false) ], false)
} }

View File

@ -11,11 +11,8 @@
#[doc(hidden)]; #[doc(hidden)];
use ptr; use ptr;
use unstable::intrinsics::TyDesc;
use unstable::raw; use unstable::raw;
type DropGlue<'a> = 'a |**TyDesc, *u8|;
static RC_IMMORTAL : uint = 0x77777777; static RC_IMMORTAL : uint = 0x77777777;
/* /*
@ -24,11 +21,6 @@ static RC_IMMORTAL : uint = 0x77777777;
* This runs at task death to free all boxes. * This runs at task death to free all boxes.
*/ */
struct AnnihilateStats {
n_total_boxes: uint,
n_bytes_freed: uint
}
unsafe fn each_live_alloc(read_next_before: bool, unsafe fn each_live_alloc(read_next_before: bool,
f: |alloc: *mut raw::Box<()>| -> bool) f: |alloc: *mut raw::Box<()>| -> bool)
-> bool { -> bool {
@ -65,21 +57,18 @@ fn debug_mem() -> bool {
} }
/// Destroys all managed memory (i.e. @ boxes) held by the current task. /// Destroys all managed memory (i.e. @ boxes) held by the current task.
#[cfg(stage0)]
pub unsafe fn annihilate() { pub unsafe fn annihilate() {
use rt::local_heap::local_free; use rt::local_heap::local_free;
use mem;
let mut stats = AnnihilateStats { let mut n_total_boxes = 0u;
n_total_boxes: 0,
n_bytes_freed: 0
};
// Pass 1: Make all boxes immortal. // Pass 1: Make all boxes immortal.
// //
// In this pass, nothing gets freed, so it does not matter whether // In this pass, nothing gets freed, so it does not matter whether
// we read the next field before or after the callback. // we read the next field before or after the callback.
each_live_alloc(true, |alloc| { each_live_alloc(true, |alloc| {
stats.n_total_boxes += 1; n_total_boxes += 1;
(*alloc).ref_count = RC_IMMORTAL; (*alloc).ref_count = RC_IMMORTAL;
true true
}); });
@ -103,18 +92,58 @@ pub unsafe fn annihilate() {
// left), so we must read the `next` field before, since it will // left), so we must read the `next` field before, since it will
// not be valid after. // not be valid after.
each_live_alloc(true, |alloc| { each_live_alloc(true, |alloc| {
stats.n_bytes_freed +=
(*((*alloc).type_desc)).size
+ mem::size_of::<raw::Box<()>>();
local_free(alloc as *u8); local_free(alloc as *u8);
true true
}); });
if debug_mem() { if debug_mem() {
// We do logging here w/o allocation. // We do logging here w/o allocation.
debug!("annihilator stats:\n \ debug!("total boxes annihilated: {}", n_total_boxes);
total boxes: {}\n \ }
bytes freed: {}", }
stats.n_total_boxes, stats.n_bytes_freed);
/// Destroys all managed memory (i.e. @ boxes) held by the current task.
#[cfg(not(stage0))]
pub unsafe fn annihilate() {
use rt::local_heap::local_free;
let mut n_total_boxes = 0u;
// Pass 1: Make all boxes immortal.
//
// In this pass, nothing gets freed, so it does not matter whether
// we read the next field before or after the callback.
each_live_alloc(true, |alloc| {
n_total_boxes += 1;
(*alloc).ref_count = RC_IMMORTAL;
true
});
// Pass 2: Drop all boxes.
//
// In this pass, unique-managed boxes may get freed, but not
// managed boxes, so we must read the `next` field *after* the
// callback, as the original value may have been freed.
each_live_alloc(false, |alloc| {
let drop_glue = (*alloc).drop_glue;
let data = &mut (*alloc).data as *mut ();
drop_glue(data as *mut u8);
true
});
// Pass 3: Free all boxes.
//
// In this pass, managed boxes may get freed (but not
// unique-managed boxes, though I think that none of those are
// left), so we must read the `next` field before, since it will
// not be valid after.
each_live_alloc(true, |alloc| {
local_free(alloc as *u8);
true
});
if debug_mem() {
// We do logging here w/o allocation.
debug!("total boxes annihilated: {}", n_total_boxes);
} }
} }

View File

@ -10,6 +10,8 @@
//! Runtime environment settings //! Runtime environment settings
// NOTE: remove `POISON_ON_FREE` after a snapshot
use from_str::from_str; use from_str::from_str;
use option::{Some, None}; use option::{Some, None};
use os; use os;

View File

@ -10,7 +10,9 @@
use libc::{c_void, size_t, free, malloc, realloc}; use libc::{c_void, size_t, free, malloc, realloc};
use ptr::{RawPtr, mut_null}; use ptr::{RawPtr, mut_null};
use unstable::intrinsics::{TyDesc, abort}; #[cfg(stage0)]
use unstable::intrinsics::TyDesc;
use unstable::intrinsics::abort;
use unstable::raw; use unstable::raw;
use mem::size_of; use mem::size_of;
@ -73,14 +75,23 @@ pub unsafe fn exchange_malloc(size: uint) -> *u8 {
} }
// FIXME: #7496 // FIXME: #7496
#[cfg(not(test))] #[cfg(not(test), stage0)]
#[lang="closure_exchange_malloc"] #[lang="closure_exchange_malloc"]
#[inline] #[inline]
pub unsafe fn closure_exchange_malloc_(td: *u8, size: uint) -> *u8 { pub unsafe fn closure_exchange_malloc_(td: *u8, size: uint) -> *u8 {
closure_exchange_malloc(td, size) closure_exchange_malloc(td, size)
} }
// FIXME: #7496
#[cfg(not(test), not(stage0))]
#[lang="closure_exchange_malloc"]
#[inline] #[inline]
pub unsafe fn closure_exchange_malloc_(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
closure_exchange_malloc(drop_glue, size, align)
}
#[inline]
#[cfg(stage0)]
pub unsafe fn closure_exchange_malloc(td: *u8, size: uint) -> *u8 { pub unsafe fn closure_exchange_malloc(td: *u8, size: uint) -> *u8 {
let td = td as *TyDesc; let td = td as *TyDesc;
let size = size; let size = size;
@ -96,6 +107,18 @@ pub unsafe fn closure_exchange_malloc(td: *u8, size: uint) -> *u8 {
alloc as *u8 alloc as *u8
} }
#[inline]
#[cfg(not(stage0))]
pub unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
let total_size = get_box_size(size, align);
let p = malloc_raw(total_size);
let alloc = p as *mut raw::Box<()>;
(*alloc).drop_glue = drop_glue;
alloc as *u8
}
// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
// inside a landing pad may corrupt the state of the exception handler. // inside a landing pad may corrupt the state of the exception handler.
#[cfg(not(test))] #[cfg(not(test))]

View File

@ -21,6 +21,7 @@ use rt::env;
use rt::global_heap; use rt::global_heap;
use rt::local::Local; use rt::local::Local;
use rt::task::Task; use rt::task::Task;
#[cfg(stage0)]
use unstable::intrinsics::TyDesc; use unstable::intrinsics::TyDesc;
use unstable::raw; use unstable::raw;
use vec::ImmutableVector; use vec::ImmutableVector;
@ -60,6 +61,7 @@ impl LocalHeap {
} }
#[inline] #[inline]
#[cfg(stage0)]
pub fn alloc(&mut self, td: *TyDesc, size: uint) -> *mut Box { pub fn alloc(&mut self, td: *TyDesc, size: uint) -> *mut Box {
let total_size = global_heap::get_box_size(size, unsafe { (*td).align }); let total_size = global_heap::get_box_size(size, unsafe { (*td).align });
let alloc = self.memory_region.malloc(total_size); let alloc = self.memory_region.malloc(total_size);
@ -80,6 +82,28 @@ impl LocalHeap {
return alloc; return alloc;
} }
#[inline]
#[cfg(not(stage0))]
pub fn alloc(&mut self, drop_glue: fn(*mut u8), size: uint, align: uint) -> *mut Box {
let total_size = global_heap::get_box_size(size, align);
let alloc = self.memory_region.malloc(total_size);
{
// Make sure that we can't use `mybox` outside of this scope
let mybox: &mut Box = unsafe { cast::transmute(alloc) };
// Clear out this box, and move it to the front of the live
// allocations list
mybox.drop_glue = drop_glue;
mybox.ref_count = 1;
mybox.prev = ptr::mut_null();
mybox.next = self.live_allocs;
if !self.live_allocs.is_null() {
unsafe { (*self.live_allocs).prev = alloc; }
}
self.live_allocs = alloc;
}
return alloc;
}
#[inline] #[inline]
pub fn realloc(&mut self, ptr: *mut Box, size: uint) -> *mut Box { pub fn realloc(&mut self, ptr: *mut Box, size: uint) -> *mut Box {
// Make sure that we can't use `mybox` outside of this scope // Make sure that we can't use `mybox` outside of this scope
@ -102,6 +126,7 @@ impl LocalHeap {
} }
#[inline] #[inline]
#[cfg(stage0)]
pub fn free(&mut self, alloc: *mut Box) { pub fn free(&mut self, alloc: *mut Box) {
{ {
// Make sure that we can't use `mybox` outside of this scope // Make sure that we can't use `mybox` outside of this scope
@ -133,6 +158,28 @@ impl LocalHeap {
self.memory_region.free(alloc); self.memory_region.free(alloc);
} }
#[inline]
#[cfg(not(stage0))]
pub fn free(&mut self, alloc: *mut Box) {
{
// Make sure that we can't use `mybox` outside of this scope
let mybox: &mut Box = unsafe { cast::transmute(alloc) };
// Unlink it from the linked list
if !mybox.prev.is_null() {
unsafe { (*mybox.prev).next = mybox.next; }
}
if !mybox.next.is_null() {
unsafe { (*mybox.next).prev = mybox.prev; }
}
if self.live_allocs == alloc {
self.live_allocs = mybox.next;
}
}
self.memory_region.free(alloc);
}
} }
impl Drop for LocalHeap { impl Drop for LocalHeap {
@ -292,6 +339,7 @@ impl Drop for MemoryRegion {
} }
#[inline] #[inline]
#[cfg(stage0)]
pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 { pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 {
// FIXME: Unsafe borrow for speed. Lame. // FIXME: Unsafe borrow for speed. Lame.
let task: Option<*mut Task> = Local::try_unsafe_borrow(); let task: Option<*mut Task> = Local::try_unsafe_borrow();
@ -303,6 +351,19 @@ pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 {
} }
} }
#[inline]
#[cfg(not(stage0))]
pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
// FIXME: Unsafe borrow for speed. Lame.
let task: Option<*mut Task> = Local::try_unsafe_borrow();
match task {
Some(task) => {
(*task).heap.alloc(drop_glue, size, align) as *u8
}
None => rtabort!("local malloc outside of task")
}
}
// A little compatibility function // A little compatibility function
#[inline] #[inline]
pub unsafe fn local_free(ptr: *u8) { pub unsafe fn local_free(ptr: *u8) {

View File

@ -27,11 +27,19 @@ pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
} }
#[lang="malloc"] #[lang="malloc"]
#[cfg(stage0)]
#[inline] #[inline]
pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 { pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 {
::rt::local_heap::local_malloc(td, size) ::rt::local_heap::local_malloc(td, size)
} }
#[lang="malloc"]
#[cfg(not(stage0))]
#[inline]
pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
::rt::local_heap::local_malloc(drop_glue, size, align)
}
// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
// inside a landing pad may corrupt the state of the exception handler. If a // inside a landing pad may corrupt the state of the exception handler. If a
// problem occurs, call exit instead. // problem occurs, call exit instead.

View File

@ -9,9 +9,11 @@
// except according to those terms. // except according to those terms.
use cast; use cast;
#[cfg(stage0)]
use unstable::intrinsics::TyDesc; use unstable::intrinsics::TyDesc;
/// The representation of a Rust managed box /// The representation of a Rust managed box
#[cfg(stage0)]
pub struct Box<T> { pub struct Box<T> {
ref_count: uint, ref_count: uint,
type_desc: *TyDesc, type_desc: *TyDesc,
@ -20,6 +22,16 @@ pub struct Box<T> {
data: T data: T
} }
/// The representation of a Rust managed box
#[cfg(not(stage0))]
pub struct Box<T> {
ref_count: uint,
drop_glue: fn(ptr: *mut u8),
prev: *mut Box<T>,
next: *mut Box<T>,
data: T
}
/// The representation of a Rust vector /// The representation of a Rust vector
pub struct Vec<T> { pub struct Vec<T> {
fill: uint, fill: uint,
@ -59,9 +71,6 @@ impl<T> Repr<*Box<T>> for @T {}
impl<T> Repr<*Vec<T>> for ~[T] {} impl<T> Repr<*Vec<T>> for ~[T] {}
impl Repr<*String> for ~str {} impl Repr<*String> for ~str {}
// sure would be nice to have this
// impl<T> Repr<*Vec<T>> for ~[T] {}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -45,7 +45,7 @@
// debugger:whatis f64 // debugger:whatis f64
// check:type = f64 // check:type = f64
// debugger:info functions _yyy // debugger:info functions _yyy
// check:[...]![...]_yyy()(); // check:[...]![...]_yyy([...])([...]);
// debugger:detach // debugger:detach
// debugger:quit // debugger:quit