Skip to content

Add uninit intrinsic and use it in libcore/libstd #6354

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 9, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/libcore/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ 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<T, U>(src: &T) -> U {
let mut dest: U = unstable::intrinsics::uninit();
{
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::<U>() as u64);
}
dest
}

#[cfg(stage0)]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
let mut dest: U = unstable::intrinsics::init();
{
Expand Down
3 changes: 3 additions & 0 deletions src/libcore/unstable/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ pub extern "rust-intrinsic" {

pub fn init<T>() -> T;

#[cfg(not(stage0))]
pub unsafe fn uninit<T>() -> T;

pub fn forget<T>(_: T) -> ();

pub fn needs_drop<T>() -> bool;
Expand Down
95 changes: 90 additions & 5 deletions src/libcore/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,14 +584,29 @@ pub fn consume_reverse<T>(mut v: ~[T], f: &fn(uint, v: T)) {
}

/// Remove the last element from a vector and return it
#[cfg(not(stage0))]
pub fn pop<T>(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::uninit();
val <-> *valptr;
raw::set_len(v, ln - 1u);
val
}
}

#[cfg(stage0)]
pub fn pop<T>(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 {
// FIXME #4204: Should be uninit() - we don't need this zeroed
let mut val = intrinsics::init();
val <-> *valptr;
raw::set_len(v, ln - 1u);
Expand Down Expand Up @@ -660,13 +675,30 @@ pub fn push_all<T:Copy>(v: &mut ~[T], rhs: &const [T]) {
}

#[inline(always)]
#[cfg(not(stage0))]
pub fn push_all_move<T>(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::uninit();
x <-> *ptr::mut_offset(p, i);
push(&mut *v, x);
}
}
raw::set_len(&mut rhs, 0);
}
}

#[inline(always)]
#[cfg(stage0)]
pub fn push_all_move<T>(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| {
// FIXME #4204 Should be uninit() - don't need to zero
let mut x = intrinsics::init();
x <-> *ptr::mut_offset(p, i);
push(&mut *v, x);
Expand All @@ -677,13 +709,29 @@ pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) {
}

/// Shorten a vector, dropping excess elements.
#[cfg(not(stage0))]
pub fn truncate<T>(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::uninit();
dropped <-> *ptr::mut_offset(p, i);
}
}
}
unsafe { raw::set_len(&mut *v, newlen); }
}

/// Shorten a vector, dropping excess elements.
#[cfg(stage0)]
pub fn truncate<T>(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| {
// FIXME #4204 Should be uninit() - don't need to zero
let mut dropped = intrinsics::init();
dropped <-> *ptr::mut_offset(p, i);
}
Expand All @@ -696,6 +744,45 @@ pub fn truncate<T>(v: &mut ~[T], newlen: uint) {
* Remove consecutive repeated elements from a vector; if the vector is
* sorted, this removes all duplicates.
*/
#[cfg(not(stage0))]
pub fn dedup<T:Eq>(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::uninit();
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);
}
}

/**
* Remove consecutive repeated elements from a vector; if the vector is
* sorted, this removes all duplicates.
*/
#[cfg(stage0)]
pub fn dedup<T:Eq>(v: &mut ~[T]) {
unsafe {
if v.len() < 1 { return; }
Expand All @@ -709,8 +796,6 @@ pub fn dedup<T:Eq>(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();
dropped <-> *ptr::mut_offset(p, next_to_read);
} else {
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/trans/foreign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/type_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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" => {
Expand Down
49 changes: 49 additions & 0 deletions src/libstd/priority_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use core::old_iter::BaseIter;
extern "rust-intrinsic" mod rusti {
fn move_val_init<T>(dst: &mut T, src: T);
fn init<T>() -> T;
#[cfg(not(stage0))]
fn uninit<T>() -> T;
}

pub struct PriorityQueue<T> {
Expand Down Expand Up @@ -132,6 +134,27 @@ pub impl <T:Ord> PriorityQueue<T> {
// 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]);

while pos > start {
let parent = (pos - 1) >> 1;
if new > self.data[parent] {
let mut x = rusti::uninit();
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(stage0)]
priv fn siftup(&mut self, start: uint, mut pos: uint) {
unsafe {
let new = *ptr::to_unsafe_ptr(&self.data[pos]);
Expand All @@ -151,6 +174,32 @@ pub impl <T:Ord> PriorityQueue<T> {
}
}


#[cfg(not(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::uninit();
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);
}
}

#[cfg(stage0)]
priv fn siftdown_range(&mut self, mut pos: uint, end: uint) {
unsafe {
let start = pos;
Expand Down
35 changes: 35 additions & 0 deletions src/libstd/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ pub impl<T: Owned> Rc<T> {
}

#[unsafe_destructor]
#[cfg(not(stage0))]
impl<T: Owned> Drop for Rc<T> {
fn finalize(&self) {
unsafe {
(*self.ptr).count -= 1;
if (*self.ptr).count == 0 {
let mut x = intrinsics::uninit();
x <-> *self.ptr;
free(self.ptr as *c_void)
}
}
}
}

#[unsafe_destructor]
#[cfg(stage0)]
impl<T: Owned> Drop for Rc<T> {
fn finalize(&self) {
unsafe {
Expand All @@ -59,6 +75,7 @@ impl<T: Owned> Drop for Rc<T> {
}
}


impl<T: Owned> Clone for Rc<T> {
#[inline]
fn clone(&self) -> Rc<T> {
Expand Down Expand Up @@ -97,6 +114,8 @@ mod test_rc {
#[abi = "rust-intrinsic"]
extern "rust-intrinsic" mod rusti {
fn init<T>() -> T;
#[cfg(not(stage0))]
fn uninit<T>() -> T;
}

#[deriving(Eq)]
Expand Down Expand Up @@ -154,6 +173,22 @@ pub impl<T: Owned> RcMut<T> {
}

#[unsafe_destructor]
#[cfg(not(stage0))]
impl<T: Owned> Drop for RcMut<T> {
fn finalize(&self) {
unsafe {
(*self.ptr).count -= 1;
if (*self.ptr).count == 0 {
let mut x = rusti::uninit();
x <-> *self.ptr;
free(self.ptr as *c_void)
}
}
}
}

#[unsafe_destructor]
#[cfg(stage0)]
impl<T: Owned> Drop for RcMut<T> {
fn finalize(&self) {
unsafe {
Expand Down
19 changes: 19 additions & 0 deletions src/test/run-pass/intrinsic-uninit.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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>() -> T;
}
}
pub fn main() {
let _a : int = unsafe {rusti::uninit()};
}