From 940d1ae2f3b1cba8cfd858ab3a54d6408b53b033 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 5 Feb 2014 23:05:30 -0500 Subject: [PATCH 1/4] remove type descriptors from proc and @T This also drops support for the managed pointer POISON_ON_FREE feature as it's not worth adding back the support for it. After a snapshot, the leftovers can be removed. --- src/librustc/middle/trans/base.rs | 6 +-- src/librustc/middle/trans/debuginfo.rs | 4 +- src/librustc/middle/trans/glue.rs | 20 +++----- src/librustc/middle/trans/type_.rs | 2 +- src/libstd/cleanup.rs | 71 ++++++++++++++++++-------- src/libstd/rt/env.rs | 2 + src/libstd/rt/global_heap.rs | 27 +++++++++- src/libstd/rt/local_heap.rs | 61 ++++++++++++++++++++++ src/libstd/unstable/lang.rs | 8 +++ src/libstd/unstable/raw.rs | 12 +++++ 10 files changed, 171 insertions(+), 42 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 485daf3d387f..d877a468cf09 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -352,7 +352,6 @@ pub fn malloc_raw_dyn<'a>( if heap == heap_exchange { let llty_value = type_of::type_of(ccx, t); - // Allocate space: let r = callee::trans_lang_call( bcx, @@ -375,17 +374,18 @@ pub fn malloc_raw_dyn<'a>( // Grab the TypeRef type of box_ptr_ty. let box_ptr_ty = ty::mk_box(bcx.tcx(), t); 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: - let tydesc = PointerCast(bcx, static_ti.tydesc, Type::i8p()); + let drop_glue = static_ti.drop_glue.get().unwrap(); let r = callee::trans_lang_call( bcx, langcall, - [tydesc, size], + [PointerCast(bcx, drop_glue, Type::glue_fn(Type::i8p()).ptr_to()), size, llalign], None); rslt(r.bcx, PointerCast(r.bcx, r.val, llty)) } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index ed233142238d..7bbbf4f99059 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -1779,7 +1779,7 @@ fn boxed_type_metadata(cx: &CrateContext, offset: ComputedMemberOffset, }, MemberDescription { - name: ~"tydesc", + name: ~"drop_glue", llvm_type: member_llvm_types[1], type_metadata: nil_pointer_type_metadata, offset: ComputedMemberOffset, @@ -1824,7 +1824,7 @@ fn boxed_type_metadata(cx: &CrateContext, -> bool { member_llvm_types.len() == 5 && 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[3] == Type::i8().ptr_to() && member_llvm_types[4] == content_llvm_type diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index abf77b4b5fa9..c1fb1fc1589e 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -355,9 +355,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]); // Only drop the value when it is non-null with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| { - let lldtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable])); - let lldtor = Load(bcx, lldtor_ptr); - Call(bcx, lldtor, [PointerCast(bcx, lluniquevalue, Type::i8p())], []); + let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable])); + let dtor = Load(bcx, dtor_ptr); + Call(bcx, dtor, [PointerCast(bcx, lluniquevalue, Type::i8p())], []); bcx }) } @@ -367,18 +367,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 = PointerCast(bcx, env, env_ptr_ty); with_cond(bcx, IsNotNull(bcx, env), |bcx| { - // Load the type descr found in the env - let lltydescty = ccx.tydesc_type.ptr_to(); - 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 dtor_ptr = GEPi(bcx, env, [0u, abi::box_field_tydesc]); + let dtor = Load(bcx, dtor_ptr); let cdata = GEPi(bcx, env, [0u, abi::box_field_body]); - call_tydesc_glue_full(bcx, cdata, tydesc, - abi::tydesc_field_drop_glue, None); + Call(bcx, dtor, [PointerCast(bcx, cdata, Type::i8p())], []); - // Free the ty descr (if necc) and the env itself + // Free the environment itself trans_exchange_free(bcx, env) }) } diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index 8eccbf8d956a..804486c41597 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -238,7 +238,7 @@ impl Type { // The box pointed to by @T. pub fn at_box(ctx: &CrateContext, ty: Type) -> Type { 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 ], false) } diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs index 82c1ed7440c5..a43dca949703 100644 --- a/src/libstd/cleanup.rs +++ b/src/libstd/cleanup.rs @@ -11,11 +11,8 @@ #[doc(hidden)]; use ptr; -use unstable::intrinsics::TyDesc; use unstable::raw; -type DropGlue<'a> = 'a |**TyDesc, *u8|; - static RC_IMMORTAL : uint = 0x77777777; /* @@ -24,11 +21,6 @@ static RC_IMMORTAL : uint = 0x77777777; * 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, f: |alloc: *mut raw::Box<()>| -> bool) -> bool { @@ -65,21 +57,18 @@ fn debug_mem() -> bool { } /// Destroys all managed memory (i.e. @ boxes) held by the current task. +#[cfg(stage0)] pub unsafe fn annihilate() { use rt::local_heap::local_free; - use mem; - let mut stats = AnnihilateStats { - n_total_boxes: 0, - n_bytes_freed: 0 - }; + 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| { - stats.n_total_boxes += 1; + n_total_boxes += 1; (*alloc).ref_count = RC_IMMORTAL; true }); @@ -103,18 +92,58 @@ pub unsafe fn annihilate() { // left), so we must read the `next` field before, since it will // not be valid after. each_live_alloc(true, |alloc| { - stats.n_bytes_freed += - (*((*alloc).type_desc)).size - + mem::size_of::>(); local_free(alloc as *u8); true }); if debug_mem() { // We do logging here w/o allocation. - debug!("annihilator stats:\n \ - total boxes: {}\n \ - bytes freed: {}", - stats.n_total_boxes, stats.n_bytes_freed); + debug!("total boxes annihilated: {}", n_total_boxes); + } +} + +/// 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); } } diff --git a/src/libstd/rt/env.rs b/src/libstd/rt/env.rs index 729e377e1af3..571ed77592fc 100644 --- a/src/libstd/rt/env.rs +++ b/src/libstd/rt/env.rs @@ -10,6 +10,8 @@ //! Runtime environment settings +// NOTE: remove `POISON_ON_FREE` after a snapshot + use from_str::from_str; use option::{Some, None}; use os; diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 6bee8cb70f56..2f553585f38c 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -10,7 +10,9 @@ use libc::{c_void, size_t, free, malloc, realloc}; use ptr::{RawPtr, mut_null}; -use unstable::intrinsics::{TyDesc, abort}; +#[cfg(stage0)] +use unstable::intrinsics::TyDesc; +use unstable::intrinsics::abort; use unstable::raw; use mem::size_of; @@ -73,14 +75,23 @@ pub unsafe fn exchange_malloc(size: uint) -> *u8 { } // FIXME: #7496 -#[cfg(not(test))] +#[cfg(not(test), stage0)] #[lang="closure_exchange_malloc"] #[inline] pub unsafe fn closure_exchange_malloc_(td: *u8, size: uint) -> *u8 { closure_exchange_malloc(td, size) } +// FIXME: #7496 +#[cfg(not(test), not(stage0))] +#[lang="closure_exchange_malloc"] #[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 { let td = td as *TyDesc; let size = size; @@ -96,6 +107,18 @@ pub unsafe fn closure_exchange_malloc(td: *u8, size: uint) -> *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 // inside a landing pad may corrupt the state of the exception handler. #[cfg(not(test))] diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs index 79936b4afad0..3bee9e48b602 100644 --- a/src/libstd/rt/local_heap.rs +++ b/src/libstd/rt/local_heap.rs @@ -21,6 +21,7 @@ use rt::env; use rt::global_heap; use rt::local::Local; use rt::task::Task; +#[cfg(stage0)] use unstable::intrinsics::TyDesc; use unstable::raw; use vec::ImmutableVector; @@ -60,6 +61,7 @@ impl LocalHeap { } #[inline] + #[cfg(stage0)] pub fn alloc(&mut self, td: *TyDesc, size: uint) -> *mut Box { let total_size = global_heap::get_box_size(size, unsafe { (*td).align }); let alloc = self.memory_region.malloc(total_size); @@ -80,6 +82,28 @@ impl LocalHeap { 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] pub fn realloc(&mut self, ptr: *mut Box, size: uint) -> *mut Box { // Make sure that we can't use `mybox` outside of this scope @@ -102,6 +126,7 @@ impl LocalHeap { } #[inline] + #[cfg(stage0)] pub fn free(&mut self, alloc: *mut Box) { { // Make sure that we can't use `mybox` outside of this scope @@ -133,6 +158,28 @@ impl LocalHeap { 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 { @@ -292,6 +339,7 @@ impl Drop for MemoryRegion { } #[inline] +#[cfg(stage0)] pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 { // FIXME: Unsafe borrow for speed. Lame. 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 #[inline] pub unsafe fn local_free(ptr: *u8) { diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index 046d3fc820dd..a85f26720bf1 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -27,11 +27,19 @@ pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! { } #[lang="malloc"] +#[cfg(stage0)] #[inline] pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 { ::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 // inside a landing pad may corrupt the state of the exception handler. If a // problem occurs, call exit instead. diff --git a/src/libstd/unstable/raw.rs b/src/libstd/unstable/raw.rs index 63208b3f2d70..8f5f8ea806f9 100644 --- a/src/libstd/unstable/raw.rs +++ b/src/libstd/unstable/raw.rs @@ -9,9 +9,11 @@ // except according to those terms. use cast; +#[cfg(stage0)] use unstable::intrinsics::TyDesc; /// The representation of a Rust managed box +#[cfg(stage0)] pub struct Box { ref_count: uint, type_desc: *TyDesc, @@ -20,6 +22,16 @@ pub struct Box { data: T } +/// The representation of a Rust managed box +#[cfg(not(stage0))] +pub struct Box { + ref_count: uint, + drop_glue: fn(ptr: *mut u8), + prev: *mut Box, + next: *mut Box, + data: T +} + /// The representation of a Rust vector pub struct Vec { fill: uint, From eced501226bf8dc9f6d0a4cbe708da6166942fd9 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 6 Feb 2014 01:07:06 -0500 Subject: [PATCH 2/4] allow generating drop glue without the TyDesc Reflection is now the only user of type descriptors. Uses of drop glue no longer cause a type descriptor to be generated. --- src/libarena/lib.rs | 5 +- src/librustc/middle/trans/base.rs | 6 +- src/librustc/middle/trans/common.rs | 1 - src/librustc/middle/trans/context.rs | 260 +++++++++++++------------ src/librustc/middle/trans/glue.rs | 194 +++++++----------- src/librustc/middle/trans/intrinsic.rs | 6 +- src/librustc/middle/trans/meth.rs | 12 +- src/librustc/middle/trans/reflect.rs | 2 +- 8 files changed, 216 insertions(+), 270 deletions(-) diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index cd9b638a5c22..856540989df5 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -214,8 +214,7 @@ impl Arena { #[inline] fn alloc_pod<'a, T>(&'a mut self, op: || -> T) -> &'a T { unsafe { - let tydesc = get_tydesc::(); - let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align); + let ptr = self.alloc_pod_inner(mem::size_of::(), mem::min_align_of::()); let ptr: *mut T = transmute(ptr); intrinsics::move_val_init(&mut (*ptr), op()); return transmute(ptr); @@ -272,7 +271,7 @@ impl Arena { unsafe { let tydesc = get_tydesc::(); let (ty_ptr, ptr) = - self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align); + self.alloc_nonpod_inner(mem::size_of::(), mem::min_align_of::()); let ty_ptr: *mut uint = transmute(ty_ptr); let ptr: *mut T = transmute(ptr); // Write in our tydesc along with a bit indicating that it diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index d877a468cf09..39e0ca176eb0 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -376,12 +376,8 @@ pub fn malloc_raw_dyn<'a>( 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: - let drop_glue = static_ti.drop_glue.get().unwrap(); + let drop_glue = glue::get_drop_glue(ccx, t); let r = callee::trans_lang_call( bcx, langcall, diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 78affcc69e11..7ee77e4c0d6f 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -114,7 +114,6 @@ pub struct tydesc_info { size: ValueRef, align: ValueRef, name: ValueRef, - drop_glue: Cell>, visit_glue: Cell>, } diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 93d874cf83ee..95875a014018 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -36,83 +36,84 @@ use syntax::ast; use syntax::parse::token::InternedString; pub struct CrateContext { - sess: session::Session, - llmod: ModuleRef, - llcx: ContextRef, - metadata_llmod: ModuleRef, - td: TargetData, - tn: TypeNames, - externs: RefCell, - intrinsics: HashMap<&'static str, ValueRef>, - item_vals: RefCell>, - exp_map2: resolve::ExportMap2, - reachable: @RefCell>, - item_symbols: RefCell>, - link_meta: LinkMeta, - tydescs: RefCell>, - // Set when running emit_tydescs to enforce that no more tydescs are - // created. - finished_tydescs: Cell, - // Track mapping of external ids to local items imported for inlining - external: RefCell>>, - // Backwards version of the `external` map (inlined items to where they - // came from) - external_srcs: RefCell>, - // A set of static items which cannot be inlined into other crates. This - // will pevent in IIItem() structures from being encoded into the metadata - // that is generated - non_inlineable_statics: RefCell>, - // Cache instances of monomorphized functions - monomorphized: RefCell>, - monomorphizing: RefCell>, - // Cache generated vtables - vtables: RefCell>, - // Cache of constant strings, - const_cstr_cache: RefCell>, + sess: session::Session, + llmod: ModuleRef, + llcx: ContextRef, + metadata_llmod: ModuleRef, + td: TargetData, + tn: TypeNames, + externs: RefCell, + intrinsics: HashMap<&'static str, ValueRef>, + item_vals: RefCell>, + exp_map2: resolve::ExportMap2, + reachable: @RefCell>, + item_symbols: RefCell>, + link_meta: LinkMeta, + drop_glues: RefCell>, + tydescs: RefCell>, + // Set when running emit_tydescs to enforce that no more tydescs are + // created. + finished_tydescs: Cell, + // Track mapping of external ids to local items imported for inlining + external: RefCell>>, + // Backwards version of the `external` map (inlined items to where they + // came from) + external_srcs: RefCell>, + // A set of static items which cannot be inlined into other crates. This + // will pevent in IIItem() structures from being encoded into the metadata + // that is generated + non_inlineable_statics: RefCell>, + // Cache instances of monomorphized functions + monomorphized: RefCell>, + monomorphizing: RefCell>, + // Cache generated vtables + vtables: RefCell>, + // Cache of constant strings, + const_cstr_cache: RefCell>, - // Reverse-direction for const ptrs cast from globals. - // Key is an int, cast from a ValueRef holding a *T, - // Val is a ValueRef holding a *[T]. - // - // Needed because LLVM loses pointer->pointee association - // when we ptrcast, and we have to ptrcast during translation - // of a [T] const because we form a slice, a [*T,int] pair, not - // a pointer to an LLVM array type. - const_globals: RefCell>, + // Reverse-direction for const ptrs cast from globals. + // Key is an int, cast from a ValueRef holding a *T, + // Val is a ValueRef holding a *[T]. + // + // Needed because LLVM loses pointer->pointee association + // when we ptrcast, and we have to ptrcast during translation + // of a [T] const because we form a slice, a [*T,int] pair, not + // a pointer to an LLVM array type. + const_globals: RefCell>, - // Cache of emitted const values - const_values: RefCell>, + // Cache of emitted const values + const_values: RefCell>, - // Cache of external const values - extern_const_values: RefCell>, + // Cache of external const values + extern_const_values: RefCell>, - impl_method_cache: RefCell>, + impl_method_cache: RefCell>, - // Cache of closure wrappers for bare fn's. - closure_bare_wrapper_cache: RefCell>, + // Cache of closure wrappers for bare fn's. + closure_bare_wrapper_cache: RefCell>, - module_data: RefCell>, - lltypes: RefCell>, - llsizingtypes: RefCell>, - adt_reprs: RefCell>, - symbol_hasher: RefCell, - type_hashcodes: RefCell>, - all_llvm_symbols: RefCell>, - tcx: ty::ctxt, - maps: astencode::Maps, - stats: @Stats, - tydesc_type: Type, - int_type: Type, - opaque_vec_type: Type, - builder: BuilderRef_res, - crate_map: ValueRef, - crate_map_name: ~str, - // Set when at least one function uses GC. Needed so that - // 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. - uses_gc: bool, - dbg_cx: Option, - do_not_commit_warning_issued: Cell, + module_data: RefCell>, + lltypes: RefCell>, + llsizingtypes: RefCell>, + adt_reprs: RefCell>, + symbol_hasher: RefCell, + type_hashcodes: RefCell>, + all_llvm_symbols: RefCell>, + tcx: ty::ctxt, + maps: astencode::Maps, + stats: @Stats, + tydesc_type: Type, + int_type: Type, + opaque_vec_type: Type, + builder: BuilderRef_res, + crate_map: ValueRef, + crate_map_name: ~str, + // Set when at least one function uses GC. Needed so that + // 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. + uses_gc: bool, + dbg_cx: Option, + do_not_commit_warning_issued: Cell, } impl CrateContext { @@ -175,64 +176,65 @@ impl CrateContext { } CrateContext { - sess: sess, - llmod: llmod, - llcx: llcx, - metadata_llmod: metadata_llmod, - td: td, - tn: tn, - externs: RefCell::new(HashMap::new()), - intrinsics: intrinsics, - item_vals: RefCell::new(HashMap::new()), - exp_map2: emap2, - reachable: reachable, - item_symbols: RefCell::new(HashMap::new()), - link_meta: link_meta, - tydescs: RefCell::new(HashMap::new()), - finished_tydescs: Cell::new(false), - external: RefCell::new(HashMap::new()), - external_srcs: RefCell::new(HashMap::new()), - non_inlineable_statics: RefCell::new(HashSet::new()), - monomorphized: RefCell::new(HashMap::new()), - monomorphizing: RefCell::new(HashMap::new()), - vtables: RefCell::new(HashMap::new()), - const_cstr_cache: RefCell::new(HashMap::new()), - const_globals: RefCell::new(HashMap::new()), - const_values: RefCell::new(HashMap::new()), - extern_const_values: RefCell::new(HashMap::new()), - impl_method_cache: RefCell::new(HashMap::new()), - closure_bare_wrapper_cache: RefCell::new(HashMap::new()), - module_data: RefCell::new(HashMap::new()), - lltypes: RefCell::new(HashMap::new()), - llsizingtypes: RefCell::new(HashMap::new()), - adt_reprs: RefCell::new(HashMap::new()), - symbol_hasher: RefCell::new(symbol_hasher), - type_hashcodes: RefCell::new(HashMap::new()), - all_llvm_symbols: RefCell::new(HashSet::new()), - tcx: tcx, - maps: maps, - stats: @Stats { - n_static_tydescs: Cell::new(0u), - n_glues_created: Cell::new(0u), - n_null_glues: Cell::new(0u), - n_real_glues: Cell::new(0u), - n_fns: Cell::new(0u), - n_monos: Cell::new(0u), - n_inlines: Cell::new(0u), - n_closures: Cell::new(0u), - n_llvm_insns: Cell::new(0u), - llvm_insns: RefCell::new(HashMap::new()), - fn_stats: RefCell::new(~[]), - }, - tydesc_type: tydesc_type, - int_type: int_type, - opaque_vec_type: opaque_vec_type, - builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), - crate_map: crate_map, - crate_map_name: crate_map_name, - uses_gc: false, - dbg_cx: dbg_cx, - do_not_commit_warning_issued: Cell::new(false), + sess: sess, + llmod: llmod, + llcx: llcx, + metadata_llmod: metadata_llmod, + td: td, + tn: tn, + externs: RefCell::new(HashMap::new()), + intrinsics: intrinsics, + item_vals: RefCell::new(HashMap::new()), + exp_map2: emap2, + reachable: reachable, + item_symbols: RefCell::new(HashMap::new()), + link_meta: link_meta, + drop_glues: RefCell::new(HashMap::new()), + tydescs: RefCell::new(HashMap::new()), + finished_tydescs: Cell::new(false), + external: RefCell::new(HashMap::new()), + external_srcs: RefCell::new(HashMap::new()), + non_inlineable_statics: RefCell::new(HashSet::new()), + monomorphized: RefCell::new(HashMap::new()), + monomorphizing: RefCell::new(HashMap::new()), + vtables: RefCell::new(HashMap::new()), + const_cstr_cache: RefCell::new(HashMap::new()), + const_globals: RefCell::new(HashMap::new()), + const_values: RefCell::new(HashMap::new()), + extern_const_values: RefCell::new(HashMap::new()), + impl_method_cache: RefCell::new(HashMap::new()), + closure_bare_wrapper_cache: RefCell::new(HashMap::new()), + module_data: RefCell::new(HashMap::new()), + lltypes: RefCell::new(HashMap::new()), + llsizingtypes: RefCell::new(HashMap::new()), + adt_reprs: RefCell::new(HashMap::new()), + symbol_hasher: RefCell::new(symbol_hasher), + type_hashcodes: RefCell::new(HashMap::new()), + all_llvm_symbols: RefCell::new(HashSet::new()), + tcx: tcx, + maps: maps, + stats: @Stats { + n_static_tydescs: Cell::new(0u), + n_glues_created: Cell::new(0u), + n_null_glues: Cell::new(0u), + n_real_glues: Cell::new(0u), + n_fns: Cell::new(0u), + n_monos: Cell::new(0u), + n_inlines: Cell::new(0u), + n_closures: Cell::new(0u), + n_llvm_insns: Cell::new(0u), + llvm_insns: RefCell::new(HashMap::new()), + fn_stats: RefCell::new(~[]), + }, + tydesc_type: tydesc_type, + int_type: int_type, + opaque_vec_type: opaque_vec_type, + builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), + crate_map: crate_map, + crate_map_name: crate_map_name, + uses_gc: false, + dbg_cx: dbg_cx, + do_not_commit_warning_issued: Cell::new(false), } } } diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index c1fb1fc1589e..1b9605a172cb 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -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> { // NB: v is an *alias* of type t here, not a direct value. let _icx = push_ctxt("drop_ty"); - if ty::type_needs_drop(cx.tcx(), t) { - return call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue); + let ccx = bcx.ccx(); + 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) @@ -91,95 +126,49 @@ pub fn drop_ty_immediate<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) drop_ty(bcx, vp, t) } -pub fn lazily_emit_all_tydesc_glue(ccx: @CrateContext, - static_ti: @tydesc_info) { - lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti); - lazily_emit_tydesc_glue(ccx, abi::tydesc_field_visit_glue, static_ti); -} - -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()), - - _ => {} +pub fn get_drop_glue(ccx: @CrateContext, t: ty::t) -> ValueRef { + let t = get_drop_glue_type(ccx, t); + { + let drop_glues = ccx.drop_glues.borrow(); + match drop_glues.get().find(&t) { + Some(&glue) => return glue, + _ => { } } } - t -} + let llfnty = Type::glue_fn(type_of(ccx, t).ptr_to()); + let glue = declare_generic_glue(ccx, t, llfnty, "drop"); -pub fn lazily_emit_tydesc_glue(ccx: @CrateContext, field: uint, ti: @tydesc_info) { - let _icx = push_ctxt("lazily_emit_tydesc_glue"); + { + let mut drop_glues = ccx.drop_glues.borrow_mut(); + drop_glues.get().insert(t, 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); + make_generic_glue(ccx, t, glue, make_drop_glue, "drop"); - 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()); - } + glue +} - return; - } +pub fn lazily_emit_visit_glue(ccx: @CrateContext, ti: @tydesc_info) { + let _icx = push_ctxt("lazily_emit_visit_glue"); let llfnty = Type::glue_fn(type_of(ccx, ti.ty).ptr_to()); - if field == abi::tydesc_field_drop_glue { - match ti.drop_glue.get() { - Some(_) => (), - None => { - 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)); + 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"); ti.visit_glue.set(Some(glue_fn)); make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit"); - debug!("--- lazily_emit_tydesc_glue VISIT {}", - ppaux::ty_to_str(ccx.tcx, ti.ty)); - } + debug!("--- lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_str(ccx.tcx, ti.ty)); } } } // See [Note-arg-mode] -pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef, - field: uint, static_ti: Option<@tydesc_info>) { +pub fn call_visit_glue(bcx: &Block, v: ValueRef, tydesc: ValueRef, + static_ti: Option<@tydesc_info>) { let _icx = push_ctxt("call_tydesc_glue_full"); let ccx = bcx.ccx(); // 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 { None => None, Some(sti) => { - lazily_emit_tydesc_glue(ccx, field, sti); - if field == abi::tydesc_field_drop_glue { - sti.drop_glue.get() - } else if field == abi::tydesc_field_visit_glue { - sti.visit_glue.get() - } else { - None - } + lazily_emit_visit_glue(ccx, sti); + sti.visit_glue.get() } }; - // When static type info is available, avoid casting parameter unless the - // glue is using a simplified type, because the function already has the - // right type. Otherwise cast to generic pointer. + // When static type info is available, avoid casting to a generic pointer. let llrawptr = if static_glue_fn.is_none() { PointerCast(bcx, v, Type::i8p()) } else { - let ty = static_ti.unwrap().ty; - let simpl = get_glue_type(ccx, field, ty); - if simpl != ty { - PointerCast(bcx, v, type_of(ccx, simpl).ptr_to()) - } else { - v - } + v }; let llfn = { match static_glue_fn { None => { // 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) } Some(sgf) => sgf @@ -229,15 +204,6 @@ pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef, 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) -> &'a Block<'a> { let _icx = push_ctxt("make_visit_glue"); @@ -462,7 +428,6 @@ pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> @tydesc_info { size: llsize, align: llalign, name: ty_name, - drop_glue: Cell::new(None), visit_glue: Cell::new(None), }; debug!("--- declare_tydesc {}", ppaux::ty_to_str(ccx.tcx, t)); @@ -514,7 +479,7 @@ fn make_generic_glue(ccx: @CrateContext, llfn } -pub fn emit_tydescs(ccx: &CrateContext) { +pub fn emit_tydescs(ccx: @CrateContext) { let _icx = push_ctxt("emit_tydescs"); // As of this point, allow no more tydescs to be created. ccx.finished_tydescs.set(true); @@ -527,21 +492,10 @@ pub fn emit_tydescs(ccx: &CrateContext) { // 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 // calling it. - let drop_glue = - match ti.drop_glue.get() { - None => { - ccx.stats.n_null_glues.set(ccx.stats.n_null_glues.get() + - 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 drop_glue = unsafe { + llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref()) + }; + ccx.stats.n_real_glues.set(ccx.stats.n_real_glues.get() + 1); let visit_glue = match ti.visit_glue.get() { None => { diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index 49f1b073f873..234b8072decc 100644 --- a/src/librustc/middle/trans/intrinsic.rs +++ b/src/librustc/middle/trans/intrinsic.rs @@ -11,7 +11,6 @@ #[allow(non_uppercase_pattern_statics)]; use arena::TypedArena; -use back::abi; use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg}; use lib::llvm::{ValueRef, Pointer, Array, Struct}; use lib; @@ -326,7 +325,7 @@ pub fn trans_intrinsic(ccx: @CrateContext, "get_tydesc" => { let tp_ty = substs.tys[0]; 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, // 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 visitor = get_param(decl, first_real_arg + 1u); let td = PointerCast(bcx, td, ccx.tydesc_type.ptr_to()); - glue::call_tydesc_glue_full(bcx, visitor, td, - abi::tydesc_field_visit_glue, None); + glue::call_visit_glue(bcx, visitor, td, None); RetVoid(bcx); } "morestack_addr" => { diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 5d1c67a27ba2..4a1ba7b22ac5 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -479,11 +479,9 @@ pub fn get_vtable(bcx: &Block, } }); - // Generate a type descriptor for the vtable. - let tydesc = get_tydesc(ccx, self_ty); - glue::lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, tydesc); - - let vtable = make_vtable(ccx, tydesc, methods); + // Generate a destructor for the vtable. + let drop_glue = glue::get_drop_glue(ccx, self_ty); + let vtable = make_vtable(ccx, drop_glue, methods); let mut vtables = ccx.vtables.borrow_mut(); vtables.get().insert(hash_id, vtable); @@ -492,13 +490,13 @@ pub fn get_vtable(bcx: &Block, /// Helper function to declare and initialize the vtable. pub fn make_vtable(ccx: &CrateContext, - tydesc: &tydesc_info, + drop_glue: ValueRef, ptrs: &[ValueRef]) -> ValueRef { unsafe { 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() { components.push(ptr) } diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index b9d23c47fcdc..8c2047a5fc56 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -81,7 +81,7 @@ impl<'a> Reflector<'a> { pub fn c_tydesc(&mut self, t: ty::t) -> ValueRef { let bcx = self.bcx; 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()) } From 0c8ba5fe7fd0d0464e8984a311bd9107815c7b67 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 30 Jan 2014 17:30:29 -0500 Subject: [PATCH 3/4] rm out-of-date comment from std::unstable::raw --- src/libstd/unstable/raw.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libstd/unstable/raw.rs b/src/libstd/unstable/raw.rs index 8f5f8ea806f9..98dde95d3b7c 100644 --- a/src/libstd/unstable/raw.rs +++ b/src/libstd/unstable/raw.rs @@ -71,9 +71,6 @@ impl Repr<*Box> for @T {} impl Repr<*Vec> for ~[T] {} impl Repr<*String> for ~str {} -// sure would be nice to have this -// impl Repr<*Vec> for ~[T] {} - #[cfg(test)] mod tests { use super::*; From 95d897c579621d92a17e9f0bc4edb3ffa24477c7 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 7 Feb 2014 21:22:47 -0500 Subject: [PATCH 4/4] add a hack to fix debug-info tests under gdb 7.7 --- src/test/debug-info/basic-types-metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/debug-info/basic-types-metadata.rs b/src/test/debug-info/basic-types-metadata.rs index 0e48b5db7ce7..a67279254de3 100644 --- a/src/test/debug-info/basic-types-metadata.rs +++ b/src/test/debug-info/basic-types-metadata.rs @@ -45,7 +45,7 @@ // debugger:whatis f64 // check:type = f64 // debugger:info functions _yyy -// check:[...]![...]_yyy()(); +// check:[...]![...]_yyy([...])([...]); // debugger:detach // debugger:quit