diff options
Diffstat (limited to 'src')
29 files changed, 398 insertions, 782 deletions
diff --git a/src/libextra/arena.rs b/src/libextra/arena.rs index 47b64d76951..ae4356eb4ba 100644 --- a/src/libextra/arena.rs +++ b/src/libextra/arena.rs @@ -67,17 +67,16 @@ pub struct Arena { priv chunks: @mut MutList<Chunk>, } -#[unsafe_destructor] -impl Drop for Arena { - fn drop(&self) { - unsafe { - destroy_chunk(&self.head); - do self.chunks.each |chunk| { - if !chunk.is_pod { - destroy_chunk(chunk); - } - true - }; +impl Arena { + pub fn new() -> Arena { + Arena::new_with_size(32u) + } + + pub fn new_with_size(initial_size: uint) -> Arena { + Arena { + head: chunk(initial_size, false), + pod_head: chunk(initial_size, true), + chunks: @mut MutNil, } } } @@ -92,18 +91,21 @@ fn chunk(size: uint, is_pod: bool) -> Chunk { } } -pub fn arena_with_size(initial_size: uint) -> Arena { - Arena { - head: chunk(initial_size, false), - pod_head: chunk(initial_size, true), - chunks: @mut MutNil, +#[unsafe_destructor] +impl Drop for Arena { + fn drop(&self) { + unsafe { + destroy_chunk(&self.head); + do self.chunks.each |chunk| { + if !chunk.is_pod { + destroy_chunk(chunk); + } + true + }; + } } } -pub fn Arena() -> Arena { - arena_with_size(32u) -} - #[inline] fn round_up_to(base: uint, align: uint) -> uint { (base + (align - 1)) & !(align - 1) @@ -276,7 +278,7 @@ impl Arena { #[test] fn test_arena_destructors() { - let arena = Arena(); + let arena = Arena::new(); for i in range(0u, 10) { // Arena allocate something with drop glue to make sure it // doesn't leak. @@ -291,7 +293,7 @@ fn test_arena_destructors() { #[should_fail] #[ignore(cfg(windows))] fn test_arena_destructors_fail() { - let arena = Arena(); + let arena = Arena::new(); // Put some stuff in the arena. for i in range(0u, 10) { // Arena allocate something with drop glue to make sure it diff --git a/src/libextra/comm.rs b/src/libextra/comm.rs index 44581efc6f0..776e25cac89 100644 --- a/src/libextra/comm.rs +++ b/src/libextra/comm.rs @@ -18,9 +18,8 @@ Higher level communication abstractions. use std::comm::{GenericChan, GenericSmartChan, GenericPort}; -use std::comm::{Chan, Port, Selectable, Peekable}; +use std::comm::{Chan, Port, Peekable}; use std::comm; -use std::pipes; /// An extension of `pipes::stream` that allows both sending and receiving. pub struct DuplexStream<T, U> { @@ -75,12 +74,6 @@ impl<T:Send,U:Send> Peekable<U> for DuplexStream<T, U> { } } -impl<T:Send,U:Send> Selectable for DuplexStream<T, U> { - fn header(&mut self) -> *mut pipes::PacketHeader { - self.port.header() - } -} - /// Creates a bidirectional stream. pub fn DuplexStream<T:Send,U:Send>() -> (DuplexStream<T, U>, DuplexStream<U, T>) diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index 4142bdadaf6..75487a44f26 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -92,6 +92,11 @@ impl<T> Rawlink<T> { Some(unsafe { cast::transmute(self.p) }) } } + + /// Return the `Rawlink` and replace with `Rawlink::none()` + fn take(&mut self) -> Rawlink<T> { + util::replace(self, Rawlink::none()) + } } impl<T> Clone for Rawlink<T> { @@ -280,13 +285,16 @@ impl<T> DList<T> { /// Add all elements from `other` to the end of the list /// /// O(1) - pub fn append(&mut self, other: DList<T>) { + pub fn append(&mut self, mut other: DList<T>) { match self.list_tail.resolve() { None => *self = other, Some(tail) => { - match other { - DList{list_head: None, _} => return, - DList{list_head: Some(node), list_tail: o_tail, length: o_length} => { + // Carefully empty `other`. + let o_tail = other.list_tail.take(); + let o_length = other.length; + match other.list_head.take() { + None => return, + Some(node) => { tail.next = link_with_prev(node, self.list_tail); self.list_tail = o_tail; self.length += o_length; @@ -404,6 +412,32 @@ impl<T: Ord> DList<T> { } } +#[unsafe_destructor] +impl<T> Drop for DList<T> { + fn drop(&self) { + let mut_self = unsafe { + cast::transmute_mut(self) + }; + // Dissolve the dlist in backwards direction + // Just dropping the list_head can lead to stack exhaustion + // when length is >> 1_000_000 + let mut tail = mut_self.list_tail; + loop { + match tail.resolve() { + None => break, + Some(prev) => { + prev.next.take(); // release ~Node<T> + tail = prev.prev; + } + } + } + mut_self.length = 0; + mut_self.list_head = None; + mut_self.list_tail = Rawlink::none(); + } +} + + impl<'self, A> Iterator<&'self A> for DListIterator<'self, A> { #[inline] fn next(&mut self) -> Option<&'self A> { diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index 1736e62aee9..487ad050e78 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -184,7 +184,68 @@ impl<K: TotalOrd, V> TreeMap<K, V> { /// Get a lazy iterator over the key-value pairs in the map. /// Requires that it be frozen (immutable). pub fn iter<'a>(&'a self) -> TreeMapIterator<'a, K, V> { - TreeMapIterator{stack: ~[], node: &self.root, remaining: self.length} + TreeMapIterator { + stack: ~[], + node: &self.root, + remaining_min: self.length, + remaining_max: self.length + } + } + + /// Get a lazy iterator that should be initialized using + /// `iter_traverse_left`/`iter_traverse_right`/`iter_traverse_complete`. + fn iter_for_traversal<'a>(&'a self) -> TreeMapIterator<'a, K, V> { + TreeMapIterator { + stack: ~[], + node: &self.root, + remaining_min: 0, + remaining_max: self.length + } + } + + /// Return a lazy iterator to the first key-value pair whose key is not less than `k` + /// If all keys in map are less than `k` an empty iterator is returned. + pub fn lower_bound_iter<'a>(&'a self, k: &K) -> TreeMapIterator<'a, K, V> { + let mut iter: TreeMapIterator<'a, K, V> = self.iter_for_traversal(); + loop { + match *iter.node { + Some(ref r) => { + match k.cmp(&r.key) { + Less => iter_traverse_left(&mut iter), + Greater => iter_traverse_right(&mut iter), + Equal => { + iter_traverse_complete(&mut iter); + return iter; + } + } + } + None => { + iter_traverse_complete(&mut iter); + return iter; + } + } + } + } + + /// Return a lazy iterator to the first key-value pair whose key is greater than `k` + /// If all keys in map are not greater than `k` an empty iterator is returned. + pub fn upper_bound_iter<'a>(&'a self, k: &K) -> TreeMapIterator<'a, K, V> { + let mut iter: TreeMapIterator<'a, K, V> = self.iter_for_traversal(); + loop { + match *iter.node { + Some(ref r) => { + match k.cmp(&r.key) { + Less => iter_traverse_left(&mut iter), + Greater => iter_traverse_right(&mut iter), + Equal => iter_traverse_right(&mut iter) + } + } + None => { + iter_traverse_complete(&mut iter); + return iter; + } + } + } } /// Get a lazy iterator that consumes the treemap. @@ -205,7 +266,8 @@ impl<K: TotalOrd, V> TreeMap<K, V> { pub struct TreeMapIterator<'self, K, V> { priv stack: ~[&'self ~TreeNode<K, V>], priv node: &'self Option<~TreeNode<K, V>>, - priv remaining: uint + priv remaining_min: uint, + priv remaining_max: uint } impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> { @@ -222,7 +284,10 @@ impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V None => { let res = self.stack.pop(); self.node = &res.right; - self.remaining -= 1; + self.remaining_max -= 1; + if self.remaining_min > 0 { + self.remaining_min -= 1; + } return Some((&res.key, &res.value)); } } @@ -232,7 +297,46 @@ impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V #[inline] fn size_hint(&self) -> (uint, Option<uint>) { - (self.remaining, Some(self.remaining)) + (self.remaining_min, Some(self.remaining_max)) + } +} + +/// iter_traverse_left, iter_traverse_right and iter_traverse_complete are used to +/// initialize TreeMapIterator pointing to element inside tree structure. +/// +/// They should be used in following manner: +/// - create iterator using TreeMap::iter_for_traversal +/// - find required node using `iter_traverse_left`/`iter_traverse_right` +/// (current node is `TreeMapIterator::node` field) +/// - complete initialization with `iter_traverse_complete` +#[inline] +fn iter_traverse_left<'a, K, V>(it: &mut TreeMapIterator<'a, K, V>) { + let node = it.node.get_ref(); + it.stack.push(node); + it.node = &node.left; +} + +#[inline] +fn iter_traverse_right<'a, K, V>(it: &mut TreeMapIterator<'a, K, V>) { + it.node = &(it.node.get_ref().right); +} + +/// iter_traverse_left, iter_traverse_right and iter_traverse_complete are used to +/// initialize TreeMapIterator pointing to element inside tree structure. +/// +/// Completes traversal. Should be called before using iterator. +/// Iteration will start from `self.node`. +/// If `self.node` is None iteration will start from last node from which we +/// traversed left. +#[inline] +fn iter_traverse_complete<'a, K, V>(it: &mut TreeMapIterator<'a, K, V>) { + static none: Option<~TreeNode<K, V>> = None; + match *it.node { + Some(ref n) => { + it.stack.push(n); + it.node = &none; + } + None => () } } @@ -417,6 +521,20 @@ impl<T: TotalOrd> TreeSet<T> { TreeSetIterator{iter: self.map.iter()} } + /// Get a lazy iterator pointing to the first value not less than `v` (greater or equal). + /// If all elements in the set are less than `v` empty iterator is returned. + #[inline] + pub fn lower_bound_iter<'a>(&'a self, v: &T) -> TreeSetIterator<'a, T> { + TreeSetIterator{iter: self.map.lower_bound_iter(v)} + } + + /// Get a lazy iterator pointing to the first value greater than `v`. + /// If all elements in the set are not greater than `v` empty iterator is returned. + #[inline] + pub fn upper_bound_iter<'a>(&'a self, v: &T) -> TreeSetIterator<'a, T> { + TreeSetIterator{iter: self.map.upper_bound_iter(v)} + } + /// Visit all values in reverse order #[inline] pub fn each_reverse(&self, f: &fn(&T) -> bool) -> bool { @@ -983,6 +1101,31 @@ mod test_treemap { assert_eq!(*v, n * 2); n += 1; } + assert_eq!(n, 5); + } + + #[test] + fn test_interval_iteration() { + let mut m = TreeMap::new(); + for i in range(1, 100) { + assert!(m.insert(i * 2, i * 4)); + } + + for i in range(1, 198) { + let mut lb_it = m.lower_bound_iter(&i); + let (&k, &v) = lb_it.next().unwrap(); + let lb = i + i % 2; + assert_eq!(lb, k); + assert_eq!(lb * 2, v); + + let mut ub_it = m.upper_bound_iter(&i); + let (&k, &v) = ub_it.next().unwrap(); + let ub = i + 2 - i % 2; + assert_eq!(ub, k); + assert_eq!(ub * 2, v); + } + let mut end_it = m.lower_bound_iter(&199); + assert_eq!(end_it.next(), None); } #[test] @@ -1256,7 +1399,6 @@ mod test_set { let mut n = 0; for x in m.iter() { - printfln!(x); assert_eq!(*x, n); n += 1 } diff --git a/src/libextra/unicode.rs b/src/libextra/unicode.rs index 4949ee79e5d..3957551c846 100644 --- a/src/libextra/unicode.rs +++ b/src/libextra/unicode.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[forbid(deprecated_mode)]; #[allow(missing_doc)]; pub mod icu { @@ -159,7 +158,10 @@ pub mod icu { pub static UCHAR_INVALID_CODE : UProperty = -1; pub mod libicu { - #[link_name = "icuuc"] + use unicode::icu::*; + + // #[link_name = "icuuc"] + #[link_args = "-licuuc"] #[abi = "cdecl"] extern { pub fn u_hasBinaryProperty(c: UChar32, which: UProperty) -> UBool; @@ -174,13 +176,17 @@ pub mod icu { } pub fn is_XID_start(c: char) -> bool { - return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START) - == icu::TRUE; + unsafe { + return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START) + == icu::TRUE; + } } pub fn is_XID_continue(c: char) -> bool { - return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START) - == icu::TRUE; + unsafe { + return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START) + == icu::TRUE; + } } /* @@ -189,7 +195,9 @@ Function: is_digit Returns true if a character is a digit. */ pub fn is_digit(c: char) -> bool { - return icu::libicu::u_isdigit(c) == icu::TRUE; + unsafe { + return icu::libicu::u_isdigit(c) == icu::TRUE; + } } /* @@ -198,7 +206,9 @@ Function: is_lower Returns true if a character is a lowercase letter. */ pub fn is_lower(c: char) -> bool { - return icu::libicu::u_islower(c) == icu::TRUE; + unsafe { + return icu::libicu::u_islower(c) == icu::TRUE; + } } /* @@ -207,7 +217,9 @@ Function: is_space Returns true if a character is space. */ pub fn is_space(c: char) -> bool { - return icu::libicu::u_isspace(c) == icu::TRUE; + unsafe { + return icu::libicu::u_isspace(c) == icu::TRUE; + } } /* @@ -216,33 +228,36 @@ Function: is_upper Returns true if a character is an uppercase letter. */ pub fn is_upper(c: char) -> bool { - return icu::libicu::u_isupper(c) == icu::TRUE; + unsafe { + return icu::libicu::u_isupper(c) == icu::TRUE; + } } #[cfg(test)] mod tests { + use unicode::*; #[test] fn test_is_digit() { - assert!((unicode::icu::is_digit('0'))); - assert!((!unicode::icu::is_digit('m'))); + assert!((is_digit('0'))); + assert!((!is_digit('m'))); } #[test] fn test_is_lower() { - assert!((unicode::icu::is_lower('m'))); - assert!((!unicode::icu::is_lower('M'))); + assert!((is_lower('m'))); + assert!((!is_lower('M'))); } #[test] fn test_is_space() { - assert!((unicode::icu::is_space(' '))); - assert!((!unicode::icu::is_space('m'))); + assert!((is_space(' '))); + assert!((!is_space('m'))); } #[test] fn test_is_upper() { - assert!((unicode::icu::is_upper('M'))); - assert!((!unicode::icu::is_upper('m'))); + assert!((is_upper('M'))); + assert!((!is_upper('m'))); } } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 1c983057dba..ea679d19f73 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -335,7 +335,7 @@ pub fn phase_5_run_llvm_passes(sess: Session, outputs: &OutputFilenames) { // NB: Android hack - if sess.targ_cfg.arch == abi::Arm && + if sess.targ_cfg.os == session::os_android && (sess.opts.output_type == link::output_type_object || sess.opts.output_type == link::output_type_exe) { let output_type = link::output_type_assembly; diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index e43f85008d5..d725e2db1eb 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -179,7 +179,8 @@ pub struct crate_metadata { #[deriving(Eq)] pub enum EntryFnType { EntryMain, - EntryStart + EntryStart, + EntryNone, } pub struct Session_ { diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index fb12f97c50c..cbd1d3cd9ad 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -52,7 +52,7 @@ pub fn check_crate(tcx: ty::ctxt, crate: &Crate) { } expr_again(_) => { if !cx.in_loop { - tcx.sess.span_err(e.span, "`again` outside of loop"); + tcx.sess.span_err(e.span, "`loop` outside of loop"); } } expr_ret(oe) => { diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index 1bf5c944fab..34aeaf8a6ce 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -50,6 +50,12 @@ pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map) return; } + // If the user wants no main function at all, then stop here. + if attr::contains_name(crate.attrs, "no_main") { + *session.entry_type = Some(session::EntryNone); + return + } + let ctxt = @mut EntryContext { session: session, ast_map: ast_map, diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index fc39af095b7..0a28da5f88a 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2268,13 +2268,16 @@ pub fn is_entry_fn(sess: &Session, node_id: ast::NodeId) -> bool { // Create a _rust_main(args: ~[str]) function which will be called from the // runtime rust_start function pub fn create_entry_wrapper(ccx: @mut CrateContext, - _sp: span, main_llfn: ValueRef) { + _sp: span, + main_llfn: ValueRef) { let et = ccx.sess.entry_type.unwrap(); - if et == session::EntryMain { - let llfn = create_main(ccx, main_llfn); - create_entry_fn(ccx, llfn, true); - } else { - create_entry_fn(ccx, main_llfn, false); + match et { + session::EntryMain => { + let llfn = create_main(ccx, main_llfn); + create_entry_fn(ccx, llfn, true); + } + session::EntryStart => create_entry_fn(ccx, main_llfn, false), + session::EntryNone => {} // Do nothing. } fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef { diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 6128c169967..e6c27fc8f83 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -408,9 +408,10 @@ fn check_for_entry_fn(ccx: &CrateCtxt) { Some((id, sp)) => match *tcx.sess.entry_type { Some(session::EntryMain) => check_main_fn_ty(ccx, id, sp), Some(session::EntryStart) => check_start_fn_ty(ccx, id, sp), + Some(session::EntryNone) => {} None => tcx.sess.bug("entry function without a type") }, - None => tcx.sess.bug("type checking without entry function") + None => {} } } } diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index a0731dc3494..4356f1143da 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -14,7 +14,6 @@ Message passing #[allow(missing_doc)]; -use cast::transmute; use either::{Either, Left, Right}; use kinds::Send; use option::{Option, Some}; @@ -23,12 +22,6 @@ pub use rt::comm::SendDeferred; use rtcomm = rt::comm; use rt; -use pipes::{wait_many, PacketHeader}; - -// FIXME #5160: Making this public exposes some plumbing from -// pipes. Needs some refactoring -pub use pipes::Selectable; - /// A trait for things that can send multiple messages. pub trait GenericChan<T> { /// Sends a message. @@ -146,15 +139,6 @@ impl<T: Send> Peekable<T> for Port<T> { } } -impl<T: Send> Selectable for Port<T> { - fn header(&mut self) -> *mut PacketHeader { - match self.inner { - Left(ref mut port) => port.header(), - Right(_) => fail!("can't select on newsched ports") - } - } -} - /// A channel that can be shared between many senders. pub struct SharedChan<T> { inner: Either<Exclusive<pipesy::Chan<T>>, rtcomm::SharedChan<T>> @@ -318,8 +302,8 @@ mod pipesy { use kinds::Send; use option::{Option, Some, None}; - use pipes::{recv, try_recv, peek, PacketHeader}; - use super::{GenericChan, GenericSmartChan, GenericPort, Peekable, Selectable}; + use pipes::{recv, try_recv, peek}; + use super::{GenericChan, GenericSmartChan, GenericPort, Peekable}; use cast::transmute_mut; /*proto! oneshot ( @@ -651,80 +635,6 @@ mod pipesy { } } - impl<T: Send> Selectable for Port<T> { - fn header(&mut self) -> *mut PacketHeader { - match self.endp { - Some(ref mut endp) => endp.header(), - None => fail!("peeking empty stream") - } - } -} - -} - -/// Returns the index of an endpoint that is ready to receive. -pub fn selecti<T: Selectable>(endpoints: &mut [T]) -> uint { - wait_many(endpoints) -} - -/// Returns 0 or 1 depending on which endpoint is ready to receive -pub fn select2i<A:Selectable, B:Selectable>(a: &mut A, b: &mut B) - -> Either<(), ()> { - let mut endpoints = [ a.header(), b.header() ]; - match wait_many(endpoints) { - 0 => Left(()), - 1 => Right(()), - _ => fail!("wait returned unexpected index"), - } -} - -/// Receive a message from one of two endpoints. -pub trait Select2<T: Send, U: Send> { - /// Receive a message or return `None` if a connection closes. - fn try_select(&mut self) -> Either<Option<T>, Option<U>>; - /// Receive a message or fail if a connection closes. - fn select(&mut self) -> Either<T, U>; -} - -impl<T:Send, - U:Send, - Left:Selectable + GenericPort<T>, - Right:Selectable + GenericPort<U>> - Select2<T, U> - for (Left, Right) { - fn select(&mut self) -> Either<T, U> { - // XXX: Bad borrow check workaround. - unsafe { - let this: &(Left, Right) = transmute(self); - match *this { - (ref lp, ref rp) => { - let lp: &mut Left = transmute(lp); - let rp: &mut Right = transmute(rp); - match select2i(lp, rp) { - Left(()) => Left(lp.recv()), - Right(()) => Right(rp.recv()), - } - } - } - } - } - - fn try_select(&mut self) -> Either<Option<T>, Option<U>> { - // XXX: Bad borrow check workaround. - unsafe { - let this: &(Left, Right) = transmute(self); - match *this { - (ref lp, ref rp) => { - let lp: &mut Left = transmute(lp); - let rp: &mut Right = transmute(rp); - match select2i(lp, rp) { - Left(()) => Left (lp.try_recv()), - Right(()) => Right(rp.try_recv()), - } - } - } - } - } } #[cfg(test)] @@ -733,22 +643,6 @@ mod test { use super::{Chan, Port, oneshot, stream}; #[test] - fn test_select2() { - let (p1, c1) = stream(); - let (p2, c2) = stream(); - - c1.send(~"abc"); - - let mut tuple = (p1, p2); - match tuple.select() { - Right(_) => fail!(), - _ => (), - } - - c2.send(123); - } - - #[test] fn test_oneshot() { let (p, c) = oneshot(); diff --git a/src/libstd/gc.rs b/src/libstd/gc.rs deleted file mode 100644 index 2e27f82f6f6..00000000000 --- a/src/libstd/gc.rs +++ /dev/null @@ -1,358 +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 <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. - -#[doc(hidden)]; -#[allow(non_uppercase_statics)]; - -/*! Precise garbage collector - -The precise GC exposes two functions, gc and -cleanup_stack_for_failure. The gc function is the entry point to the -garbage collector itself. The cleanup_stack_for_failure is the entry -point for GC-based cleanup. - -Precise GC depends on changes to LLVM's GC which add support for -automatic rooting and addrspace-based metadata marking. Rather than -explicitly rooting pointers with LLVM's gcroot intrinsic, the GC -merely creates allocas for pointers, and allows an LLVM pass to -automatically infer roots based on the allocas present in a function -(and live at a given location). The compiler communicates the type of -the pointer to LLVM by setting the addrspace of the pointer type. The -compiler then emits a map from addrspace to tydesc, which LLVM then -uses to match pointers with their tydesc. The GC reads the metadata -table produced by LLVM, and uses it to determine which glue functions -to call to free objects on their respective heaps. - -GC-based cleanup is a replacement for landing pads which relies on the -GC infrastructure to find pointers on the stack to cleanup. Whereas -the normal GC needs to walk task-local heap allocations, the cleanup -code needs to walk exchange heap allocations and stack-allocations -with destructors. - -*/ - -use cast; -use container::{Set, MutableSet}; -use io; -use libc::{uintptr_t}; -use option::{None, Option, Some}; -use ptr; -use hashmap::HashSet; -use stackwalk::walk_stack; -use sys; -use unstable::intrinsics::{TyDesc}; - -pub use stackwalk::Word; - -// Mirrors rust_stack.h stk_seg -pub struct StackSegment { - prev: *StackSegment, - next: *StackSegment, - end: uintptr_t, - // And other fields which we don't care about... -} - -pub mod rustrt { - use stackwalk::Word; - use super::StackSegment; - - #[link_name = "rustrt"] - extern { - #[rust_stack] - pub fn rust_gc_metadata() -> *Word; - - pub fn rust_get_stack_segment() -> *StackSegment; - pub fn rust_get_c_stack() -> *StackSegment; - } -} - -unsafe fn bump<T, U>(ptr: *T, count: uint) -> *U { - return ptr::offset(ptr, count as int) as *U; -} - -unsafe fn align_to_pointer<T>(ptr: *T) -> *T { - let align = sys::min_align_of::<*T>(); - let ptr = ptr as uint; - let ptr = (ptr + (align - 1)) & -align; - return ptr as *T; -} - -unsafe fn get_safe_point_count() -> uint { - let module_meta = rustrt::rust_gc_metadata(); - return *module_meta; -} - -struct SafePoint { - sp_meta: *Word, - fn_meta: *Word, -} - -// Returns the safe point metadata for the given program counter, if -// any. -unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> { - let module_meta = rustrt::rust_gc_metadata(); - let num_safe_points = *module_meta; - let safe_points: *Word = bump(module_meta, 1); - - if ptr::is_null(pc) { - return None; - } - - // FIXME (#2997): Use binary rather than linear search. - let mut spi = 0; - while spi < num_safe_points { - let sp: **Word = bump(safe_points, spi*3); - let sp_loc = *sp; - if sp_loc == pc { - return Some(SafePoint { - sp_meta: *bump(sp, 1), - fn_meta: *bump(sp, 2), - }); - } - spi += 1; - } - return None; -} - -type Visitor<'self> = &'self fn(root: **Word, tydesc: *TyDesc); - -// Walks the list of roots for the given safe point, and calls visitor -// on each root. -unsafe fn _walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) { - let fp_bytes = fp as *u8; - let sp_meta = sp.sp_meta as *u32; - - let num_stack_roots = *sp_meta as uint; - let num_reg_roots = *ptr::offset(sp_meta, 1) as uint; - - let stack_roots: *u32 = bump(sp_meta, 2); - let reg_roots: *u8 = bump(stack_roots, num_stack_roots); - let addrspaces: *Word = align_to_pointer(bump(reg_roots, num_reg_roots)); - let tydescs: ***TyDesc = bump(addrspaces, num_stack_roots); - - // Stack roots - let mut sri = 0; - while sri < num_stack_roots { - if *ptr::offset(addrspaces, sri as int) >= 1 { - let root = - ptr::offset(fp_bytes, *ptr::offset(stack_roots, sri as int) as int) - as **Word; - let tydescpp = ptr::offset(tydescs, sri as int); - let tydesc = if ptr::is_not_null(tydescpp) && - ptr::is_not_null(*tydescpp) { - **tydescpp - } else { - ptr::null() - }; - visitor(root, tydesc); - } - sri += 1; - } - - // Register roots - let mut rri = 0; - while rri < num_reg_roots { - if *ptr::offset(addrspaces, (num_stack_roots + rri) as int) == 1 { - // FIXME(#2997): Need to find callee saved registers on the stack. - } - rri += 1; - } -} - -unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) { - _walk_safe_point(fp, sp, visitor) -} - -// Is fp contained in segment? -unsafe fn is_frame_in_segment(fp: *Word, segment: *StackSegment) -> bool { - let begin = segment as Word; - let end = (*segment).end as Word; - let frame = fp as Word; - - return begin <= frame && frame <= end; -} - -struct Segment { segment: *StackSegment, boundary: bool } - -// Find and return the segment containing the given frame pointer. At -// stack segment boundaries, returns true for boundary, so that the -// caller can do any special handling to identify where the correct -// return address is in the stack frame. -unsafe fn find_segment_for_frame(fp: *Word, segment: *StackSegment) - -> Segment { - // Check if frame is in either current frame or previous frame. - let in_segment = is_frame_in_segment(fp, segment); - let in_prev_segment = ptr::is_not_null((*segment).prev) && - is_frame_in_segment(fp, (*segment).prev); - - // If frame is not in either segment, walk down segment list until - // we find the segment containing this frame. - if !in_segment && !in_prev_segment { - let mut segment = segment; - while ptr::is_not_null((*segment).next) && - is_frame_in_segment(fp, (*segment).next) { - segment = (*segment).next; - } - return Segment {segment: segment, boundary: false}; - } - - // If frame is in previous frame, then we're at a boundary. - if !in_segment && in_prev_segment { - return Segment {segment: (*segment).prev, boundary: true}; - } - - // Otherwise, we're somewhere on the inside of the frame. - return Segment {segment: segment, boundary: false}; -} - -type Memory = uint; - -static task_local_heap: Memory = 1; -static exchange_heap: Memory = 2; -static stack: Memory = 4; - -static need_cleanup: Memory = exchange_heap | stack; - -// Walks stack, searching for roots of the requested type, and passes -// each root to the visitor. -unsafe fn _walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) { - let mut segment = rustrt::rust_get_stack_segment(); - let mut last_ret: *Word = ptr::null(); - // To avoid collecting memory used by the GC itself, skip stack - // frames until past the root GC stack frame. The root GC stack - // frame is marked by a sentinel, which is a box pointer stored on - // the stack. - let mut reached_sentinel = ptr::is_null(sentinel); - do walk_stack |frame| { - let pc = last_ret; - let Segment {segment: next_segment, boundary: boundary} = - find_segment_for_frame(frame.fp, segment); - segment = next_segment; - // Each stack segment is bounded by a morestack frame. The - // morestack frame includes two return addresses, one for - // morestack itself, at the normal offset from the frame - // pointer, and then a second return address for the - // function prologue (which called morestack after - // determining that it had hit the end of the stack). - // Since morestack itself takes two parameters, the offset - // for this second return address is 3 greater than the - // return address for morestack. - let ret_offset = if boundary { 4 } else { 1 }; - last_ret = *ptr::offset(frame.fp, ret_offset as int) as *Word; - - if !ptr::is_null(pc) { - - let mut delay_reached_sentinel = reached_sentinel; - let sp = is_safe_point(pc); - match sp { - Some(sp_info) => { - do walk_safe_point(frame.fp, sp_info) |root, tydesc| { - // Skip roots until we see the sentinel. - if !reached_sentinel && root == sentinel { - delay_reached_sentinel = true; - } - - // Skip null pointers, which can occur when a - // unique pointer has already been freed. - if reached_sentinel && !ptr::is_null(*root) { - if ptr::is_null(tydesc) { - // Root is a generic box. - let refcount = **root; - if mem | task_local_heap != 0 && refcount != -1 { - visitor(root, tydesc); - } else if mem | exchange_heap != 0 && refcount == -1 { - visitor(root, tydesc); - } - } else { - // Root is a non-immediate. - if mem | stack != 0 { - visitor(root, tydesc); - } - } - } - } - } - None => () - } - reached_sentinel = delay_reached_sentinel; - } - } -} - -unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) { - _walk_gc_roots(mem, sentinel, visitor) -} -pub fn gc() { - unsafe { - // Abort when GC is disabled. - if get_safe_point_count() == 0 { - return; - } - - do walk_gc_roots(task_local_heap, ptr::null()) |_root, _tydesc| { - // FIXME(#2997): Walk roots and mark them. - io::stdout().write([46]); // . - } - } -} - -#[cfg(gc)] -fn expect_sentinel() -> bool { true } - -#[cfg(nogc)] -fn expect_sentinel() -> bool { false } - -// Entry point for GC-based cleanup. Walks stack looking for exchange -// heap and stack allocations requiring drop, and runs all -// destructors. -// -// This should only be called from fail!, as it will drop the roots -// which are *live* on the stack, rather than dropping those that are -// dead. -pub fn cleanup_stack_for_failure() { - unsafe { - // Abort when GC is disabled. - if get_safe_point_count() == 0 { - return; - } - - // Leave a sentinel on the stack to mark the current frame. The - // stack walker will ignore any frames above the sentinel, thus - // avoiding collecting any memory being used by the stack walker - // itself. - // - // However, when core itself is not compiled with GC, then none of - // the functions in core will have GC metadata, which means we - // won't be able to find the sentinel root on the stack. In this - // case, we can safely skip the sentinel since we won't find our - // own stack roots on the stack anyway. - let sentinel_box = ~0; - let sentinel: **Word = if expect_sentinel() { - cast::transmute(&sentinel_box) - } else { - ptr::null() - }; - - let mut roots = HashSet::new(); - do walk_gc_roots(need_cleanup, sentinel) |root, tydesc| { - // Track roots to avoid double frees. - if !roots.contains(&*root) { - roots.insert(*root); - - if ptr::is_null(tydesc) { - // FIXME #4420: Destroy this box - // FIXME #4330: Destroy this box - } else { - ((*tydesc).drop_glue)(*root as *i8); - } - } - } - } -} diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs index c662e5997af..6e11d14aea9 100644 --- a/src/libstd/logging.rs +++ b/src/libstd/logging.rs @@ -85,16 +85,6 @@ pub fn log_type<T>(level: u32, object: &T) { fn newsched_log_str(msg: ~str) { use rt::task::Task; use rt::local::Local; - use str::StrSlice; - use container::Container; - - // Truncate the string - let buf_bytes = 256; - let msg = if msg.len() > buf_bytes { - msg.slice(0, buf_bytes) + "[...]" - } else { - msg - }; unsafe { match Local::try_unsafe_borrow::<Task>() { diff --git a/src/libstd/pipes.rs b/src/libstd/pipes.rs index 1fd534825a5..78f937e058a 100644 --- a/src/libstd/pipes.rs +++ b/src/libstd/pipes.rs @@ -868,47 +868,3 @@ pub mod rt { pub fn make_some<T>(val: T) -> Option<T> { Some(val) } pub fn make_none<T>() -> Option<T> { None } } - -#[cfg(test)] -mod test { - use either::Right; - use comm::{Chan, Port, oneshot, recv_one, stream, Select2, - GenericChan, Peekable}; - - #[test] - fn test_select2() { - let (p1, c1) = stream(); - let (p2, c2) = stream(); - - c1.send(~"abc"); - - let mut tuple = (p1, p2); - match tuple.select() { - Right(_) => fail!(), - _ => (), - } - - c2.send(123); - } - - #[test] - fn test_oneshot() { - let (p, c) = oneshot(); - - c.send(()); - - recv_one(p) - } - - #[test] - fn test_peek_terminated() { - let (port, chan): (Port<int>, Chan<int>) = stream(); - - { - // Destroy the channel - let _chan = chan; - } - - assert!(!port.peek()); - } -} diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs index 7ab63233cff..131507196b1 100644 --- a/src/libstd/rt/local.rs +++ b/src/libstd/rt/local.rs @@ -126,6 +126,7 @@ impl Local for IoFactoryObject { #[cfg(test)] mod test { + use unstable::run_in_bare_thread; use rt::test::*; use super::*; use rt::task::Task; @@ -133,56 +134,64 @@ mod test { #[test] fn thread_local_task_smoke_test() { - local_ptr::init_tls_key(); - let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); - Local::put(task); - let task: ~Task = Local::take(); - cleanup_task(task); + do run_in_bare_thread { + local_ptr::init_tls_key(); + let mut sched = ~new_test_uv_sched(); + let task = ~Task::new_root(&mut sched.stack_pool, || {}); + Local::put(task); + let task: ~Task = Local::take(); + cleanup_task(task); + } } #[test] fn thread_local_task_two_instances() { - local_ptr::init_tls_key(); - let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); - Local::put(task); - let task: ~Task = Local::take(); - cleanup_task(task); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); - Local::put(task); - let task: ~Task = Local::take(); - cleanup_task(task); + do run_in_bare_thread { + local_ptr::init_tls_key(); + let mut sched = ~new_test_uv_sched(); + let task = ~Task::new_root(&mut sched.stack_pool, || {}); + Local::put(task); + let task: ~Task = Local::take(); + cleanup_task(task); + let task = ~Task::new_root(&mut sched.stack_pool, || {}); + Local::put(task); + let task: ~Task = Local::take(); + cleanup_task(task); + } } #[test] fn borrow_smoke_test() { - local_ptr::init_tls_key(); - let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); - Local::put(task); - - unsafe { - let _task: *mut Task = Local::unsafe_borrow(); + do run_in_bare_thread { + local_ptr::init_tls_key(); + let mut sched = ~new_test_uv_sched(); + let task = ~Task::new_root(&mut sched.stack_pool, || {}); + Local::put(task); + + unsafe { + let _task: *mut Task = Local::unsafe_borrow(); + } + let task: ~Task = Local::take(); + cleanup_task(task); } - let task: ~Task = Local::take(); - cleanup_task(task); } #[test] fn borrow_with_return() { - local_ptr::init_tls_key(); - let mut sched = ~new_test_uv_sched(); - let task = ~Task::new_root(&mut sched.stack_pool, || {}); - Local::put(task); - - let res = do Local::borrow::<Task,bool> |_task| { - true - }; - assert!(res) - let task: ~Task = Local::take(); - cleanup_task(task); + do run_in_bare_thread { + local_ptr::init_tls_key(); + let mut sched = ~new_test_uv_sched(); + let task = ~Task::new_root(&mut sched.stack_pool, || {}); + Local::put(task); + + let res = do Local::borrow::<Task,bool> |_task| { + true + }; + assert!(res) + let task: ~Task = Local::take(); + cleanup_task(task); + } } } diff --git a/src/libstd/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs index cd7c5daa444..652e39b05c7 100644 --- a/src/libstd/rt/local_ptr.rs +++ b/src/libstd/rt/local_ptr.rs @@ -52,7 +52,9 @@ pub unsafe fn put<T>(sched: ~T) { pub unsafe fn take<T>() -> ~T { let key = tls_key(); let void_ptr: *mut c_void = tls::get(key); - rtassert!(void_ptr.is_not_null()); + if void_ptr.is_null() { + rtabort!("thread-local pointer is null. bogus!"); + } let ptr: ~T = cast::transmute(void_ptr); tls::set(key, ptr::mut_null()); return ptr; @@ -68,8 +70,8 @@ pub fn exists() -> bool { } } -/// Borrow the thread-local scheduler from thread-local storage. -/// While the scheduler is borrowed it is not available in TLS. +/// Borrow the thread-local value from thread-local storage. +/// While the value is borrowed it is not available in TLS. /// /// # Safety note /// @@ -88,21 +90,23 @@ pub unsafe fn borrow<T>(f: &fn(&mut T)) { } } -/// Borrow a mutable reference to the thread-local Scheduler +/// Borrow a mutable reference to the thread-local value /// /// # Safety Note /// -/// Because this leaves the Scheduler in thread-local storage it is possible +/// Because this leaves the value in thread-local storage it is possible /// For the Scheduler pointer to be aliased pub unsafe fn unsafe_borrow<T>() -> *mut T { let key = tls_key(); - let mut void_sched: *mut c_void = tls::get(key); - rtassert!(void_sched.is_not_null()); + let mut void_ptr: *mut c_void = tls::get(key); + if void_ptr.is_null() { + rtabort!("thread-local pointer is null. bogus!"); + } { - let sched: *mut *mut c_void = &mut void_sched; - let sched: *mut ~T = sched as *mut ~T; - let sched: *mut T = &mut **sched; - return sched; + let ptr: *mut *mut c_void = &mut void_ptr; + let ptr: *mut ~T = ptr as *mut ~T; + let ptr: *mut T = &mut **ptr; + return ptr; } } diff --git a/src/libstd/rt/logging.rs b/src/libstd/rt/logging.rs index 11d11daebc2..9056f0d52e0 100644 --- a/src/libstd/rt/logging.rs +++ b/src/libstd/rt/logging.rs @@ -10,6 +10,7 @@ use either::*; use libc; +use str::StrSlice; pub trait Logger { fn log(&mut self, msg: Either<~str, &'static str>); @@ -35,10 +36,22 @@ impl Logger for StdErrLogger { s } }; - let dbg = ::libc::STDERR_FILENO as ::io::fd_t; - dbg.write_str(s); - dbg.write_str("\n"); - dbg.flush(); + + // Truncate the string + let buf_bytes = 256; + if s.len() > buf_bytes { + let s = s.slice(0, buf_bytes) + "[...]"; + print(s); + } else { + print(s) + }; + + fn print(s: &str) { + let dbg = ::libc::STDERR_FILENO as ::io::fd_t; + dbg.write_str(s); + dbg.write_str("\n"); + dbg.flush(); + } } } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 4cfe0efacfe..33e83fd9040 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -432,13 +432,3 @@ pub fn context() -> RuntimeContext { pub fn rust_try_get_task() -> *rust_task; } } - -#[test] -fn test_context() { - use unstable::run_in_bare_thread; - - assert_eq!(context(), OldTaskContext); - do run_in_bare_thread { - assert_eq!(context(), GlobalContext); - } -} diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 18cfeade157..1a75f2569b5 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -172,6 +172,10 @@ impl Scheduler { rtdebug!("stopping scheduler %u", stask.sched.get_ref().sched_id()); + // Should not have any messages + let message = stask.sched.get_mut_ref().message_queue.pop(); + assert!(message.is_none()); + stask.destroyed = true; } @@ -335,19 +339,24 @@ impl Scheduler { let mut this = self; match this.message_queue.pop() { Some(PinnedTask(task)) => { + this.event_loop.callback(Scheduler::run_sched_once); let mut task = task; task.give_home(Sched(this.make_handle())); this.resume_task_immediately(task); return None; } Some(TaskFromFriend(task)) => { + this.event_loop.callback(Scheduler::run_sched_once); + rtdebug!("got a task from a friend. lovely!"); return this.sched_schedule_task(task); } Some(Wake) => { + this.event_loop.callback(Scheduler::run_sched_once); this.sleepy = false; return Some(this); } Some(Shutdown) => { + this.event_loop.callback(Scheduler::run_sched_once); if this.sleepy { // There may be an outstanding handle on the // sleeper list. Pop them all to make sure that's @@ -395,6 +404,7 @@ impl Scheduler { /// Take a non-homed task we aren't allowed to run here and send /// it to the designated friend scheduler to execute. fn send_to_friend(&mut self, task: ~Task) { + rtdebug!("sending a task to friend"); match self.friend_handle { Some(ref mut handle) => { handle.send(TaskFromFriend(task)); @@ -426,12 +436,14 @@ impl Scheduler { Scheduler::send_task_home(task); return Some(this); } else { + this.event_loop.callback(Scheduler::run_sched_once); task.give_home(Sched(home_handle)); this.resume_task_immediately(task); return None; } } AnySched if this.run_anything => { + this.event_loop.callback(Scheduler::run_sched_once); task.give_home(AnySched); this.resume_task_immediately(task); return None; diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index abafe1cf209..cb949edd7bb 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -228,6 +228,19 @@ impl Task { _ => () } + // FIXME #8302: Dear diary. I'm so tired and confused. + // There's some interaction in rustc between the box + // annihilator and the TLS dtor by which TLS is + // accessed from annihilated box dtors *after* TLS is + // destroyed. Somehow setting TLS back to null, as the + // old runtime did, makes this work, but I don't currently + // understand how. I would expect that, if the annihilator + // reinvokes TLS while TLS is uninitialized, that + // TLS would be reinitialized but never destroyed, + // but somehow this works. I have no idea what's going + // on but this seems to make things magically work. FML. + self.storage = LocalStorage(ptr::null(), None); + // Destroy remaining boxes. Also may run user dtors. unsafe { cleanup::annihilate(); } } @@ -303,7 +316,7 @@ impl Task { impl Drop for Task { fn drop(&self) { rtdebug!("called drop for a task: %u", borrow::to_uint(self)); - assert!(self.destroyed) + rtassert!(self.destroyed) } } @@ -313,7 +326,7 @@ impl Drop for Task { impl Coroutine { pub fn new(stack_pool: &mut StackPool, start: ~fn()) -> Coroutine { - static MIN_STACK_SIZE: uint = 2000000; // XXX: Too much stack + static MIN_STACK_SIZE: uint = 3000000; // XXX: Too much stack let start = Coroutine::build_start_wrapper(start); let mut stack = stack_pool.take_segment(MIN_STACK_SIZE); diff --git a/src/libstd/stackwalk.rs b/src/libstd/stackwalk.rs deleted file mode 100644 index cc516fb559e..00000000000 --- a/src/libstd/stackwalk.rs +++ /dev/null @@ -1,80 +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 <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. - -#[allow(missing_doc)]; - -use cast::transmute; -use unstable::intrinsics; - -pub type Word = uint; - -pub struct Frame { - fp: *Word -} - -pub fn Frame(fp: *Word) -> Frame { - Frame { - fp: fp - } -} - -pub fn walk_stack(visit: &fn(Frame)) { - - debug!("beginning stack walk"); - - do frame_address |frame_pointer| { - let mut frame_address: *Word = unsafe { - transmute(frame_pointer) - }; - loop { - let fr = Frame(frame_address); - - debug!("frame: %x", unsafe { transmute(fr.fp) }); - visit(fr); - - unsafe { - let next_fp: **Word = transmute(frame_address); - frame_address = *next_fp; - if *frame_address == 0u { - debug!("encountered task_start_wrapper. ending walk"); - // This is the task_start_wrapper_frame. There is - // no stack beneath it and it is a foreign frame. - break; - } - } - } - } -} - -#[test] -fn test_simple() { - do walk_stack |_frame| { - } -} - -#[test] -fn test_simple_deep() { - fn run(i: int) { - if i == 0 { return } - - do walk_stack |_frame| { - // Would be nice to test something here... - } - run(i - 1); - } - - run(10); -} - -fn frame_address(f: &fn(x: *u8)) { - unsafe { - intrinsics::frame_address(f) - } -} diff --git a/src/libstd/std.rs b/src/libstd/std.rs index 76d65192e01..568709c89da 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -170,7 +170,6 @@ pub mod local_data; /* Runtime and platform support */ -pub mod gc; pub mod libc; pub mod os; pub mod path; @@ -196,7 +195,6 @@ pub mod unstable; mod unicode; #[path = "num/cmath.rs"] mod cmath; -mod stackwalk; // XXX: This shouldn't be pub, and it should be reexported under 'unstable' // but name resolution doesn't work without it being pub. diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 5c6895fea43..1a913fb4e99 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -902,7 +902,7 @@ pub mod raw { let new_len = s.len() + 1; s.reserve_at_least(new_len); do s.as_mut_buf |buf, len| { - *ptr::mut_offset(buf, len as int) = b; + *ptr::mut_offset(buf, (len-1) as int) = b; } set_len(&mut *s, new_len); } @@ -2826,6 +2826,13 @@ mod tests { } #[test] + fn test_push_byte() { + let mut s = ~"ABC"; + unsafe{raw::push_byte(&mut s, 'D' as u8)}; + assert_eq!(s, ~"ABCD"); + } + + #[test] fn test_shift_byte() { let mut s = ~"ABC"; let b = unsafe{raw::shift_byte(&mut s)}; diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs index 51609709cdb..9d853087123 100644 --- a/src/libstd/sys.rs +++ b/src/libstd/sys.rs @@ -13,7 +13,6 @@ #[allow(missing_doc)]; use cast; -use gc; use io; use libc; use libc::{c_char, size_t}; @@ -147,7 +146,6 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { match context { OldTaskContext => { unsafe { - gc::cleanup_stack_for_failure(); rustrt::rust_upcall_fail(msg, file, line); cast::transmute(()) } @@ -180,8 +178,6 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { msg, file, line as int); } - gc::cleanup_stack_for_failure(); - let task = Local::unsafe_borrow::<Task>(); if (*task).unwinder.unwinding { rtabort!("unwinding again"); diff --git a/src/rt/arch/arm/record_sp.S b/src/rt/arch/arm/record_sp.S index 8d5f24bc5a8..3c5c7644beb 100644 --- a/src/rt/arch/arm/record_sp.S +++ b/src/rt/arch/arm/record_sp.S @@ -14,22 +14,36 @@ .globl get_sp record_sp_limit: + // First, try to read TLS address from coprocessor mrc p15, #0, r3, c13, c0, #3 + cmp r3, #0 + // Otherwise, try to read from magic address 0xFFFF0FF0 + mvneq r3, #0xF000 + ldreq r3, [r3, #-15] + #if __ANDROID__ add r3, r3, #252 #elif __linux__ add r3, r3, #4 #endif + str r0, [r3] mov pc, lr get_sp_limit: + // First, try to read TLS address from coprocessor mrc p15, #0, r3, c13, c0, #3 + cmp r3, #0 + // Otherwise, try to read from magic address 0xFFFF0FF0 + mvneq r3, #0xF000 + ldreq r3, [r3, #-15] + #if __ANDROID__ add r3, r3, #252 #elif __linux__ add r3, r3, #4 #endif + ldr r0, [r3] mov pc, lr diff --git a/src/test/bench/shootout-binarytrees.rs b/src/test/bench/shootout-binarytrees.rs index 596a5b5422a..57bf33fb2fd 100644 --- a/src/test/bench/shootout-binarytrees.rs +++ b/src/test/bench/shootout-binarytrees.rs @@ -9,7 +9,7 @@ // except according to those terms. extern mod extra; -use extra::arena; +use extra::arena::Arena; enum Tree<'self> { Nil, @@ -25,7 +25,7 @@ fn item_check(t: &Tree) -> int { } } -fn bottom_up_tree<'r>(arena: &'r arena::Arena, item: int, depth: int) +fn bottom_up_tree<'r>(arena: &'r Arena, item: int, depth: int) -> &'r Tree<'r> { if depth > 0 { return arena.alloc( @@ -57,7 +57,7 @@ fn main() { max_depth = n; } - let stretch_arena = arena::Arena(); + let stretch_arena = Arena::new(); let stretch_depth = max_depth + 1; let stretch_tree = bottom_up_tree(&stretch_arena, 0, stretch_depth); @@ -65,7 +65,7 @@ fn main() { stretch_depth, item_check(stretch_tree)); - let long_lived_arena = arena::Arena(); + let long_lived_arena = Arena::new(); let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth); let mut depth = min_depth; while depth <= max_depth { diff --git a/src/test/run-pass/issue-3176.rs b/src/test/run-pass/issue-3176.rs deleted file mode 100644 index df242ee3d30..00000000000 --- a/src/test/run-pass/issue-3176.rs +++ /dev/null @@ -1,39 +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 <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. - -// xfail-fast -// xfail-win32 #7999 - -use std::comm::{Select2, Selectable}; -use std::comm; -use std::task; - -pub fn main() { - let (p,c) = comm::stream(); - do task::try || { - let (p2,c2) = comm::stream(); - do task::spawn || { - p2.recv(); - error!("sibling fails"); - fail!(); - } - let (p3,c3) = comm::stream(); - c.send(c3); - c2.send(()); - error!("child blocks"); - let (p, c) = comm::stream(); - let mut tuple = (p, p3); - tuple.select(); - c.send(()); - }; - error!("parent tries"); - assert!(!p.recv().try_send(())); - error!("all done!"); -} diff --git a/src/test/run-pass/placement-new-arena.rs b/src/test/run-pass/placement-new-arena.rs index 9500f83b76b..f2063b583e4 100644 --- a/src/test/run-pass/placement-new-arena.rs +++ b/src/test/run-pass/placement-new-arena.rs @@ -11,10 +11,10 @@ // except according to those terms. extern mod extra; -use extra::arena; +use extra::arena::Arena; pub fn main() { - let mut arena = arena::Arena(); + let mut arena = Arena::new(); let p = &mut arena; let x = p.alloc(|| 4u); printf!("%u", *x); |
