mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-21 04:03:11 +00:00
auto merge of #12059 : thestinger/rust/glue, r=pcwalton
A follow-up from the work I started with 383e3fd13b
.
This commit is contained in:
commit
80c6c73647
@ -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
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 => {
|
||||||
|
@ -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" => {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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))]
|
||||||
|
@ -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) {
|
||||||
|
@ -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.
|
||||||
|
@ -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::*;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user