From 050c744c23a8e01407452bc64ca63f92554afee2 Mon Sep 17 00:00:00 2001 From: James Miller Date: Thu, 9 May 2013 22:23:38 +1200 Subject: [PATCH 1/4] Add uninit intrinsic --- src/libcore/unstable/intrinsics.rs | 3 +++ src/librustc/middle/trans/foreign.rs | 3 +++ src/librustc/middle/trans/type_use.rs | 2 +- src/librustc/middle/typeck/check/mod.rs | 1 + src/test/run-pass/intrinsic-uninit.rs | 19 +++++++++++++++++++ 5 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/intrinsic-uninit.rs diff --git a/src/libcore/unstable/intrinsics.rs b/src/libcore/unstable/intrinsics.rs index 363dbb84c1c3e..cfd305f4b70c1 100644 --- a/src/libcore/unstable/intrinsics.rs +++ b/src/libcore/unstable/intrinsics.rs @@ -44,6 +44,9 @@ pub extern "rust-intrinsic" { pub fn init() -> T; + #[cfg(not(stage0))] + pub unsafe fn uninit() -> T; + pub fn forget(_: T) -> (); pub fn needs_drop() -> bool; diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 7eea65e458f1e..26654cf31f861 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -715,6 +715,9 @@ pub fn trans_intrinsic(ccx: @CrateContext, Store(bcx, C_null(lltp_ty), fcx.llretptr.get()); } } + ~"uninit" => { + // Do nothing, this is effectively a no-op + } ~"forget" => {} ~"transmute" => { let (in_type, out_type) = (substs.tys[0], substs.tys[1]); diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index f1c3a42d1583e..cbad7bcb3a6be 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -118,7 +118,7 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint) if abi.is_intrinsic() { let flags = match *cx.ccx.sess.str_of(i.ident) { ~"size_of" | ~"pref_align_of" | ~"min_align_of" | - ~"init" | ~"transmute" | ~"move_val" | + ~"uninit" | ~"init" | ~"transmute" | ~"move_val" | ~"move_val_init" => use_repr, ~"get_tydesc" | ~"needs_drop" => use_tydesc, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 6cd10b5bd6f1b..a6f2f0da234d4 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3447,6 +3447,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { ~"size_of" | ~"pref_align_of" | ~"min_align_of" => (1u, ~[], ty::mk_uint()), ~"init" => (1u, ~[], param(ccx, 0u)), + ~"uninit" => (1u, ~[], param(ccx, 0u)), ~"forget" => (1u, ~[arg(param(ccx, 0u))], ty::mk_nil()), ~"transmute" => (2, ~[ arg(param(ccx, 0)) ], param(ccx, 1)), ~"move_val" | ~"move_val_init" => { diff --git a/src/test/run-pass/intrinsic-uninit.rs b/src/test/run-pass/intrinsic-uninit.rs new file mode 100644 index 0000000000000..a835c9531bf78 --- /dev/null +++ b/src/test/run-pass/intrinsic-uninit.rs @@ -0,0 +1,19 @@ +// 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. + +mod rusti { + #[abi = "rust-intrinsic"] + pub extern "rust-intrinsic" { + fn uninit() -> T; + } +} +pub fn main() { + let _a : int = unsafe {rusti::uninit()}; +} From f5ab112e6b083ab20fdcf9e2fff7dde4a85940b0 Mon Sep 17 00:00:00 2001 From: James Miller Date: Thu, 9 May 2013 22:41:26 +1200 Subject: [PATCH 2/4] Replace init() with uninit() where appropriate --- src/libcore/cast.rs | 2 +- src/libcore/vec.rs | 13 ++++--------- src/libstd/priority_queue.rs | 4 ++-- src/libstd/rc.rs | 4 ++-- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/libcore/cast.rs b/src/libcore/cast.rs index 5e6d2f8b910c6..fe5da8bae693f 100644 --- a/src/libcore/cast.rs +++ b/src/libcore/cast.rs @@ -25,7 +25,7 @@ pub mod rusti { /// Casts the value at `src` to U. The two types must have the same length. pub unsafe fn transmute_copy(src: &T) -> U { - let mut dest: U = unstable::intrinsics::init(); + let mut dest: U = unstable::intrinsics::uninit(); { let dest_ptr: *mut u8 = rusti::transmute(&mut dest); let src_ptr: *u8 = rusti::transmute(src); diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 404e32b2e2ec7..ea780ff9bdd95 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -591,8 +591,7 @@ pub fn pop(v: &mut ~[T]) -> T { } let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]); unsafe { - // FIXME #4204: Should be uninit() - we don't need this zeroed - let mut val = intrinsics::init(); + let mut val = intrinsics::uninit(); val <-> *valptr; raw::set_len(v, ln - 1u); val @@ -666,8 +665,7 @@ pub fn push_all_move(v: &mut ~[T], mut rhs: ~[T]) { unsafe { do as_mut_buf(rhs) |p, len| { for uint::range(0, len) |i| { - // FIXME #4204 Should be uninit() - don't need to zero - let mut x = intrinsics::init(); + let mut x = intrinsics::uninit(); x <-> *ptr::mut_offset(p, i); push(&mut *v, x); } @@ -683,8 +681,7 @@ pub fn truncate(v: &mut ~[T], newlen: uint) { unsafe { // This loop is optimized out for non-drop types. for uint::range(newlen, oldlen) |i| { - // FIXME #4204 Should be uninit() - don't need to zero - let mut dropped = intrinsics::init(); + let mut dropped = intrinsics::uninit(); dropped <-> *ptr::mut_offset(p, i); } } @@ -709,9 +706,7 @@ pub fn dedup(v: &mut ~[T]) { // last_written < next_to_read < ln if *ptr::mut_offset(p, next_to_read) == *ptr::mut_offset(p, last_written) { - // FIXME #4204 Should be uninit() - don't need to - // zero - let mut dropped = intrinsics::init(); + let mut dropped = intrinsics::uninit(); dropped <-> *ptr::mut_offset(p, next_to_read); } else { last_written += 1; diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 9bf7db07ac9dd..2ca13c43d342e 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -139,7 +139,7 @@ pub impl PriorityQueue { while pos > start { let parent = (pos - 1) >> 1; if new > self.data[parent] { - let mut x = rusti::init(); + let mut x = rusti::uninit(); x <-> self.data[parent]; rusti::move_val_init(&mut self.data[pos], x); pos = parent; @@ -162,7 +162,7 @@ pub impl PriorityQueue { if right < end && !(self.data[child] > self.data[right]) { child = right; } - let mut x = rusti::init(); + let mut x = rusti::uninit(); x <-> self.data[child]; rusti::move_val_init(&mut self.data[pos], x); pos = child; diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs index 815f03f426913..3095bdd16d0bf 100644 --- a/src/libstd/rc.rs +++ b/src/libstd/rc.rs @@ -51,7 +51,7 @@ impl Drop for Rc { unsafe { (*self.ptr).count -= 1; if (*self.ptr).count == 0 { - let mut x = intrinsics::init(); + let mut x = intrinsics::uninit(); x <-> *self.ptr; free(self.ptr as *c_void) } @@ -159,7 +159,7 @@ impl Drop for RcMut { unsafe { (*self.ptr).count -= 1; if (*self.ptr).count == 0 { - let mut x = rusti::init(); + let mut x = rusti::uninit(); x <-> *self.ptr; free(self.ptr as *c_void) } From 57509709b4ecc31b04b765bd07cd5fe672667e43 Mon Sep 17 00:00:00 2001 From: James Miller Date: Thu, 9 May 2013 23:05:17 +1200 Subject: [PATCH 3/4] Make staged versions of the functions that use uninit --- src/libcore/cast.rs | 14 ++++++ src/libcore/vec.rs | 90 ++++++++++++++++++++++++++++++++++++ src/libstd/priority_queue.rs | 47 +++++++++++++++++++ src/libstd/rc.rs | 33 +++++++++++++ 4 files changed, 184 insertions(+) diff --git a/src/libcore/cast.rs b/src/libcore/cast.rs index fe5da8bae693f..7451353458e28 100644 --- a/src/libcore/cast.rs +++ b/src/libcore/cast.rs @@ -24,6 +24,7 @@ pub mod rusti { } /// Casts the value at `src` to U. The two types must have the same length. +#[cfg(not(stage0))] pub unsafe fn transmute_copy(src: &T) -> U { let mut dest: U = unstable::intrinsics::uninit(); { @@ -36,6 +37,19 @@ pub unsafe fn transmute_copy(src: &T) -> U { dest } +#[cfg(stage0)] +pub unsafe fn transmute_copy(src: &T) -> U { + let mut dest: U = unstable::intrinsics::init(); + { + let dest_ptr: *mut u8 = rusti::transmute(&mut dest); + let src_ptr: *u8 = rusti::transmute(src); + unstable::intrinsics::memmove64(dest_ptr, + src_ptr, + sys::size_of::() as u64); + } + dest +} + /** * Move a thing into the void * diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index ea780ff9bdd95..137a573fb790d 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -584,6 +584,7 @@ pub fn consume_reverse(mut v: ~[T], f: &fn(uint, v: T)) { } /// Remove the last element from a vector and return it +#[cfg(not(stage0))] pub fn pop(v: &mut ~[T]) -> T { let ln = v.len(); if ln == 0 { @@ -598,6 +599,21 @@ pub fn pop(v: &mut ~[T]) -> T { } } +#[cfg(stage0)] +pub fn pop(v: &mut ~[T]) -> T { + let ln = v.len(); + if ln == 0 { + fail!(~"sorry, cannot vec::pop an empty vector") + } + let valptr = ptr::to_mut_unsafe_ptr(&mut v[ln - 1u]); + unsafe { + let mut val = intrinsics::init(); + val <-> *valptr; + raw::set_len(v, ln - 1u); + val + } +} + /** * Remove an element from anywhere in the vector and return it, replacing it * with the last element. This does not preserve ordering, but is O(1). @@ -659,6 +675,7 @@ pub fn push_all(v: &mut ~[T], rhs: &const [T]) { } #[inline(always)] +#[cfg(not(stage0))] pub fn push_all_move(v: &mut ~[T], mut rhs: ~[T]) { let new_len = v.len() + rhs.len(); reserve(&mut *v, new_len); @@ -674,7 +691,25 @@ pub fn push_all_move(v: &mut ~[T], mut rhs: ~[T]) { } } +#[inline(always)] +#[cfg(stage0)] +pub fn push_all_move(v: &mut ~[T], mut rhs: ~[T]) { + let new_len = v.len() + rhs.len(); + reserve(&mut *v, new_len); + unsafe { + do as_mut_buf(rhs) |p, len| { + for uint::range(0, len) |i| { + let mut x = intrinsics::init(); + x <-> *ptr::mut_offset(p, i); + push(&mut *v, x); + } + } + raw::set_len(&mut rhs, 0); + } +} + /// Shorten a vector, dropping excess elements. +#[cfg(not(stage0))] pub fn truncate(v: &mut ~[T], newlen: uint) { do as_mut_buf(*v) |p, oldlen| { assert!(newlen <= oldlen); @@ -689,10 +724,27 @@ pub fn truncate(v: &mut ~[T], newlen: uint) { unsafe { raw::set_len(&mut *v, newlen); } } +/// Shorten a vector, dropping excess elements. +#[cfg(stage0)] +pub fn truncate(v: &mut ~[T], newlen: uint) { + do as_mut_buf(*v) |p, oldlen| { + assert!(newlen <= oldlen); + unsafe { + // This loop is optimized out for non-drop types. + for uint::range(newlen, oldlen) |i| { + let mut dropped = intrinsics::init(); + dropped <-> *ptr::mut_offset(p, i); + } + } + } + unsafe { raw::set_len(&mut *v, newlen); } +} + /** * Remove consecutive repeated elements from a vector; if the vector is * sorted, this removes all duplicates. */ +#[cfg(not(stage0))] pub fn dedup(v: &mut ~[T]) { unsafe { if v.len() < 1 { return; } @@ -726,6 +778,44 @@ pub fn dedup(v: &mut ~[T]) { } } +/** + * Remove consecutive repeated elements from a vector; if the vector is + * sorted, this removes all duplicates. + */ +#[cfg(stage0)] +pub fn dedup(v: &mut ~[T]) { + unsafe { + if v.len() < 1 { return; } + let mut last_written = 0, next_to_read = 1; + do as_const_buf(*v) |p, ln| { + // We have a mutable reference to v, so we can make arbitrary + // changes. (cf. push and pop) + let p = p as *mut T; + // last_written < next_to_read <= ln + while next_to_read < ln { + // last_written < next_to_read < ln + if *ptr::mut_offset(p, next_to_read) == + *ptr::mut_offset(p, last_written) { + let mut dropped = intrinsics::init(); + dropped <-> *ptr::mut_offset(p, next_to_read); + } else { + last_written += 1; + // last_written <= next_to_read < ln + if next_to_read != last_written { + *ptr::mut_offset(p, last_written) <-> + *ptr::mut_offset(p, next_to_read); + } + } + // last_written <= next_to_read < ln + next_to_read += 1; + // last_written < next_to_read <= ln + } + } + // last_written < next_to_read == ln + raw::set_len(v, last_written + 1); + } +} + // Appending #[inline(always)] diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 2ca13c43d342e..b5dd9e456a107 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -132,6 +132,7 @@ pub impl PriorityQueue { // vector over the junk element. This reduces the constant factor // compared to using swaps, which involves twice as many moves. + #[cfg(not(stage0))] priv fn siftup(&mut self, start: uint, mut pos: uint) { unsafe { let new = *ptr::to_unsafe_ptr(&self.data[pos]); @@ -151,6 +152,28 @@ pub impl PriorityQueue { } } + #[cfg(stage0)] + priv fn siftup(&mut self, start: uint, mut pos: uint) { + unsafe { + let new = *ptr::to_unsafe_ptr(&self.data[pos]); + + while pos > start { + let parent = (pos - 1) >> 1; + if new > self.data[parent] { + let mut x = rusti::init(); + x <-> self.data[parent]; + rusti::move_val_init(&mut self.data[pos], x); + pos = parent; + loop + } + break + } + rusti::move_val_init(&mut self.data[pos], new); + } + } + + + #[cfg(not(stage0))] priv fn siftdown_range(&mut self, mut pos: uint, end: uint) { unsafe { let start = pos; @@ -174,6 +197,30 @@ pub impl PriorityQueue { } } + #[cfg(stage0)] + priv fn siftdown_range(&mut self, mut pos: uint, end: uint) { + unsafe { + let start = pos; + let new = *ptr::to_unsafe_ptr(&self.data[pos]); + + let mut child = 2 * pos + 1; + while child < end { + let right = child + 1; + if right < end && !(self.data[child] > self.data[right]) { + child = right; + } + let mut x = rusti::init(); + x <-> self.data[child]; + rusti::move_val_init(&mut self.data[pos], x); + pos = child; + child = 2 * pos + 1; + } + + rusti::move_val_init(&mut self.data[pos], new); + self.siftup(start, pos); + } + } + priv fn siftdown(&mut self, pos: uint) { let len = self.len(); self.siftdown_range(pos, len); diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs index 3095bdd16d0bf..da90716316b2e 100644 --- a/src/libstd/rc.rs +++ b/src/libstd/rc.rs @@ -46,6 +46,7 @@ pub impl Rc { } #[unsafe_destructor] +#[cfg(not(stage0))] impl Drop for Rc { fn finalize(&self) { unsafe { @@ -59,6 +60,22 @@ impl Drop for Rc { } } +#[unsafe_destructor] +#[cfg(stage0)] +impl Drop for Rc { + fn finalize(&self) { + unsafe { + (*self.ptr).count -= 1; + if (*self.ptr).count == 0 { + let mut x = intrinsics::init(); + x <-> *self.ptr; + free(self.ptr as *c_void) + } + } + } +} + + impl Clone for Rc { #[inline] fn clone(&self) -> Rc { @@ -154,6 +171,7 @@ pub impl RcMut { } #[unsafe_destructor] +#[cfg(not(stage0))] impl Drop for RcMut { fn finalize(&self) { unsafe { @@ -167,6 +185,21 @@ impl Drop for RcMut { } } +#[unsafe_destructor] +#[cfg(stage0)] +impl Drop for RcMut { + fn finalize(&self) { + unsafe { + (*self.ptr).count -= 1; + if (*self.ptr).count == 0 { + let mut x = rusti::init(); + x <-> *self.ptr; + free(self.ptr as *c_void) + } + } + } +} + impl Clone for RcMut { #[inline] fn clone(&self) -> RcMut { From 414970c46f75c730d7fed029deb48b0d1c454391 Mon Sep 17 00:00:00 2001 From: James Miller Date: Thu, 9 May 2013 23:16:07 +1200 Subject: [PATCH 4/4] Add intrinsic declaration where I missed them --- src/libstd/priority_queue.rs | 2 ++ src/libstd/rc.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index b5dd9e456a107..e386b6fbd8231 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -16,6 +16,8 @@ use core::old_iter::BaseIter; extern "rust-intrinsic" mod rusti { fn move_val_init(dst: &mut T, src: T); fn init() -> T; + #[cfg(not(stage0))] + fn uninit() -> T; } pub struct PriorityQueue { diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs index da90716316b2e..9eab1adde4759 100644 --- a/src/libstd/rc.rs +++ b/src/libstd/rc.rs @@ -114,6 +114,8 @@ mod test_rc { #[abi = "rust-intrinsic"] extern "rust-intrinsic" mod rusti { fn init() -> T; + #[cfg(not(stage0))] + fn uninit() -> T; } #[deriving(Eq)]