From b883d6a54c460f8357b1107b3599108eb1f8580b Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 29 Jun 2013 22:35:04 -0400 Subject: [PATCH 1/7] simplify the exchange allocator * stop using an atomic counter, this has a significant cost and valgrind will already catch these leaks * remove the extra layer of function calls * remove the assert of non-null in free, freeing null is well defined but throwing a failure from free will not be * stop initializing the `prev`/`next` pointers * abort on out-of-memory, failing won't necessarily work --- src/libstd/os.rs | 6 +- src/libstd/rt/global_heap.rs | 94 ++++++++++++--------------- src/libstd/unstable/exchange_alloc.rs | 83 ----------------------- src/libstd/unstable/lang.rs | 17 ----- src/rt/rust_exchange_alloc.cpp | 16 ----- src/rt/rust_exchange_alloc.h | 6 -- src/rt/rust_kernel.cpp | 1 - src/rt/rustrt.def.in | 1 - 8 files changed, 44 insertions(+), 180 deletions(-) delete mode 100644 src/libstd/unstable/exchange_alloc.rs diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 1fbcda12dce14..9b74754d71107 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -730,7 +730,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { #[cfg(windows)] unsafe fn get_list(p: &Path) -> ~[~str] { use libc::consts::os::extra::INVALID_HANDLE_VALUE; - use libc::wcslen; + use libc::{wcslen, free}; use libc::funcs::extra::kernel32::{ FindFirstFileW, FindNextFileW, @@ -739,7 +739,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { use os::win32::{ as_utf16_p }; - use rt::global_heap::{malloc_raw, free_raw}; + use rt::global_heap::malloc_raw; #[nolink] extern { unsafe fn rust_list_dir_wfd_size() -> libc::size_t; @@ -772,7 +772,7 @@ pub fn list_dir(p: &Path) -> ~[~str] { ::cast::transmute(wfd_ptr)); } FindClose(find_handle); - free_raw(wfd_ptr); + free(wfd_ptr) } strings } diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 1e9f9aab8345c..3994b722f5922 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -8,62 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use sys::{size_of}; -use libc::{c_void, size_t, uintptr_t}; -use c_malloc = libc::malloc; -use c_free = libc::free; +use libc::{c_char, c_void, size_t, uintptr_t, free, malloc}; use managed::raw::{BoxHeaderRepr, BoxRepr}; -use cast::transmute; -use unstable::intrinsics::{atomic_xadd,atomic_xsub,TyDesc}; -use ptr::null; +use unstable::intrinsics::TyDesc; +use sys::size_of; -pub unsafe fn malloc(td: *TyDesc, size: uint) -> *c_void { - assert!(td.is_not_null()); - - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert!(p.is_not_null()); - - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); - - let exchange_count = &mut *exchange_count_ptr(); - atomic_xadd(exchange_count, 1); - - return transmute(box); -} -/** -Thin wrapper around libc::malloc, none of the box header -stuff in exchange_alloc::malloc -*/ -pub unsafe fn malloc_raw(size: uint) -> *c_void { - let p = c_malloc(size as size_t); - if p.is_null() { - fail!("Failure in malloc_raw: result ptr is null"); - } - p -} - -pub unsafe fn free(ptr: *c_void) { - let exchange_count = &mut *exchange_count_ptr(); - atomic_xsub(exchange_count, 1); - - assert!(ptr.is_not_null()); - c_free(ptr); -} -///Thin wrapper around libc::free, as with exchange_alloc::malloc_raw -pub unsafe fn free_raw(ptr: *c_void) { - c_free(ptr); +extern { + #[rust_stack] + fn abort(); } fn get_box_size(body_size: uint, body_align: uint) -> uint { let header_size = size_of::(); // FIXME (#2699): This alignment calculation is suspicious. Is it right? let total_size = align_to(header_size, body_align) + body_size; - return total_size; + total_size } // Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power @@ -73,11 +32,40 @@ fn align_to(size: uint, align: uint) -> uint { (size + align - 1) & !(align - 1) } -fn exchange_count_ptr() -> *mut int { - // XXX: Need mutable globals - unsafe { transmute(&rust_exchange_count) } +/// A wrapper around libc::malloc, aborting on out-of-memory +pub unsafe fn malloc_raw(size: uint) -> *c_void { + let p = malloc(size as size_t); + if p.is_null() { + // we need a non-allocating way to print an error here + abort(); + } + p } -extern { - static rust_exchange_count: uintptr_t; +// FIXME #4942: Make these signatures agree with exchange_alloc's signatures +#[lang="exchange_malloc"] +#[inline] +pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + let p = malloc_raw(total_size as uint); + + let box: *mut BoxRepr = p as *mut BoxRepr; + (*box).header.ref_count = -1; // Exchange values not ref counted + (*box).header.type_desc = td; + + box as *c_char +} + +// 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))] +#[lang="exchange_free"] +#[inline] +pub unsafe fn exchange_free(ptr: *c_char) { + free(ptr as *c_void); } diff --git a/src/libstd/unstable/exchange_alloc.rs b/src/libstd/unstable/exchange_alloc.rs deleted file mode 100644 index 5c47901df4802..0000000000000 --- a/src/libstd/unstable/exchange_alloc.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use sys::size_of; -use libc::{c_void, size_t}; -use c_malloc = libc::malloc; -use c_free = libc::free; -use managed::raw::{BoxHeaderRepr, BoxRepr}; -use cast::transmute; -use unstable::intrinsics::{atomic_xadd,atomic_xsub}; -use ptr::null; -#[cfg(stage0)] -use intrinsic::TyDesc; -#[cfg(not(stage0))] -use unstable::intrinsics::TyDesc; - -pub unsafe fn malloc(td: *TyDesc, size: uint) -> *c_void { - assert!(td.is_not_null()); - - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert!(p.is_not_null()); - - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); - - let exchange_count = &mut *rust_get_exchange_count_ptr(); - atomic_xadd(exchange_count, 1); - - return transmute(box); -} -/** -Thin wrapper around libc::malloc, none of the box header -stuff in exchange_alloc::malloc -*/ -pub unsafe fn malloc_raw(size: uint) -> *c_void { - let p = c_malloc(size as size_t); - if p.is_null() { - fail!("Failure in malloc_raw: result ptr is null"); - } - p -} - -pub unsafe fn free(ptr: *c_void) { - let exchange_count = &mut *rust_get_exchange_count_ptr(); - atomic_xsub(exchange_count, 1); - - assert!(ptr.is_not_null()); - c_free(ptr); -} -///Thin wrapper around libc::free, as with exchange_alloc::malloc_raw -pub unsafe fn free_raw(ptr: *c_void) { - c_free(ptr); -} - -fn get_box_size(body_size: uint, body_align: uint) -> uint { - let header_size = size_of::(); - // FIXME (#2699): This alignment calculation is suspicious. Is it right? - let total_size = align_to(header_size, body_align) + body_size; - return total_size; -} - -// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power -// of two. -fn align_to(size: uint, align: uint) -> uint { - assert!(align != 0); - (size + align - 1) & !(align - 1) -} - -extern { - #[rust_stack] - fn rust_get_exchange_count_ptr() -> *mut int; -} diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index d37579b0c47cf..fddd847af341c 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -22,7 +22,6 @@ use rt::task::Task; use rt::local::Local; use option::{Option, Some, None}; use io; -use rt::global_heap; #[allow(non_camel_case_types)] pub type rust_task = c_void; @@ -150,13 +149,6 @@ unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { } } -// FIXME #4942: Make these signatures agree with exchange_alloc's signatures -#[lang="exchange_malloc"] -#[inline] -pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { - transmute(global_heap::malloc(transmute(td), transmute(size))) -} - /// Because this code is so perf. sensitive, use a static constant so that /// debug printouts are compiled out most of the time. static ENABLE_DEBUG: bool = false; @@ -228,15 +220,6 @@ impl DebugPrints for io::fd_t { } } -// 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. -#[lang="exchange_free"] -#[inline] -pub unsafe fn exchange_free(ptr: *c_char) { - global_heap::free(transmute(ptr)) -} - #[lang="malloc"] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { match context() { diff --git a/src/rt/rust_exchange_alloc.cpp b/src/rt/rust_exchange_alloc.cpp index 89257dc9f6e43..658d97031ce0a 100644 --- a/src/rt/rust_exchange_alloc.cpp +++ b/src/rt/rust_exchange_alloc.cpp @@ -15,16 +15,10 @@ #include #include -extern uintptr_t rust_exchange_count; -uintptr_t rust_exchange_count = 0; - void * rust_exchange_alloc::malloc(size_t size) { void *value = ::malloc(size); assert(value); - - sync::increment(rust_exchange_count); - return value; } @@ -37,15 +31,5 @@ rust_exchange_alloc::realloc(void *ptr, size_t size) { void rust_exchange_alloc::free(void *ptr) { - sync::decrement(rust_exchange_count); ::free(ptr); } - -void -rust_check_exchange_count_on_exit() { - if (rust_exchange_count != 0) { - printf("exchange heap not empty on exit\n"); - printf("%d dangling allocations\n", (int)rust_exchange_count); - abort(); - } -} diff --git a/src/rt/rust_exchange_alloc.h b/src/rt/rust_exchange_alloc.h index 767caf0132345..9699ef6b5e9d9 100644 --- a/src/rt/rust_exchange_alloc.h +++ b/src/rt/rust_exchange_alloc.h @@ -21,10 +21,4 @@ class rust_exchange_alloc { void free(void *mem); }; -extern "C" uintptr_t * -rust_get_exchange_count_ptr(); - -void -rust_check_exchange_count_on_exit(); - #endif diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index c1c40222f1a3b..583f836c0d66c 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -211,7 +211,6 @@ rust_kernel::run() { assert(osmain_driver != NULL); osmain_driver->start_main_loop(); sched_reaper.join(); - rust_check_exchange_count_on_exit(); return rval; } diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index a4876618c9715..b572f1aba6a53 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -196,7 +196,6 @@ rust_register_exit_function rust_get_global_data_ptr rust_inc_kernel_live_count rust_dec_kernel_live_count -rust_exchange_count rust_get_rt_tls_key swap_registers rust_readdir From b91416214ed0e24b780dec8608a122b6b3a943f5 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 29 Jun 2013 22:36:27 -0400 Subject: [PATCH 2/7] add a contains_managed intrinsic --- src/librustc/middle/trans/foreign.rs | 6 ++++++ src/librustc/middle/trans/type_use.rs | 2 +- src/librustc/middle/typeck/check/mod.rs | 2 +- src/libstd/unstable/intrinsics.rs | 4 ++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 7672f3b615d03..5dcd6927fa101 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -751,6 +751,12 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)), fcx.llretptr.get()); } + "contains_managed" => { + let tp_ty = substs.tys[0]; + Store(bcx, + C_bool(ty::type_contents(ccx.tcx, tp_ty).contains_managed()), + fcx.llretptr.get()); + } "visit_tydesc" => { let td = get_param(decl, first_real_arg); let visitor = get_param(decl, first_real_arg + 1u); diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index d8d5397646203..5544751529cea 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -127,7 +127,7 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint) "uninit" | "init" | "transmute" | "move_val" | "move_val_init" => use_repr, - "get_tydesc" | "needs_drop" => use_tydesc, + "get_tydesc" | "needs_drop" | "contains_managed" => use_tydesc, "visit_tydesc" | "forget" | "frame_address" | "morestack_addr" => 0, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 0cd9aac379892..8a280374ebf53 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3540,7 +3540,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { ty::mk_nil()) } "needs_drop" => (1u, ~[], ty::mk_bool()), - + "contains_managed" => (1u, ~[], ty::mk_bool()), "atomic_xchg" | "atomic_xadd" | "atomic_xsub" | "atomic_xchg_acq" | "atomic_xadd_acq" | "atomic_xsub_acq" | "atomic_xchg_rel" | "atomic_xadd_rel" | "atomic_xsub_rel" => { diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 1254a59129326..500143fb57773 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -308,6 +308,10 @@ pub extern "rust-intrinsic" { /// Returns `true` if a type requires drop glue. pub fn needs_drop() -> bool; + /// Returns `true` if a type is managed (will be allocated on the local heap) + #[cfg(not(stage0))] + pub fn contains_managed() -> bool; + #[cfg(not(stage0))] pub fn visit_tydesc(td: *TyDesc, tv: @TyVisitor); From 350a5c0b722038a3743058a7a824cfa6ac7094da Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 29 Jun 2013 22:40:40 -0400 Subject: [PATCH 3/7] vec: use contains_managed instead of box header --- src/libstd/vec.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 4196fbac0beb5..009c84a4a6e9f 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -34,7 +34,7 @@ use unstable::intrinsics; #[cfg(stage0)] use intrinsic::{get_tydesc}; #[cfg(not(stage0))] -use unstable::intrinsics::{get_tydesc}; +use unstable::intrinsics::{get_tydesc, contains_managed}; use vec; use util; @@ -1521,6 +1521,7 @@ impl OwnedVector for ~[T] { * * n - The number of elements to reserve space for */ #[inline] + #[cfg(stage0)] fn reserve(&mut self, n: uint) { // Only make the (slow) call into the runtime if we have to use managed; @@ -1538,6 +1539,33 @@ impl OwnedVector for ~[T] { } } + /** + * Reserves capacity for exactly `n` elements in the given vector. + * + * If the capacity for `self` is already equal to or greater than the requested + * capacity, then no action is taken. + * + * # Arguments + * + * * n - The number of elements to reserve space for + */ + #[inline] + #[cfg(not(stage0))] + fn reserve(&mut self, n: uint) { + // Only make the (slow) call into the runtime if we have to + if self.capacity() < n { + unsafe { + let ptr: **raw::VecRepr = cast::transmute(self); + let td = get_tydesc::(); + if contains_managed::() { + rustrt::vec_reserve_shared_actual(td, ptr, n as libc::size_t); + } else { + rustrt::vec_reserve_shared(td, ptr, n as libc::size_t); + } + } + } + } + /** * Reserves capacity for at least `n` elements in the given vector. * From 408eef0d89f4520b5ede7e5868a8ca1bc83795bc Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 29 Jun 2013 23:08:00 -0400 Subject: [PATCH 4/7] stop initializing ref_count in exchange_alloc this is never read anymore --- src/libstd/rt/global_heap.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 3994b722f5922..5d4ac37055caf 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -43,6 +43,27 @@ pub unsafe fn malloc_raw(size: uint) -> *c_void { } // FIXME #4942: Make these signatures agree with exchange_alloc's signatures +#[cfg(stage0, not(test))] +#[lang="exchange_malloc"] +#[inline] +pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + let p = malloc_raw(total_size as uint); + + let box: *mut BoxRepr = p as *mut BoxRepr; + (*box).header.ref_count = -1; + (*box).header.type_desc = td; + + box as *c_char +} + +// FIXME #4942: Make these signatures agree with exchange_alloc's signatures +#[cfg(not(stage0), not(test))] #[lang="exchange_malloc"] #[inline] pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { @@ -55,7 +76,6 @@ pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { let p = malloc_raw(total_size as uint); let box: *mut BoxRepr = p as *mut BoxRepr; - (*box).header.ref_count = -1; // Exchange values not ref counted (*box).header.type_desc = td; box as *c_char From 7f3752c7f95a2439db774d977da0caa299ef48e6 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 30 Jun 2013 00:30:19 -0400 Subject: [PATCH 5/7] managed: rm RC_EXCHANGE_UNIQUE constant this is no longer used, exchange allocations do not set ref_count --- src/libstd/managed.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/managed.rs b/src/libstd/managed.rs index b71b3b503c2ac..2c9fcb2999f06 100644 --- a/src/libstd/managed.rs +++ b/src/libstd/managed.rs @@ -17,7 +17,6 @@ use ptr::to_unsafe_ptr; pub mod raw { use std::unstable::intrinsics::TyDesc; - pub static RC_EXCHANGE_UNIQUE : uint = (-1) as uint; pub static RC_MANAGED_UNIQUE : uint = (-2) as uint; pub static RC_IMMORTAL : uint = 0x77777777; From 45e2582e09dd97d01a01e351c47da210bd6803f3 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 30 Jun 2013 00:49:57 -0400 Subject: [PATCH 6/7] stop copying the tydesc in unique box take glue the only user of the tydesc is ~fn, and it doesn't use this glue code --- src/librustc/middle/trans/closure.rs | 3 +++ src/librustc/middle/trans/uniq.rs | 10 +--------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index ad68ffb402e1d..d99b9b109efd7 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -486,6 +486,9 @@ pub fn make_closure_glue( } } +// note: unique pointers no longer copy the type descriptor in the take glue, +// so we cannot delegate to the unique box take glue here without copying it +// ourselves pub fn make_opaque_cbox_take_glue( bcx: block, sigil: ast::Sigil, diff --git a/src/librustc/middle/trans/uniq.rs b/src/librustc/middle/trans/uniq.rs index d27d6efb2416f..ada85c82b304b 100644 --- a/src/librustc/middle/trans/uniq.rs +++ b/src/librustc/middle/trans/uniq.rs @@ -52,13 +52,5 @@ pub fn duplicate(bcx: block, src_box: ValueRef, src_ty: ty::t) -> Result { } = malloc_unique(bcx, body_datum.ty); body_datum.copy_to(bcx, datum::INIT, dst_body); - // Copy the type descriptor - let src_tydesc_ptr = GEPi(bcx, src_box, - [0u, back::abi::box_field_tydesc]); - let dst_tydesc_ptr = GEPi(bcx, dst_box, - [0u, back::abi::box_field_tydesc]); - let td = Load(bcx, src_tydesc_ptr); - Store(bcx, td, dst_tydesc_ptr); - - return rslt(bcx, dst_box); + rslt(bcx, dst_box) } From 4a29d6eb3f20c2b7a05bb9c9c2f964da606e39ca Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 30 Jun 2013 03:22:18 -0400 Subject: [PATCH 7/7] add a closure_exchange_malloc lang item this makes the exchange allocation header completely unused, and leaves it uninitialized --- src/librustc/middle/lang_items.rs | 136 ++++++++++++++------------- src/librustc/middle/trans/base.rs | 3 + src/librustc/middle/trans/closure.rs | 15 ++- src/librustc/middle/trans/common.rs | 3 +- src/librustc/middle/trans/tvec.rs | 1 + src/libstd/rt/global_heap.rs | 14 +++ 6 files changed, 101 insertions(+), 71 deletions(-) diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index b167a22992cf1..5496fd3079996 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -33,63 +33,64 @@ use syntax::visit::visit_crate; use core::hashmap::HashMap; pub enum LangItem { - FreezeTraitLangItem, // 0 - CopyTraitLangItem, // 1 - SendTraitLangItem, // 2 - SizedTraitLangItem, // 3 - - DropTraitLangItem, // 4 - - AddTraitLangItem, // 5 - SubTraitLangItem, // 6 - MulTraitLangItem, // 7 - DivTraitLangItem, // 8 - RemTraitLangItem, // 9 - NegTraitLangItem, // 10 - NotTraitLangItem, // 11 - BitXorTraitLangItem, // 11 - BitAndTraitLangItem, // 13 - BitOrTraitLangItem, // 14 - ShlTraitLangItem, // 15 - ShrTraitLangItem, // 16 - IndexTraitLangItem, // 17 - - EqTraitLangItem, // 18 - OrdTraitLangItem, // 19 - - StrEqFnLangItem, // 20 - UniqStrEqFnLangItem, // 21 - AnnihilateFnLangItem, // 22 - LogTypeFnLangItem, // 23 - FailFnLangItem, // 24 - FailBoundsCheckFnLangItem, // 25 - ExchangeMallocFnLangItem, // 26 - ExchangeFreeFnLangItem, // 27 - MallocFnLangItem, // 28 - FreeFnLangItem, // 29 - BorrowAsImmFnLangItem, // 30 - BorrowAsMutFnLangItem, // 31 - ReturnToMutFnLangItem, // 32 - CheckNotBorrowedFnLangItem, // 33 - StrDupUniqFnLangItem, // 34 - RecordBorrowFnLangItem, // 35 - UnrecordBorrowFnLangItem, // 36 - - StartFnLangItem, // 37 - - TyDescStructLangItem, // 38 - TyVisitorTraitLangItem, // 39 - OpaqueStructLangItem, // 40 + FreezeTraitLangItem, // 0 + CopyTraitLangItem, // 1 + SendTraitLangItem, // 2 + SizedTraitLangItem, // 3 + + DropTraitLangItem, // 4 + + AddTraitLangItem, // 5 + SubTraitLangItem, // 6 + MulTraitLangItem, // 7 + DivTraitLangItem, // 8 + RemTraitLangItem, // 9 + NegTraitLangItem, // 10 + NotTraitLangItem, // 11 + BitXorTraitLangItem, // 11 + BitAndTraitLangItem, // 13 + BitOrTraitLangItem, // 14 + ShlTraitLangItem, // 15 + ShrTraitLangItem, // 16 + IndexTraitLangItem, // 17 + + EqTraitLangItem, // 18 + OrdTraitLangItem, // 19 + + StrEqFnLangItem, // 20 + UniqStrEqFnLangItem, // 21 + AnnihilateFnLangItem, // 22 + LogTypeFnLangItem, // 23 + FailFnLangItem, // 24 + FailBoundsCheckFnLangItem, // 25 + ExchangeMallocFnLangItem, // 26 + ClosureExchangeMallocFnLangItem, // 27 + ExchangeFreeFnLangItem, // 28 + MallocFnLangItem, // 29 + FreeFnLangItem, // 30 + BorrowAsImmFnLangItem, // 31 + BorrowAsMutFnLangItem, // 32 + ReturnToMutFnLangItem, // 33 + CheckNotBorrowedFnLangItem, // 34 + StrDupUniqFnLangItem, // 35 + RecordBorrowFnLangItem, // 36 + UnrecordBorrowFnLangItem, // 37 + + StartFnLangItem, // 38 + + TyDescStructLangItem, // 39 + TyVisitorTraitLangItem, // 40 + OpaqueStructLangItem, // 41 } pub struct LanguageItems { - items: [Option, ..41] + items: [Option, ..42] } impl LanguageItems { pub fn new() -> LanguageItems { LanguageItems { - items: [ None, ..41 ] + items: [ None, ..42 ] } } @@ -129,22 +130,23 @@ impl LanguageItems { 24 => "fail_", 25 => "fail_bounds_check", 26 => "exchange_malloc", - 27 => "exchange_free", - 28 => "malloc", - 29 => "free", - 30 => "borrow_as_imm", - 31 => "borrow_as_mut", - 32 => "return_to_mut", - 33 => "check_not_borrowed", - 34 => "strdup_uniq", - 35 => "record_borrow", - 36 => "unrecord_borrow", - - 37 => "start", - - 38 => "ty_desc", - 39 => "ty_visitor", - 40 => "opaque", + 27 => "closure_exchange_malloc", + 28 => "exchange_free", + 29 => "malloc", + 30 => "free", + 31 => "borrow_as_imm", + 32 => "borrow_as_mut", + 33 => "return_to_mut", + 34 => "check_not_borrowed", + 35 => "strdup_uniq", + 36 => "record_borrow", + 37 => "unrecord_borrow", + + 38 => "start", + + 39 => "ty_desc", + 40 => "ty_visitor", + 41 => "opaque", _ => "???" } @@ -237,6 +239,9 @@ impl LanguageItems { pub fn exchange_malloc_fn(&self) -> def_id { self.items[ExchangeMallocFnLangItem as uint].get() } + pub fn closure_exchange_malloc_fn(&self) -> def_id { + self.items[ClosureExchangeMallocFnLangItem as uint].get() + } pub fn exchange_free_fn(&self) -> def_id { self.items[ExchangeFreeFnLangItem as uint].get() } @@ -327,6 +332,7 @@ impl<'self> LanguageItemCollector<'self> { item_refs.insert(@"fail_bounds_check", FailBoundsCheckFnLangItem as uint); item_refs.insert(@"exchange_malloc", ExchangeMallocFnLangItem as uint); + item_refs.insert(@"closure_exchange_malloc", ClosureExchangeMallocFnLangItem as uint); item_refs.insert(@"exchange_free", ExchangeFreeFnLangItem as uint); item_refs.insert(@"malloc", MallocFnLangItem as uint); item_refs.insert(@"free", FreeFnLangItem as uint); diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index d9fea12134684..254cb279d2e35 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -254,6 +254,9 @@ pub fn malloc_raw_dyn(bcx: block, heap_exchange => { (ty::mk_imm_uniq, bcx.tcx().lang_items.exchange_malloc_fn()) } + heap_exchange_closure => { + (ty::mk_imm_uniq, bcx.tcx().lang_items.closure_exchange_malloc_fn()) + } }; // Grab the TypeRef type of box_ptr_ty. diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index d99b9b109efd7..8405caa10a823 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -160,6 +160,14 @@ pub fn mk_closure_tys(tcx: ty::ctxt, return cdata_ty; } +fn heap_for_unique_closure(bcx: block, t: ty::t) -> heap { + if ty::type_contents(bcx.tcx(), t).contains_managed() { + heap_managed_unique + } else { + heap_exchange_closure + } +} + pub fn allocate_cbox(bcx: block, sigil: ast::Sigil, cdata_ty: ty::t) -> Result { let _icx = push_ctxt("closure::allocate_cbox"); @@ -182,7 +190,7 @@ pub fn allocate_cbox(bcx: block, sigil: ast::Sigil, cdata_ty: ty::t) malloc_raw(bcx, cdata_ty, heap_managed) } ast::OwnedSigil => { - malloc_raw(bcx, cdata_ty, heap_for_unique(bcx, cdata_ty)) + malloc_raw(bcx, cdata_ty, heap_for_unique_closure(bcx, cdata_ty)) } ast::BorrowedSigil => { let cbox_ty = tuplify_box_ty(tcx, cdata_ty); @@ -486,9 +494,6 @@ pub fn make_closure_glue( } } -// note: unique pointers no longer copy the type descriptor in the take glue, -// so we cannot delegate to the unique box take glue here without copying it -// ourselves pub fn make_opaque_cbox_take_glue( bcx: block, sigil: ast::Sigil, @@ -530,7 +535,7 @@ pub fn make_opaque_cbox_take_glue( let rval = alloca(bcx, Type::i8p()); let bcx = callee::trans_lang_call( bcx, - bcx.tcx().lang_items.exchange_malloc_fn(), + bcx.tcx().lang_items.closure_exchange_malloc_fn(), [opaque_tydesc, sz], expr::SaveIn(rval)); let cbox_out = PointerCast(bcx, Load(bcx, rval), llopaquecboxty); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index b255f2ca78c7f..7638839f95f35 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -276,6 +276,7 @@ pub enum heap { heap_managed, heap_managed_unique, heap_exchange, + heap_exchange_closure } #[deriving(Eq)] @@ -385,7 +386,7 @@ pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { let f: @fn(block) -> block = |a| glue::trans_free(a, ptr); f } - heap_exchange => { + heap_exchange | heap_exchange_closure => { let f: @fn(block) -> block = |a| glue::trans_exchange_free(a, ptr); f } diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 1344bed96eec6..456ae4195a92c 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -321,6 +321,7 @@ pub fn trans_uniq_or_managed_vstore(bcx: block, heap: heap, vstore_expr: @ast::e _ => {} } } + heap_exchange_closure => fail!("vectors are not allocated with closure_exchange_alloc"), heap_managed | heap_managed_unique => {} } diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 5d4ac37055caf..f669dc753d60d 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -72,6 +72,20 @@ pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { assert!(td.is_not_null()); + let total_size = get_box_size(size, (*td).align); + malloc_raw(total_size as uint) as *c_char +} + +// FIXME: #7496 +#[cfg(not(test))] +#[lang="closure_exchange_malloc"] +#[inline] +pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { + let td = td as *TyDesc; + let size = size as uint; + + assert!(td.is_not_null()); + let total_size = get_box_size(size, (*td).align); let p = malloc_raw(total_size as uint);